1 // 2 // Copyright (c) 2008-2017 the Urho3D project. 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a copy 5 // of this software and associated documentation files (the "Software"), to deal 6 // in the Software without restriction, including without limitation the rights 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 // copies of the Software, and to permit persons to whom the Software is 9 // furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 // THE SOFTWARE. 21 // 22 23 #pragma once 24 25 #include "../Container/HashSet.h" 26 #include "../Core/Mutex.h" 27 #include "../Core/Object.h" 28 #include "../Container/List.h" 29 #include "../Input/InputEvents.h" 30 #include "../UI/Cursor.h" 31 32 namespace Urho3D 33 { 34 35 /// %Input Mouse Modes. 36 enum MouseMode 37 { 38 MM_ABSOLUTE = 0, 39 MM_RELATIVE, 40 MM_WRAP, 41 MM_FREE, 42 MM_INVALID 43 }; 44 45 class Deserializer; 46 class Graphics; 47 class Serializer; 48 class UIElement; 49 class XMLFile; 50 51 const IntVector2 MOUSE_POSITION_OFFSCREEN = IntVector2(M_MIN_INT, M_MIN_INT); 52 53 /// %Input state for a finger touch. 54 struct TouchState 55 { 56 /// Return last touched UI element, used by scripting integration. 57 UIElement* GetTouchedElement(); 58 59 /// Touch (finger) ID. 60 int touchID_; 61 /// Position in screen coordinates. 62 IntVector2 position_; 63 /// Last position in screen coordinates. 64 IntVector2 lastPosition_; 65 /// Movement since last frame. 66 IntVector2 delta_; 67 /// Finger pressure. 68 float pressure_; 69 /// Last touched UI element from screen joystick. 70 WeakPtr<UIElement> touchedElement_; 71 }; 72 73 /// %Input state for a joystick. 74 struct JoystickState 75 { 76 /// Construct with defaults. JoystickStateJoystickState77 JoystickState() : 78 joystick_(0), controller_(0), screenJoystick_(0) 79 { 80 } 81 82 /// Initialize the number of buttons, axes and hats and set them to neutral state. 83 void Initialize(unsigned numButtons, unsigned numAxes, unsigned numHats); 84 /// Reset button, axis and hat states to neutral. 85 void Reset(); 86 87 /// Return whether is a game controller. Game controllers will use standardized axis and button mappings. IsControllerJoystickState88 bool IsController() const { return controller_ != 0; } 89 90 /// Return number of buttons. GetNumButtonsJoystickState91 unsigned GetNumButtons() const { return buttons_.Size(); } 92 93 /// Return number of axes. GetNumAxesJoystickState94 unsigned GetNumAxes() const { return axes_.Size(); } 95 96 /// Return number of hats. GetNumHatsJoystickState97 unsigned GetNumHats() const { return hats_.Size(); } 98 99 /// Check if a button is held down. GetButtonDownJoystickState100 bool GetButtonDown(unsigned index) const { return index < buttons_.Size() ? buttons_[index] : false; } 101 102 /// Check if a button has been pressed on this frame. GetButtonPressJoystickState103 bool GetButtonPress(unsigned index) const { return index < buttonPress_.Size() ? buttonPress_[index] : false; } 104 105 /// Return axis position. GetAxisPositionJoystickState106 float GetAxisPosition(unsigned index) const { return index < axes_.Size() ? axes_[index] : 0.0f; } 107 108 /// Return hat position. GetHatPositionJoystickState109 int GetHatPosition(unsigned index) const { return index < hats_.Size() ? hats_[index] : HAT_CENTER; } 110 111 /// SDL joystick. 112 SDL_Joystick* joystick_; 113 /// SDL joystick instance ID. 114 SDL_JoystickID joystickID_; 115 /// SDL game controller. 116 SDL_GameController* controller_; 117 /// UI element containing the screen joystick. 118 UIElement* screenJoystick_; 119 /// Joystick name. 120 String name_; 121 /// Button up/down state. 122 PODVector<bool> buttons_; 123 /// Button pressed on this frame. 124 PODVector<bool> buttonPress_; 125 /// Axis position from -1 to 1. 126 PODVector<float> axes_; 127 /// POV hat bits. 128 PODVector<int> hats_; 129 }; 130 131 #ifdef __EMSCRIPTEN__ 132 class EmscriptenInput; 133 #endif 134 135 /// %Input subsystem. Converts operating system window messages to input state and events. 136 class URHO3D_API Input : public Object 137 { 138 URHO3D_OBJECT(Input, Object); 139 140 #ifdef __EMSCRIPTEN__ 141 friend class EmscriptenInput; 142 #endif 143 144 public: 145 /// Construct. 146 Input(Context* context); 147 /// Destruct. 148 virtual ~Input(); 149 150 /// Poll for window messages. Called by HandleBeginFrame(). 151 void Update(); 152 /// Set whether ALT-ENTER fullscreen toggle is enabled. 153 void SetToggleFullscreen(bool enable); 154 /// Set whether the operating system mouse cursor is visible. When not visible (default), is kept centered to prevent leaving the window. Mouse visibility event can be suppressed-- this also recalls any unsuppressed SetMouseVisible which can be returned by ResetMouseVisible(). 155 void SetMouseVisible(bool enable, bool suppressEvent = false); 156 /// Reset last mouse visibility that was not suppressed in SetMouseVisible. 157 void ResetMouseVisible(); 158 /// Set whether the mouse is currently being grabbed by an operation. 159 void SetMouseGrabbed(bool grab, bool suppressEvent = false); 160 /// Reset the mouse grabbed to the last unsuppressed SetMouseGrabbed call 161 void ResetMouseGrabbed(); 162 /// Set the mouse mode. 163 /** Set the mouse mode behaviour. 164 * MM_ABSOLUTE is the default behaviour, allowing the toggling of operating system cursor visibility and allowing the cursor to escape the window when visible. 165 * When the operating system cursor is invisible in absolute mouse mode, the mouse is confined to the window. 166 * If the operating system and UI cursors are both invisible, interaction with the Urho UI will be limited (eg: drag move / drag end events will not trigger). 167 * SetMouseMode(MM_ABSOLUTE) will call SetMouseGrabbed(false). 168 * 169 * MM_RELATIVE sets the operating system cursor to invisible and confines the cursor to the window. 170 * The operating system cursor cannot be set to be visible in this mode via SetMouseVisible(), however changes are tracked and will be restored when another mouse mode is set. 171 * When the virtual cursor is also invisible, UI interaction will still function as normal (eg: drag events will trigger). 172 * SetMouseMode(MM_RELATIVE) will call SetMouseGrabbed(true). 173 * 174 * MM_WRAP grabs the mouse from the operating system and confines the operating system cursor to the window, wrapping the cursor when it is near the edges. 175 * SetMouseMode(MM_WRAP) will call SetMouseGrabbed(true). 176 * 177 * MM_FREE does not grab/confine the mouse cursor even when it is hidden. This can be used for cases where the cursor should render using the operating system 178 * outside the window, and perform custom rendering (with SetMouseVisible(false)) inside. 179 */ 180 void SetMouseMode(MouseMode mode, bool suppressEvent = false); 181 /// Reset the last mouse mode that wasn't suppressed in SetMouseMode 182 void ResetMouseMode(); 183 /// Add screen joystick. 184 /** Return the joystick instance ID when successful or negative on error. 185 * If layout file is not given, use the default screen joystick layout. 186 * If style file is not given, use the default style file from root UI element. 187 * 188 * This method should only be called in main thread. 189 */ 190 SDL_JoystickID AddScreenJoystick(XMLFile* layoutFile = 0, XMLFile* styleFile = 0); 191 /// Remove screen joystick by instance ID. 192 /** Return true if successful. 193 * 194 * This method should only be called in main thread. 195 */ 196 bool RemoveScreenJoystick(SDL_JoystickID id); 197 /// Set whether the virtual joystick is visible. 198 void SetScreenJoystickVisible(SDL_JoystickID id, bool enable); 199 /// Show or hide on-screen keyboard on platforms that support it. When shown, keypresses from it are delivered as key events. 200 void SetScreenKeyboardVisible(bool enable); 201 /// Set touch emulation by mouse. Only available on desktop platforms. When enabled, actual mouse events are no longer sent and the mouse cursor is forced visible. 202 void SetTouchEmulation(bool enable); 203 /// Begin recording a touch gesture. Return true if successful. The E_GESTURERECORDED event (which contains the ID for the new gesture) will be sent when recording finishes. 204 bool RecordGesture(); 205 /// Save all in-memory touch gestures. Return true if successful. 206 bool SaveGestures(Serializer& dest); 207 /// Save a specific in-memory touch gesture to a file. Return true if successful. 208 bool SaveGesture(Serializer& dest, unsigned gestureID); 209 /// Load touch gestures from a file. Return number of loaded gestures, or 0 on failure. 210 unsigned LoadGestures(Deserializer& source); 211 /// Remove an in-memory gesture by ID. Return true if was found. 212 bool RemoveGesture(unsigned gestureID); 213 /// Remove all in-memory gestures. 214 void RemoveAllGestures(); 215 /// Set the mouse cursor position. Uses the backbuffer (Graphics width/height) coordinates. 216 void SetMousePosition(const IntVector2& position); 217 /// Center the mouse position. 218 void CenterMousePosition(); 219 220 /// Return keycode from key name. 221 int GetKeyFromName(const String& name) const; 222 /// Return keycode from scancode. 223 int GetKeyFromScancode(int scancode) const; 224 /// Return name of key from keycode. 225 String GetKeyName(int key) const; 226 /// Return scancode from keycode. 227 int GetScancodeFromKey(int key) const; 228 /// Return scancode from key name. 229 int GetScancodeFromName(const String& name) const; 230 /// Return name of key from scancode. 231 String GetScancodeName(int scancode) const; 232 /// Check if a key is held down. 233 bool GetKeyDown(int key) const; 234 /// Check if a key has been pressed on this frame. 235 bool GetKeyPress(int key) const; 236 /// Check if a key is held down by scancode. 237 bool GetScancodeDown(int scancode) const; 238 /// Check if a key has been pressed on this frame by scancode. 239 bool GetScancodePress(int scancode) const; 240 /// Check if a mouse button is held down. 241 bool GetMouseButtonDown(int button) const; 242 /// Check if a mouse button has been pressed on this frame. 243 bool GetMouseButtonPress(int button) const; 244 /// Check if a qualifier key is held down. 245 bool GetQualifierDown(int qualifier) const; 246 /// Check if a qualifier key has been pressed on this frame. 247 bool GetQualifierPress(int qualifier) const; 248 /// Return the currently held down qualifiers. 249 int GetQualifiers() const; 250 /// Return mouse position within window. Should only be used with a visible mouse cursor. Uses the backbuffer (Graphics width/height) coordinates. 251 IntVector2 GetMousePosition() const; 252 /// Return mouse movement since last frame. 253 IntVector2 GetMouseMove() const; 254 /// Return horizontal mouse movement since last frame. 255 int GetMouseMoveX() const; 256 /// Return vertical mouse movement since last frame. 257 int GetMouseMoveY() const; 258 /// Return mouse wheel movement since last frame. GetMouseMoveWheel()259 int GetMouseMoveWheel() const { return mouseMoveWheel_; } 260 /// Return input coordinate scaling. Should return non-unity on High DPI display. GetInputScale()261 Vector2 GetInputScale() const { return inputScale_; } 262 263 /// Return number of active finger touches. GetNumTouches()264 unsigned GetNumTouches() const { return touches_.Size(); } 265 /// Return active finger touch by index. 266 TouchState* GetTouch(unsigned index) const; 267 268 /// Return number of connected joysticks. GetNumJoysticks()269 unsigned GetNumJoysticks() const { return joysticks_.Size(); } 270 /// Return joystick state by ID, or null if does not exist. 271 JoystickState* GetJoystick(SDL_JoystickID id); 272 /// Return joystick state by index, or null if does not exist. 0 = first connected joystick. 273 JoystickState* GetJoystickByIndex(unsigned index); 274 /// Return joystick state by name, or null if does not exist. 275 JoystickState* GetJoystickByName(const String& name); 276 277 /// Return whether fullscreen toggle is enabled. GetToggleFullscreen()278 bool GetToggleFullscreen() const { return toggleFullscreen_; } 279 280 /// Return whether a virtual joystick is visible. 281 bool IsScreenJoystickVisible(SDL_JoystickID id) const; 282 /// Return whether on-screen keyboard is supported. 283 bool GetScreenKeyboardSupport() const; 284 /// Return whether on-screen keyboard is being shown. 285 bool IsScreenKeyboardVisible() const; 286 287 /// Return whether touch emulation is enabled. GetTouchEmulation()288 bool GetTouchEmulation() const { return touchEmulation_; } 289 290 /// Return whether the operating system mouse cursor is visible. IsMouseVisible()291 bool IsMouseVisible() const { return mouseVisible_; } 292 /// Return whether the mouse is currently being grabbed by an operation. IsMouseGrabbed()293 bool IsMouseGrabbed() const { return mouseGrabbed_; } 294 /// Return whether the mouse is locked to the window 295 bool IsMouseLocked() const; 296 297 /// Return the mouse mode. GetMouseMode()298 MouseMode GetMouseMode() const { return mouseMode_; } 299 300 /// Return whether application window has input focus. HasFocus()301 bool HasFocus() { return inputFocus_; } 302 303 /// Return whether application window is minimized. 304 bool IsMinimized() const; 305 306 private: 307 /// Initialize when screen mode initially set. 308 void Initialize(); 309 /// Open a joystick and return its ID. Return -1 if no joystick. 310 SDL_JoystickID OpenJoystick(unsigned index); 311 /// Setup internal joystick structures. 312 void ResetJoysticks(); 313 /// Prepare input state for application gaining input focus. 314 void GainFocus(); 315 /// Prepare input state for application losing input focus. 316 void LoseFocus(); 317 /// Clear input state. 318 void ResetState(); 319 /// Clear touch states and send touch end events. 320 void ResetTouches(); 321 /// Reset input accumulation. 322 void ResetInputAccumulation(); 323 /// Get the index of a touch based on the touch ID. 324 unsigned GetTouchIndexFromID(int touchID); 325 /// Used internally to return and remove the next available touch index. 326 unsigned PopTouchIndex(); 327 /// Push a touch index back into the list of available when finished with it. 328 void PushTouchIndex(int touchID); 329 /// Send an input focus or window minimization change event. 330 void SendInputFocusEvent(); 331 /// Handle a mouse button change. 332 void SetMouseButton(int button, bool newState); 333 /// Handle a key change. 334 void SetKey(int key, int scancode, bool newState); 335 /// Handle mouse wheel change. 336 void SetMouseWheel(int delta); 337 /// Suppress next mouse movement. 338 void SuppressNextMouseMove(); 339 /// Unsuppress mouse movement. 340 void UnsuppressMouseMove(); 341 /// Handle screen mode event. 342 void HandleScreenMode(StringHash eventType, VariantMap& eventData); 343 /// Handle frame start event. 344 void HandleBeginFrame(StringHash eventType, VariantMap& eventData); 345 /// Handle touch events from the controls of screen joystick(s). 346 void HandleScreenJoystickTouch(StringHash eventType, VariantMap& eventData); 347 /// Handle SDL event. 348 void HandleSDLEvent(void* sdlEvent); 349 350 #ifndef __EMSCRIPTEN__ 351 /// Set SDL mouse mode relative. 352 void SetMouseModeRelative(SDL_bool enable); 353 /// Set SDL mouse mode absolute. 354 void SetMouseModeAbsolute(SDL_bool enable); 355 #else 356 /// Set whether the operating system mouse cursor is visible (Emscripten platform only). 357 void SetMouseVisibleEmscripten(bool enable, bool suppressEvent = false); 358 /// Set mouse mode final resolution (Emscripten platform only). 359 void SetMouseModeEmscriptenFinal(MouseMode mode, bool suppressEvent = false); 360 /// SetMouseMode (Emscripten platform only). 361 void SetMouseModeEmscripten(MouseMode mode, bool suppressEvent); 362 /// Handle frame end event. 363 void HandleEndFrame(StringHash eventType, VariantMap& eventData); 364 #endif 365 366 /// Graphics subsystem. 367 WeakPtr<Graphics> graphics_; 368 /// Key down state. 369 HashSet<int> keyDown_; 370 /// Key pressed state. 371 HashSet<int> keyPress_; 372 /// Key down state by scancode. 373 HashSet<int> scancodeDown_; 374 /// Key pressed state by scancode. 375 HashSet<int> scancodePress_; 376 /// Active finger touches. 377 HashMap<int, TouchState> touches_; 378 /// List that maps between event touch IDs and normalised touch IDs 379 List<int> availableTouchIDs_; 380 /// Mapping of touch indices 381 HashMap<int, int> touchIDMap_; 382 /// String for text input. 383 String textInput_; 384 /// Opened joysticks. 385 HashMap<SDL_JoystickID, JoystickState> joysticks_; 386 /// Mouse buttons' down state. 387 unsigned mouseButtonDown_; 388 /// Mouse buttons' pressed state. 389 unsigned mouseButtonPress_; 390 /// Last mouse position for calculating movement. 391 IntVector2 lastMousePosition_; 392 /// Last mouse position before being set to not visible. 393 IntVector2 lastVisibleMousePosition_; 394 /// Mouse movement since last frame. 395 IntVector2 mouseMove_; 396 /// Mouse wheel movement since last frame. 397 int mouseMoveWheel_; 398 /// Input coordinate scaling. Non-unity when window and backbuffer have different sizes (e.g. Retina display.) 399 Vector2 inputScale_; 400 /// SDL window ID. 401 unsigned windowID_; 402 /// Fullscreen toggle flag. 403 bool toggleFullscreen_; 404 /// Operating system mouse cursor visible flag. 405 bool mouseVisible_; 406 /// The last operating system mouse cursor visible flag set by end use call to SetMouseVisible. 407 bool lastMouseVisible_; 408 /// Flag to indicate the mouse is being grabbed by an operation. Subsystems like UI that uses mouse should temporarily ignore the mouse hover or click events. 409 bool mouseGrabbed_; 410 /// The last mouse grabbed set by SetMouseGrabbed. 411 bool lastMouseGrabbed_; 412 /// Determines the mode of mouse behaviour. 413 MouseMode mouseMode_; 414 /// The last mouse mode set by SetMouseMode. 415 MouseMode lastMouseMode_; 416 #ifndef __EMSCRIPTEN__ 417 /// Flag to determine whether SDL mouse relative was used. 418 bool sdlMouseRelative_; 419 #endif 420 /// Touch emulation mode flag. 421 bool touchEmulation_; 422 /// Input focus flag. 423 bool inputFocus_; 424 /// Minimized flag. 425 bool minimized_; 426 /// Gained focus on this frame flag. 427 bool focusedThisFrame_; 428 /// Next mouse move suppress flag. 429 bool suppressNextMouseMove_; 430 /// Whether mouse move is accumulated in backbuffer scale or not (when using events directly). 431 bool mouseMoveScaled_; 432 /// Initialized flag. 433 bool initialized_; 434 435 #ifdef __EMSCRIPTEN__ 436 /// Emscripten Input glue instance. 437 UniquePtr<EmscriptenInput> emscriptenInput_; 438 /// Flag used to detect mouse jump when exiting pointer-lock. 439 bool emscriptenExitingPointerLock_; 440 /// Flag used to detect mouse jump on initial mouse click when entering pointer-lock. 441 bool emscriptenEnteredPointerLock_; 442 /// Flag indicating current pointer-lock status. 443 bool emscriptenPointerLock_; 444 #endif 445 }; 446 447 } 448