//********************************** Banshee Engine (www.banshee3d.com) **************************************************// //**************** Copyright (c) 2016 Marko Pintera (marko.pintera@gmail.com). All rights reserved. **********************// #pragma once #include "BsCorePrerequisites.h" #include "Utility/BsModule.h" #include "Platform/BsPlatform.h" #include "Input/BsInputFwd.h" namespace bs { class Mouse; class Keyboard; class Gamepad; struct InputPrivateData; /** @addtogroup Input * @{ */ /** * Primary module used for dealing with input. Allows you to receieve and query raw or OS input for * mouse/keyboard/gamepad. */ class BS_CORE_EXPORT Input : public Module { /** Possible button states. */ enum class ButtonState { Off, /**< Button is not being pressed. */ On, /**< Button is being pressed. */ ToggledOn, /**< Button has been pressed this frame. */ ToggledOff, /**< Button has been released this frame. */ ToggledOnOff, /**< Button has been pressed and released this frame. */ }; /** Contains axis and device data per device. */ struct DeviceData { DeviceData(); Vector axes; ButtonState keyStates[BC_Count]; }; /** Different types of possible input event callbacks. */ enum class EventType { ButtonUp, ButtonDown, PointerMoved, PointerUp, PointerDown, PointerDoubleClick, TextInput, Command }; /** Stores information about a queued input event that is to be triggered later. */ struct QueuedEvent { QueuedEvent(EventType type, UINT32 idx) :type(type), idx(idx) { } EventType type; UINT32 idx; }; public: Input(); ~Input(); /** * Returns value of the specified input axis. Normally in range [-1.0, 1.0] but can be outside the range for * devices with unbound axes (for example mouse). * * @param[in] type Type of axis to query. Usually a type from InputAxis but can be a custom value. * @param[in] deviceIdx Index of the device in case more than one is hooked up (0 - primary). */ float getAxisValue(UINT32 type, UINT32 deviceIdx = 0) const; /** * Query if the provided button is currently being held (this frame or previous frames). * * @param[in] keyCode Code of the button to query. * @param[in] deviceIdx Device to query the button on (0 - primary). */ bool isButtonHeld(ButtonCode keyCode, UINT32 deviceIdx = 0) const; /** * Query if the provided button is currently being released (only true for one frame). * * @param[in] keyCode Code of the button to query. * @param[in] deviceIdx Device to query the button on (0 - primary). */ bool isButtonUp(ButtonCode keyCode, UINT32 deviceIdx = 0) const; /** * Query if the provided button is currently being pressed (only true for one frame). * * @param[in] keyCode Code of the button to query. * @param[in] deviceIdx Device to query the button on (0 - primary). */ bool isButtonDown(ButtonCode keyCode, UINT32 deviceIdx = 0) const; /** Returns position of the pointer (for example mouse cursor) relative to the screen. */ Vector2I getPointerPosition() const; /** Returns difference between pointer position between current and last frame. */ Vector2I getPointerDelta() const { return mPointerDelta; } /** * Query if the provided pointer button is currently being held (this frame or previous frames). * * @param[in] pointerButton Code of the button to query. */ bool isPointerButtonHeld(PointerEventButton pointerButton) const; /** * Query if the provided pointer button is currently being released (only true for one frame). * * @param[in] pointerButton Code of the button to query. */ bool isPointerButtonUp(PointerEventButton pointerButton) const; /** * Query if the provided pointer button is currently being pressed (only true for one frame). * * @param[in] pointerButton Code of the button to query. */ bool isPointerButtonDown(PointerEventButton pointerButton) const; /** Query has the left pointer button has been double-clicked this frame. */ bool isPointerDoubleClicked() const; /** Enables or disables mouse smoothing. Smoothing makes the changes to mouse axes more gradual. */ void setMouseSmoothing(bool enabled); /** Returns the number of detected devices of the specified type. */ UINT32 getDeviceCount(InputDevice device) const; /** Returns the name of a specific input device. Returns empty string if the device doesn't exist. */ String getDeviceName(InputDevice type, UINT32 idx); /** Triggered whenever a button is first pressed. */ Event onButtonDown; /** Triggered whenever a button is first released. */ Event onButtonUp; /** Triggered whenever user inputs a text character. */ Event onCharInput; /** Triggers when some pointing device (mouse cursor, touch) moves. */ Event onPointerMoved; /** Triggers when some pointing device (mouse cursor, touch) button is pressed. */ Event onPointerPressed; /** Triggers when some pointing device (mouse cursor, touch) button is released. */ Event onPointerReleased; /** Triggers when some pointing device (mouse cursor, touch) button is double clicked. */ Event onPointerDoubleClick; // TODO Low priority: Remove this, I can emulate it using virtual input /** Triggers on special input commands. */ Event onInputCommand; public: // ***** INTERNAL ****** /** @name Internal * @{ */ /** * Called every frame. Detects button state changes and prepares callback events to trigger via a call to * _triggerCallbacks(). */ void _update(); /** Triggers any queued input event callbacks. */ void _triggerCallbacks(); /** Returns internal, platform specific privata data. */ InputPrivateData* _getPrivateData() const { return mPlatformData; } /** Returns a handle to the window that is currently receiving input. */ UINT64 _getWindowHandle() const { return mWindowHandle; } /** Called by Mouse when mouse movement is detected. */ void _notifyMouseMoved(INT32 relX, INT32 relY, INT32 relZ); /** Called by any of the raw input devices when analog axis movement is detected. */ void _notifyAxisMoved(UINT32 gamepadIdx, UINT32 axisIdx, INT32 value); /** Called by any of the raw input devices when a button is pressed. */ void _notifyButtonPressed(UINT32 deviceIdx, ButtonCode code, UINT64 timestamp); /** Called by any of the raw input devices when a button is released. */ void _notifyButtonReleased(UINT32 deviceIdx, ButtonCode code, UINT64 timestamp); /** @} */ private: /** Performs platform specific raw input system initialization. */ void initRawInput(); /** Performs platform specific raw input system cleanup. */ void cleanUpRawInput(); /** * Smooths the input mouse axis value. Smoothing makes the changes to the axis more gradual depending on previous * values. * * @param[in] value Value to smooth. * @param[in] idx Index of the mouse axis to smooth, 0 - horizontal, 1 - vertical. * @return Smoothed value. */ float smoothMouse(float value, UINT32 idx); /** Triggered by input handler when a button is pressed. */ void buttonDown(UINT32 deviceIdx, ButtonCode code, UINT64 timestamp); /** Triggered by input handler when a button is released. */ void buttonUp(UINT32 deviceIdx, ButtonCode code, UINT64 timestamp); /** Triggered by input handler when a mouse/joystick axis is moved. */ void axisMoved(UINT32 deviceIdx, float value, UINT32 axis); /** * Called from the message loop to notify user has entered a character. * * @see onCharInput */ void charInput(UINT32 character); /** * Called from the message loop to notify user has moved the cursor. * * @see onCursorMoved */ void cursorMoved(const Vector2I& cursorPos, const OSPointerButtonStates& btnStates); /** * Called from the message loop to notify user has pressed a mouse button. * * @see onCursorPressed */ void cursorPressed(const Vector2I& cursorPos, OSMouseButton button, const OSPointerButtonStates& btnStates); /** * Called from the message loop to notify user has released a mouse button. * * @see onCursorReleased */ void cursorReleased(const Vector2I& cursorPos, OSMouseButton button, const OSPointerButtonStates& btnStates); /** * Called from the message loop to notify user has double-clicked a mouse button. * * @see onDoubleClick */ void cursorDoubleClick(const Vector2I& cursorPos, const OSPointerButtonStates& btnStates); /** * Called from the message loop to notify user has entered an input command. * * @see onInputCommand */ void inputCommandEntered(InputCommandType commandType); /** * Called from the message loop to notify user has scrolled the mouse wheel. * * @see onMouseWheelScrolled */ void mouseWheelScrolled(float scrollPos); /** Called when window in focus changes, as reported by the OS. */ void inputWindowChanged(RenderWindow& win); private: Mutex mMutex; Vector mDevices; Vector2I mLastPointerPosition; Vector2I mPointerDelta; ButtonState mPointerButtonStates[3]; bool mPointerDoubleClicked; bool mLastPositionSet; // Thread safe Vector2I mPointerPosition; float mMouseScroll; OSPointerButtonStates mPointerState; Vector mQueuedEvents[2]; Vector mTextInputEvents[2]; Vector mCommandEvents[2]; Vector mPointerDoubleClickEvents[2]; Vector mPointerReleasedEvents[2]; Vector mPointerPressedEvents[2]; Vector mButtonDownEvents[2]; Vector mButtonUpEvents[2]; // OS input events HEvent mCharInputConn; HEvent mCursorMovedConn; HEvent mCursorPressedConn; HEvent mCursorReleasedConn; HEvent mCursorDoubleClickConn; HEvent mInputCommandConn; HEvent mMouseWheelScrolledConn; // Raw input bool mMouseSmoothingEnabled; UINT64 mWindowHandle; Mouse* mMouse; Keyboard* mKeyboard; Vector mGamepads; float mTotalMouseSamplingTime[2]; UINT32 mTotalMouseNumSamples[2]; float mMouseZeroTime[2]; INT32 mMouseSampleAccumulator[2]; float mMouseSmoothedAxis[2]; UINT64 mLastMouseUpdateFrame; UINT64 mTimestampClockOffset; InputPrivateData* mPlatformData; /************************************************************************/ /* STATICS */ /************************************************************************/ static const int HISTORY_BUFFER_SIZE; // Size of buffer used for input smoothing static const float WEIGHT_MODIFIER; }; /** Provides global access to Input. */ BS_CORE_EXPORT Input& gInput(); /** @} */ }