| 1 | //************************************ bs::framework - Copyright 2018 Marko Pintera **************************************// | 
|---|
| 2 | //*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********// | 
|---|
| 3 | #pragma once | 
|---|
| 4 |  | 
|---|
| 5 | #include "BsCorePrerequisites.h" | 
|---|
| 6 | #include "Utility/BsModule.h" | 
|---|
| 7 | #include "Platform/BsPlatform.h" | 
|---|
| 8 | #include "Input/BsInputFwd.h" | 
|---|
| 9 |  | 
|---|
| 10 | namespace bs | 
|---|
| 11 | { | 
|---|
| 12 | class Mouse; | 
|---|
| 13 | class Keyboard; | 
|---|
| 14 | class Gamepad; | 
|---|
| 15 | struct InputPrivateData; | 
|---|
| 16 |  | 
|---|
| 17 | /** @addtogroup Input | 
|---|
| 18 | *  @{ | 
|---|
| 19 | */ | 
|---|
| 20 |  | 
|---|
| 21 | /** | 
|---|
| 22 | * Primary module used for dealing with input. Allows you to receieve and query raw or OS input for | 
|---|
| 23 | * mouse/keyboard/gamepad. | 
|---|
| 24 | */ | 
|---|
| 25 | class BS_CORE_EXPORT Input : public Module<Input> | 
|---|
| 26 | { | 
|---|
| 27 | /** Possible button states. */ | 
|---|
| 28 | enum class ButtonState | 
|---|
| 29 | { | 
|---|
| 30 | Off, /**< Button is not being pressed. */ | 
|---|
| 31 | On, /**< Button is being pressed. */ | 
|---|
| 32 | ToggledOn, /**< Button has been pressed this frame. */ | 
|---|
| 33 | ToggledOff, /**< Button has been released this frame. */ | 
|---|
| 34 | ToggledOnOff, /**< Button has been pressed and released this frame. */ | 
|---|
| 35 | }; | 
|---|
| 36 |  | 
|---|
| 37 | /** Contains axis and device data per device. */ | 
|---|
| 38 | struct DeviceData | 
|---|
| 39 | { | 
|---|
| 40 | DeviceData(); | 
|---|
| 41 |  | 
|---|
| 42 | Vector<float> axes; | 
|---|
| 43 | ButtonState keyStates[BC_Count]; | 
|---|
| 44 | }; | 
|---|
| 45 |  | 
|---|
| 46 | /**	Different types of possible input event callbacks. */ | 
|---|
| 47 | enum class EventType | 
|---|
| 48 | { | 
|---|
| 49 | ButtonUp, ButtonDown, PointerMoved, PointerUp, PointerDown, PointerDoubleClick, TextInput, Command | 
|---|
| 50 | }; | 
|---|
| 51 |  | 
|---|
| 52 | /**	Stores information about a queued input event that is to be triggered later. */ | 
|---|
| 53 | struct QueuedEvent | 
|---|
| 54 | { | 
|---|
| 55 | QueuedEvent(EventType type, UINT32 idx) | 
|---|
| 56 | :type(type), idx(idx) | 
|---|
| 57 | { } | 
|---|
| 58 |  | 
|---|
| 59 | EventType type; | 
|---|
| 60 | UINT32 idx; | 
|---|
| 61 | }; | 
|---|
| 62 |  | 
|---|
| 63 | public: | 
|---|
| 64 | Input(); | 
|---|
| 65 | ~Input(); | 
|---|
| 66 |  | 
|---|
| 67 | /** | 
|---|
| 68 | * Returns value of the specified input axis. Normally in range [-1.0, 1.0] but can be outside the range for | 
|---|
| 69 | * devices with unbound axes (for example mouse). | 
|---|
| 70 | * | 
|---|
| 71 | * @param[in]	type		Type of axis to query. Usually a type from InputAxis but can be a custom value. | 
|---|
| 72 | * @param[in]	deviceIdx	Index of the device in case more than one is hooked up (0 - primary). | 
|---|
| 73 | */ | 
|---|
| 74 | float getAxisValue(UINT32 type, UINT32 deviceIdx = 0) const; | 
|---|
| 75 |  | 
|---|
| 76 | /** | 
|---|
| 77 | * Query if the provided button is currently being held (this frame or previous frames). | 
|---|
| 78 | * | 
|---|
| 79 | * @param[in]	keyCode		Code of the button to query. | 
|---|
| 80 | * @param[in]	deviceIdx	Device to query the button on (0 - primary). | 
|---|
| 81 | */ | 
|---|
| 82 | bool isButtonHeld(ButtonCode keyCode, UINT32 deviceIdx = 0) const; | 
|---|
| 83 |  | 
|---|
| 84 | /** | 
|---|
| 85 | * Query if the provided button is currently being released (only true for one frame). | 
|---|
| 86 | * | 
|---|
| 87 | * @param[in]	keyCode		Code of the button to query. | 
|---|
| 88 | * @param[in]	deviceIdx	Device to query the button on (0 - primary). | 
|---|
| 89 | */ | 
|---|
| 90 | bool isButtonUp(ButtonCode keyCode, UINT32 deviceIdx = 0) const; | 
|---|
| 91 |  | 
|---|
| 92 | /** | 
|---|
| 93 | * Query if the provided button is currently being pressed (only true for one frame). | 
|---|
| 94 | * | 
|---|
| 95 | * @param[in]	keyCode		Code of the button to query. | 
|---|
| 96 | * @param[in]	deviceIdx	Device to query the button on (0 - primary). | 
|---|
| 97 | */ | 
|---|
| 98 | bool isButtonDown(ButtonCode keyCode, UINT32 deviceIdx = 0) const; | 
|---|
| 99 |  | 
|---|
| 100 | /** Returns position of the pointer (for example mouse cursor) relative to the screen. */ | 
|---|
| 101 | Vector2I getPointerPosition() const; | 
|---|
| 102 |  | 
|---|
| 103 | /** Returns difference between pointer position between current and last frame. */ | 
|---|
| 104 | Vector2I getPointerDelta() const { return mPointerDelta; } | 
|---|
| 105 |  | 
|---|
| 106 | /** | 
|---|
| 107 | * Query if the provided pointer button is currently being held (this frame or previous frames). | 
|---|
| 108 | * | 
|---|
| 109 | * @param[in]	pointerButton		Code of the button to query. | 
|---|
| 110 | */ | 
|---|
| 111 | bool isPointerButtonHeld(PointerEventButton pointerButton) const; | 
|---|
| 112 |  | 
|---|
| 113 | /** | 
|---|
| 114 | * Query if the provided pointer button is currently being released (only true for one frame). | 
|---|
| 115 | * | 
|---|
| 116 | * @param[in]	pointerButton		Code of the button to query. | 
|---|
| 117 | */ | 
|---|
| 118 | bool isPointerButtonUp(PointerEventButton pointerButton) const; | 
|---|
| 119 |  | 
|---|
| 120 | /** | 
|---|
| 121 | * Query if the provided pointer button is currently being pressed (only true for one frame). | 
|---|
| 122 | * | 
|---|
| 123 | * @param[in]	pointerButton		Code of the button to query. | 
|---|
| 124 | */ | 
|---|
| 125 | bool isPointerButtonDown(PointerEventButton pointerButton) const; | 
|---|
| 126 |  | 
|---|
| 127 | /** Query has the left pointer button has been double-clicked this frame. */ | 
|---|
| 128 | bool isPointerDoubleClicked() const; | 
|---|
| 129 |  | 
|---|
| 130 | /** Enables or disables mouse smoothing. Smoothing makes the changes to mouse axes more gradual. */ | 
|---|
| 131 | void setMouseSmoothing(bool enabled); | 
|---|
| 132 |  | 
|---|
| 133 | /** Returns the number of detected devices of the specified type. */ | 
|---|
| 134 | UINT32 getDeviceCount(InputDevice device) const; | 
|---|
| 135 |  | 
|---|
| 136 | /** Returns the name of a specific input device. Returns empty string if the device doesn't exist. */ | 
|---|
| 137 | String getDeviceName(InputDevice type, UINT32 idx); | 
|---|
| 138 |  | 
|---|
| 139 | /** Triggered whenever a button is first pressed. */ | 
|---|
| 140 | Event<void(const ButtonEvent&)> onButtonDown; | 
|---|
| 141 |  | 
|---|
| 142 | /**	Triggered whenever a button is first released. */ | 
|---|
| 143 | Event<void(const ButtonEvent&)> onButtonUp; | 
|---|
| 144 |  | 
|---|
| 145 | /**	Triggered whenever user inputs a text character. */ | 
|---|
| 146 | Event<void(const TextInputEvent&)> onCharInput; | 
|---|
| 147 |  | 
|---|
| 148 | /**	Triggers when some pointing device (mouse cursor, touch) moves. */ | 
|---|
| 149 | Event<void(const PointerEvent&)> onPointerMoved; | 
|---|
| 150 |  | 
|---|
| 151 | /**	Triggers when some pointing device (mouse cursor, touch) button is pressed. */ | 
|---|
| 152 | Event<void(const PointerEvent&)> onPointerPressed; | 
|---|
| 153 |  | 
|---|
| 154 | /**	Triggers when some pointing device (mouse cursor, touch) button is released. */ | 
|---|
| 155 | Event<void(const PointerEvent&)> onPointerReleased; | 
|---|
| 156 |  | 
|---|
| 157 | /**	Triggers when some pointing device (mouse cursor, touch) button is double clicked. */ | 
|---|
| 158 | Event<void(const PointerEvent&)> onPointerDoubleClick; | 
|---|
| 159 |  | 
|---|
| 160 | // TODO Low priority: Remove this, I can emulate it using virtual input | 
|---|
| 161 | /**	Triggers on special input commands. */ | 
|---|
| 162 | Event<void(InputCommandType)> onInputCommand; | 
|---|
| 163 |  | 
|---|
| 164 | public: // ***** INTERNAL ****** | 
|---|
| 165 | /** @name Internal | 
|---|
| 166 | *  @{ | 
|---|
| 167 | */ | 
|---|
| 168 |  | 
|---|
| 169 | /** | 
|---|
| 170 | * Called every frame. Detects button state changes and prepares callback events to trigger via a call to | 
|---|
| 171 | * _triggerCallbacks(). | 
|---|
| 172 | */ | 
|---|
| 173 | void _update(); | 
|---|
| 174 |  | 
|---|
| 175 | /** Triggers any queued input event callbacks. */ | 
|---|
| 176 | void _triggerCallbacks(); | 
|---|
| 177 |  | 
|---|
| 178 | /** Returns internal, platform specific privata data. */ | 
|---|
| 179 | InputPrivateData* _getPrivateData() const { return mPlatformData; } | 
|---|
| 180 |  | 
|---|
| 181 | /** Returns a handle to the window that is currently receiving input. */ | 
|---|
| 182 | UINT64 _getWindowHandle() const { return mWindowHandle; } | 
|---|
| 183 |  | 
|---|
| 184 | /** Called by Mouse when mouse movement is detected. */ | 
|---|
| 185 | void _notifyMouseMoved(INT32 relX, INT32 relY, INT32 relZ); | 
|---|
| 186 |  | 
|---|
| 187 | /** Called by any of the raw input devices when analog axis movement is detected. */ | 
|---|
| 188 | void _notifyAxisMoved(UINT32 gamepadIdx, UINT32 axisIdx, INT32 value); | 
|---|
| 189 |  | 
|---|
| 190 | /** Called by any of the raw input devices when a button is pressed. */ | 
|---|
| 191 | void _notifyButtonPressed(UINT32 deviceIdx, ButtonCode code, UINT64 timestamp); | 
|---|
| 192 |  | 
|---|
| 193 | /** Called by any of the raw input devices when a button is released. */ | 
|---|
| 194 | void _notifyButtonReleased(UINT32 deviceIdx, ButtonCode code, UINT64 timestamp); | 
|---|
| 195 |  | 
|---|
| 196 | /** @} */ | 
|---|
| 197 |  | 
|---|
| 198 | private: | 
|---|
| 199 | /** Performs platform specific raw input system initialization. */ | 
|---|
| 200 | void initRawInput(); | 
|---|
| 201 |  | 
|---|
| 202 | /** Performs platform specific raw input system cleanup. */ | 
|---|
| 203 | void cleanUpRawInput(); | 
|---|
| 204 |  | 
|---|
| 205 | /** | 
|---|
| 206 | * Smooths the input mouse axis value. Smoothing makes the changes to the axis more gradual depending on previous | 
|---|
| 207 | * values. | 
|---|
| 208 | * | 
|---|
| 209 | * @param[in]	value	Value to smooth. | 
|---|
| 210 | * @param[in]	idx		Index of the mouse axis to smooth, 0 - horizontal, 1 - vertical. | 
|---|
| 211 | * @return				Smoothed value. | 
|---|
| 212 | */ | 
|---|
| 213 | float smoothMouse(float value, UINT32 idx); | 
|---|
| 214 |  | 
|---|
| 215 | /**	Triggered by input handler when a button is pressed. */ | 
|---|
| 216 | void buttonDown(UINT32 deviceIdx, ButtonCode code, UINT64 timestamp); | 
|---|
| 217 |  | 
|---|
| 218 | /**	Triggered by input handler when a button is released. */ | 
|---|
| 219 | void buttonUp(UINT32 deviceIdx, ButtonCode code, UINT64 timestamp); | 
|---|
| 220 |  | 
|---|
| 221 | /**	Triggered by input handler when a mouse/joystick axis is moved. */ | 
|---|
| 222 | void axisMoved(UINT32 deviceIdx, float value, UINT32 axis); | 
|---|
| 223 |  | 
|---|
| 224 | /** | 
|---|
| 225 | * Called from the message loop to notify user has entered a character. | 
|---|
| 226 | * | 
|---|
| 227 | * @see		onCharInput | 
|---|
| 228 | */ | 
|---|
| 229 | void charInput(UINT32 character); | 
|---|
| 230 |  | 
|---|
| 231 | /** | 
|---|
| 232 | * Called from the message loop to notify user has moved the cursor. | 
|---|
| 233 | * | 
|---|
| 234 | * @see		onCursorMoved | 
|---|
| 235 | */ | 
|---|
| 236 | void cursorMoved(const Vector2I& cursorPos, const OSPointerButtonStates& btnStates); | 
|---|
| 237 |  | 
|---|
| 238 | /** | 
|---|
| 239 | * Called from the message loop to notify user has pressed a mouse button. | 
|---|
| 240 | * | 
|---|
| 241 | * @see		onCursorPressed | 
|---|
| 242 | */ | 
|---|
| 243 | void cursorPressed(const Vector2I& cursorPos, OSMouseButton button, const OSPointerButtonStates& btnStates); | 
|---|
| 244 |  | 
|---|
| 245 | /** | 
|---|
| 246 | * Called from the message loop to notify user has released a mouse button. | 
|---|
| 247 | * | 
|---|
| 248 | * @see		onCursorReleased | 
|---|
| 249 | */ | 
|---|
| 250 | void cursorReleased(const Vector2I& cursorPos, OSMouseButton button, const OSPointerButtonStates& btnStates); | 
|---|
| 251 |  | 
|---|
| 252 | /** | 
|---|
| 253 | * Called from the message loop to notify user has double-clicked a mouse button. | 
|---|
| 254 | * | 
|---|
| 255 | * @see		onDoubleClick | 
|---|
| 256 | */ | 
|---|
| 257 | void cursorDoubleClick(const Vector2I& cursorPos, const OSPointerButtonStates& btnStates); | 
|---|
| 258 |  | 
|---|
| 259 | /** | 
|---|
| 260 | * Called from the message loop to notify user has entered an input command. | 
|---|
| 261 | * | 
|---|
| 262 | * @see		onInputCommand | 
|---|
| 263 | */ | 
|---|
| 264 | void inputCommandEntered(InputCommandType commandType); | 
|---|
| 265 |  | 
|---|
| 266 | /** | 
|---|
| 267 | * Called from the message loop to notify user has scrolled the mouse wheel. | 
|---|
| 268 | * | 
|---|
| 269 | * @see		onMouseWheelScrolled | 
|---|
| 270 | */ | 
|---|
| 271 | void mouseWheelScrolled(float scrollPos); | 
|---|
| 272 |  | 
|---|
| 273 | /** Called when window in focus changes, as reported by the OS. */ | 
|---|
| 274 | void inputWindowChanged(RenderWindow& win); | 
|---|
| 275 |  | 
|---|
| 276 | /** | 
|---|
| 277 | * Called when the current window loses input focus. This might be followed by inputWindowChanged() if the focus | 
|---|
| 278 | * just switched to another of this application's windows. | 
|---|
| 279 | */ | 
|---|
| 280 | void inputFocusLost(); | 
|---|
| 281 |  | 
|---|
| 282 | private: | 
|---|
| 283 | Mutex mMutex; | 
|---|
| 284 |  | 
|---|
| 285 | Vector<DeviceData> mDevices; | 
|---|
| 286 | Vector2I mLastPointerPosition; | 
|---|
| 287 | Vector2I mPointerDelta; | 
|---|
| 288 | ButtonState mPointerButtonStates[3]; | 
|---|
| 289 | bool mPointerDoubleClicked = false; | 
|---|
| 290 | bool mLastPositionSet = false; | 
|---|
| 291 |  | 
|---|
| 292 | // Thread safe | 
|---|
| 293 | Vector2I mPointerPosition; | 
|---|
| 294 | float mMouseScroll = 0.0f; | 
|---|
| 295 | OSPointerButtonStates mPointerState; | 
|---|
| 296 |  | 
|---|
| 297 | Vector<QueuedEvent> mQueuedEvents[2]; | 
|---|
| 298 |  | 
|---|
| 299 | Vector<TextInputEvent> mTextInputEvents[2]; | 
|---|
| 300 | Vector<InputCommandType> mCommandEvents[2]; | 
|---|
| 301 | Vector<PointerEvent> mPointerDoubleClickEvents[2]; | 
|---|
| 302 | Vector<PointerEvent> mPointerReleasedEvents[2]; | 
|---|
| 303 | Vector<PointerEvent> mPointerPressedEvents[2]; | 
|---|
| 304 |  | 
|---|
| 305 | Vector<ButtonEvent> mButtonDownEvents[2]; | 
|---|
| 306 | Vector<ButtonEvent> mButtonUpEvents[2]; | 
|---|
| 307 |  | 
|---|
| 308 | // OS input events | 
|---|
| 309 | HEvent mCharInputConn; | 
|---|
| 310 | HEvent mCursorMovedConn; | 
|---|
| 311 | HEvent mCursorPressedConn; | 
|---|
| 312 | HEvent mCursorReleasedConn; | 
|---|
| 313 | HEvent mCursorDoubleClickConn; | 
|---|
| 314 | HEvent mInputCommandConn; | 
|---|
| 315 | HEvent mMouseWheelScrolledConn; | 
|---|
| 316 |  | 
|---|
| 317 | // Raw input | 
|---|
| 318 | bool mMouseSmoothingEnabled = false; | 
|---|
| 319 | UINT64 mWindowHandle; | 
|---|
| 320 |  | 
|---|
| 321 | Mouse* mMouse = nullptr; | 
|---|
| 322 | Keyboard* mKeyboard = nullptr; | 
|---|
| 323 | Vector<Gamepad*> mGamepads; | 
|---|
| 324 |  | 
|---|
| 325 | float mTotalMouseSamplingTime[2]; | 
|---|
| 326 | UINT32 mTotalMouseNumSamples[2]; | 
|---|
| 327 | float mMouseZeroTime[2]; | 
|---|
| 328 | INT32 mMouseSampleAccumulator[2]; | 
|---|
| 329 | float mMouseSmoothedAxis[2]; | 
|---|
| 330 | UINT64 mLastMouseUpdateFrame; | 
|---|
| 331 |  | 
|---|
| 332 | UINT64 mTimestampClockOffset; | 
|---|
| 333 |  | 
|---|
| 334 | InputPrivateData* mPlatformData; | 
|---|
| 335 |  | 
|---|
| 336 | /************************************************************************/ | 
|---|
| 337 | /* 								STATICS		                      		*/ | 
|---|
| 338 | /************************************************************************/ | 
|---|
| 339 | static const int HISTORY_BUFFER_SIZE; // Size of buffer used for input smoothing | 
|---|
| 340 | static const float WEIGHT_MODIFIER; | 
|---|
| 341 | }; | 
|---|
| 342 |  | 
|---|
| 343 | /** Provides global access to Input. */ | 
|---|
| 344 | BS_CORE_EXPORT Input& gInput(); | 
|---|
| 345 |  | 
|---|
| 346 | /** @} */ | 
|---|
| 347 | } | 
|---|
| 348 |  | 
|---|