windowInputGenerator.cpp
Engine/source/windowManager/windowInputGenerator.cpp
Public Functions
Detailed Description
Public Functions
convertModifierBits(const U32 in)
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "windowManager/windowInputGenerator.h" 25#include "windowManager/platformWindow.h" 26#include "sim/actionMap.h" 27#include "platform/input/IProcessInput.h" 28 29 30extern InputModifiers convertModifierBits(const U32 in); 31 32 33//----------------------------------------------------------------------------- 34// Constructor/Destructor 35//----------------------------------------------------------------------------- 36WindowInputGenerator::WindowInputGenerator( PlatformWindow *window ) : 37 mWindow(window), 38 mInputController(NULL), 39 mLastCursorPos(0,0), 40 mClampToWindow(true), 41 mFocused(false), 42 mPixelsPerMickey(1.0f), 43 mLastPressWasGlobalActionMap(false) 44{ 45 AssertFatal(mWindow, "NULL PlatformWindow on WindowInputGenerator creation"); 46 47 if (mWindow->getOffscreenRender()) 48 mFocused = true; 49 50 mWindow->appEvent.notify(this, &WindowInputGenerator::handleAppEvent); 51 mWindow->mouseEvent.notify(this, &WindowInputGenerator::handleMouseMove); 52 mWindow->wheelEvent.notify(this, &WindowInputGenerator::handleMouseWheel); 53 mWindow->buttonEvent.notify(this, &WindowInputGenerator::handleMouseButton); 54 mWindow->keyEvent.notify(this, &WindowInputGenerator::handleKeyboard); 55 mWindow->charEvent.notify(this, &WindowInputGenerator::handleCharInput); 56 57 // We also want to subscribe to input events. 58 Input::smInputEvent.notify(this, &WindowInputGenerator::handleInputEvent); 59} 60 61WindowInputGenerator::~WindowInputGenerator() 62{ 63 if( mWindow ) 64 { 65 mWindow->mouseEvent.remove(this, &WindowInputGenerator::handleMouseMove); 66 mWindow->buttonEvent.remove(this, &WindowInputGenerator::handleMouseButton); 67 mWindow->wheelEvent.remove(this, &WindowInputGenerator::handleMouseWheel); 68 mWindow->keyEvent.remove(this, &WindowInputGenerator::handleKeyboard); 69 mWindow->charEvent.remove(this, &WindowInputGenerator::handleCharInput); 70 mWindow->appEvent.remove(this, &WindowInputGenerator::handleAppEvent); 71 } 72 73 Input::smInputEvent.remove(this, &WindowInputGenerator::handleInputEvent); 74} 75 76//----------------------------------------------------------------------------- 77// Process an input event and pass it on. 78// Respect the action map. 79//----------------------------------------------------------------------------- 80void WindowInputGenerator::generateInputEvent( InputEventInfo &inputEvent ) 81{ 82 // Reset last press being global 83 mLastPressWasGlobalActionMap = false; 84 85 if (!mInputController)// || !mFocused) 86 return; 87 88 if (inputEvent.action == SI_MAKE && inputEvent.deviceType == KeyboardDeviceType) 89 { 90 for (int i = 0; i < mAcceleratorMap.size(); ++i) 91 { 92 const AccKeyMap &acc = mAcceleratorMap[i]; 93 if (!mWindow->getKeyboardTranslation() && 94 ((acc.modifier == inputEvent.modifier && acc.modifier != 0) || (acc.modifier == 0 && inputEvent.modifier == 0)) 95 && acc.keyCode == inputEvent.objInst) 96 { 97 Con::evaluatef(acc.cmd); 98 return; 99 } 100 } 101 } 102 103 // Give the ActionMap first shot. 104 if (ActionMap::handleEventGlobal(&inputEvent)) 105 { 106 mLastPressWasGlobalActionMap = true; 107 return; 108 } 109 110 if (mInputController->processInputEvent(inputEvent)) 111 return; 112 113 if (mWindow->getKeyboardTranslation()) 114 return; 115 116 // If we get here we failed to process it with anything prior... so let 117 // the ActionMap handle it. 118 ActionMap::handleEvent(&inputEvent); 119 120} 121 122//----------------------------------------------------------------------------- 123// Mouse Events 124//----------------------------------------------------------------------------- 125void WindowInputGenerator::handleMouseMove( WindowId did, U32 modifier, S32 x, S32 y, bool isRelative ) 126{ 127 if( !mInputController || !mFocused ) 128 return; 129 130 // jddTODO : Clean this up 131 // CodeReview currently the Torque GuiCanvas deals with mouse input 132 // as relative movement, even when the cursor is visible. Because 133 // of this there is an asinine bit of code in there that manages 134 // updating the cursor position on the class based on relative movement. 135 // Because of this we always have to generate and send off for processing 136 // relative events, even if the mouse is not locked. 137 // I'm considering removing this in the Canvas refactor, thoughts? [7/6/2007 justind] 138 // Now sends the absolute position event whenever an absolute position is received from the OS. [2/13/2019 mar] 139 140 // Generate a base Movement along and Axis event 141 InputEventInfo event; 142 event.deviceType = MouseDeviceType; 143 event.deviceInst = 0; 144 event.objType = SI_AXIS; 145#ifdef TORQUE_SDL 146 event.modifier = modifier; 147#else 148 event.modifier = convertModifierBits(modifier); 149#endif 150 event.ascii = 0; 151 152 // Generate delta movement along each axis 153 Point2F cursDelta; 154 if(isRelative) 155 { 156 cursDelta.x = F32(x) * mPixelsPerMickey; 157 cursDelta.y = F32(y) * mPixelsPerMickey; 158 } 159 else 160 { 161 cursDelta.x = F32(x - mLastCursorPos.x); 162 cursDelta.y = F32(y - mLastCursorPos.y); 163 } 164 165 // If X axis changed, generate a relative event 166 if(mFabs(cursDelta.x) > 0.1) 167 { 168 event.objInst = SI_XAXIS; 169 event.action = SI_MOVE; 170 event.fValue = cursDelta.x; 171 generateInputEvent(event); 172 } 173 174 // If Y axis changed, generate a relative event 175 if(mFabs(cursDelta.y) > 0.1) 176 { 177 event.objInst = SI_YAXIS; 178 event.action = SI_MOVE; 179 event.fValue = cursDelta.y; 180 generateInputEvent(event); 181 } 182 183 // CodeReview : If we're not relative, pass along a positional update 184 // so that the canvas can update it's internal cursor tracking 185 // point. [7/6/2007 justind] 186 if( !isRelative ) 187 { 188 if( mClampToWindow ) 189 { 190 Point2I winExtent = mWindow->getClientExtent(); 191 x = mClampF(x, 0.0f, F32(winExtent.x - 1)); 192 y = mClampF(y, 0.0f, F32(winExtent.y - 1)); 193 194 } 195 196 // We use SI_MAKE to signify that the position is being set, not relatively moved. 197 event.action = SI_MAKE; 198 199 // X Axis 200 event.objInst = SI_XAXIS; 201 event.fValue = (F32)x; 202 generateInputEvent(event); 203 204 // Y Axis 205 event.objInst = SI_YAXIS; 206 event.fValue = (F32)y; 207 generateInputEvent(event); 208 209 mLastCursorPos = Point2I(x,y); 210 } 211 else 212 mLastCursorPos += Point2I(x,y); 213} 214 215void WindowInputGenerator::handleMouseButton( WindowId did, U32 modifiers, U32 action, U16 button ) 216{ 217 if( !mInputController || !mFocused ) 218 return; 219 220 InputEventInfo event; 221 event.deviceType = MouseDeviceType; 222 event.deviceInst = 0; 223 event.objType = SI_BUTTON; 224 event.objInst = (InputObjectInstances)(KEY_BUTTON0 + button); 225#ifdef TORQUE_SDL 226 event.modifier = modifiers; 227#else 228 event.modifier = convertModifierBits(modifiers); 229#endif 230 event.ascii = 0; 231 event.action = (action==<a href="/coding/file/journaledsignal_8h/#journaledsignal_8h_1a9c56096a2c51a4a98f907f8f87fd1671a1ff2cf77afe457ec438f62a1f1bd19e6">IA_MAKE</a>) ? SI_MAKE : SI_BREAK; 232 event.fValue = (action==<a href="/coding/file/journaledsignal_8h/#journaledsignal_8h_1a9c56096a2c51a4a98f907f8f87fd1671a1ff2cf77afe457ec438f62a1f1bd19e6">IA_MAKE</a>) ? 1.0 : 0.0; 233 234 generateInputEvent(event); 235} 236 237void WindowInputGenerator::handleMouseWheel( WindowId did, U32 modifiers, S32 wheelDeltaX, S32 wheelDeltaY ) 238{ 239 if( !mInputController || !mFocused ) 240 return; 241 242 InputEventInfo event; 243 event.deviceType = MouseDeviceType; 244 event.deviceInst = 0; 245 event.objType = SI_AXIS; 246#ifdef TORQUE_SDL 247 event.modifier = modifiers; 248#else 249 event.modifier = convertModifierBits(modifiers); 250#endif 251 event.ascii = 0; 252 event.action = SI_MOVE; 253 254 if( wheelDeltaY ) // Vertical 255 { 256 event.objInst = SI_ZAXIS; 257 event.fValue = (F32)wheelDeltaY; 258 259 generateInputEvent(event); 260 } 261 if( wheelDeltaX ) // Horizontal 262 { 263 event.objInst = SI_RZAXIS; 264 event.fValue = (F32)wheelDeltaX; 265 266 generateInputEvent(event); 267 } 268} 269 270//----------------------------------------------------------------------------- 271// Key/Character Input 272//----------------------------------------------------------------------------- 273void WindowInputGenerator::handleCharInput( WindowId did, U32 modifier, U16 key ) 274{ 275 if( !mInputController || !mFocused ) 276 return; 277 278 InputEventInfo event; 279 event.deviceType = KeyboardDeviceType; 280 event.deviceInst = 0; 281 event.objType = SI_KEY; 282 event.objInst = KEY_NULL; 283#ifdef TORQUE_SDL 284 event.modifier = modifier; 285#else 286 event.modifier = convertModifierBits(modifier); 287#endif 288 event.ascii = key; 289 event.action = SI_MAKE; 290 event.fValue = 1.0; 291 generateInputEvent(event); 292 293 event.action = SI_BREAK; 294 event.fValue = 0.f; 295 generateInputEvent(event); 296} 297 298 299void WindowInputGenerator::handleKeyboard( WindowId did, U32 modifier, U32 action, U16 key ) 300{ 301 if( !mInputController || !mFocused ) 302 return; 303 304 InputEventInfo event; 305 event.deviceType = KeyboardDeviceType; 306 event.deviceInst = 0; 307 event.objType = SI_KEY; 308 event.objInst = (InputObjectInstances)key; 309#ifdef TORQUE_SDL 310 event.modifier = modifier; 311#else 312 event.modifier = convertModifierBits(modifier); 313#endif 314 event.ascii = 0; 315 316 switch(action) 317 { 318 case IA_MAKE: 319 event.action = SI_MAKE; 320 event.fValue = 1.f; 321 break; 322 323 case IA_REPEAT: 324 event.action = SI_REPEAT; 325 event.fValue = 1.f; 326 break; 327 328 case IA_BREAK: 329 event.action = SI_BREAK; 330 event.fValue = 0.f; 331 break; 332 333 // If we encounter an unknown don't submit the event. 334 default: 335 //Con::warnf("GuiCanvas::handleKeyboard - got an unknown action type %d!", action); 336 return; 337 } 338 339 generateInputEvent(event); 340} 341 342//----------------------------------------------------------------------------- 343// Raw input 344//----------------------------------------------------------------------------- 345void WindowInputGenerator::handleInputEvent( U32 deviceInst, F32 fValue, F32 fValue2, F32 fValue3, F32 fValue4, S32 iValue, U16 deviceType, U16 objType, U16 ascii, U16 objInst, U8 action, U8 modifier ) 346{ 347 // Skip it if we don't have focus. 348 if(!mInputController)// || !mFocused) 349 return; 350 351 // Convert to an InputEventInfo and pass it around for processing. 352 InputEventInfo event; 353 event.deviceInst = deviceInst; 354 event.fValue = fValue; 355 event.fValue2 = fValue2; 356 event.fValue3 = fValue3; 357 event.fValue4 = fValue4; 358 event.iValue = iValue; 359 event.deviceType = (InputDeviceTypes)deviceType; 360 event.objType = (InputEventType)objType; 361 event.ascii = ascii; 362 event.objInst = (InputObjectInstances)objInst; 363 event.action = (InputActionType)action; 364 event.modifier = (InputModifiers)modifier; 365 366 generateInputEvent(event); 367} 368 369//----------------------------------------------------------------------------- 370// Window Events 371//----------------------------------------------------------------------------- 372void WindowInputGenerator::handleAppEvent( WindowId did, S32 event ) 373{ 374 if(event == LoseFocus) 375 { 376 // Fire all breaks; this will prevent issues with dangling keys. 377 ActionMap::clearAllBreaks(); 378 mFocused = false; 379 } 380 else if(event == GainFocus) 381 { 382 mFocused = true; 383 } 384 385 // always focused with offscreen rendering 386 if (mWindow->getOffscreenRender()) 387 mFocused = true; 388} 389 390//----------------------------------------------------------------------------- 391// Character Input Mapping 392//----------------------------------------------------------------------------- 393 394bool WindowInputGenerator::wantAsKeyboardEvent( U32 modifiers, U32 keyCode ) 395{ 396 // Disallow translation on keys that are bound in the global action map. 397 398 return ActionMap::getGlobalMap()->isAction( 399 KeyboardDeviceType, 400 0, 401 modifiers, 402 keyCode 403 ); 404} 405