/* Copyright (c) 2014 Alex Diener This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Alex Diener alex@ludobloom.com */ #ifndef __InputController_H__ #define __InputController_H__ #ifdef __cplusplus extern "C" { #endif typedef struct InputController InputController; #define InputController_superclass StemObject #include "inputcontroller/GamepadLogicalInputController.h" #include "inputcontroller/InputMap.h" #include "gamemath/Vector2x.h" #include "gamepad/Gamepad.h" #include "stemobject/StemObject.h" #include "utilities/EventDispatcher.h" #include "utilities/HashTable.h" #include // eventData -> InputController_event * #define INPUT_CONTROLLER_EVENT_ACTION_DOWN "INPUT_CONTROLLER_EVENT_ACTION_DOWN" #define INPUT_CONTROLLER_EVENT_ACTION_REPEAT "INPUT_CONTROLLER_EVENT_ACTION_REPEAT" #define INPUT_CONTROLLER_EVENT_ACTION_UP "INPUT_CONTROLLER_EVENT_ACTION_UP" // eventData -> InputController_motionEvent * #define INPUT_CONTROLLER_EVENT_MOTION "INPUT_CONTROLLER_EVENT_MOTION" struct InputController_event { Atom actionID; double timestamp; InputMap_bindingGeneric binding; // Defined only for INPUT_CONTROLLER_EVENT_ACTION_DOWN }; struct InputController_motionEvent { Atom actionID; double timestamp; // Corrected by dead zones or mouse sensitivity multipliers. Note that physical axis motion bindings do not correct for dead zones, as they can't determine the type of element. fixed16_16 valueX; fixed16_16 valueY; // Unused for 1D events // Uncorrected by dead zones or mouse sensitivity multipliers fixed16_16 rawValueX; fixed16_16 rawValueY; // Unused for 1D events }; struct InputController_action { Atom actionID; bool active; fixed16_16 lastX; fixed16_16 lastY; unsigned int modifiersWhenStarted; unsigned int repeatCount; double nextRepeatReferenceTime; double timeUntilNextRepeat; }; #define InputController_ivars \ StemObject_ivars \ \ EventDispatcher * eventDispatcher; \ GamepadLogicalInputController * gamepadInputController; \ InputMap * inputMap; \ unsigned int actionCount; \ struct InputController_action * actions; \ HashTable * motion2DAxisValueMemory; \ double repeatInitialDelay; \ double repeatInterval; \ double lastRepeatReferenceTime; \ float mouseSensitivityX; \ float mouseSensitivityY; #define InputController_vtable(self_type) \ StemObject_vtable(self_type) \ bool (* startAction)(self_type * self, Atom actionID, double timestamp, bool peek, InputMap_bindingGeneric binding); \ bool (* stopAction)(self_type * self, Atom actionID, double timestamp, bool peek); \ bool (* motion)(self_type * self, Atom actionID, double timestamp, fixed16_16 valueX, fixed16_16 valueY, fixed16_16 rawValueX, fixed16_16 rawValueY, bool peek); stemobject_declare(InputController) // Additional arguments: List of all valid action ID strings InputController * InputController_create(GamepadMap * gamepadMap, InputMap * inputMap, ...) __attribute__((sentinel)); InputController * InputController_vcreate(GamepadMap * gamepadMap, InputMap * inputMap, va_list args); bool InputController_init(InputController * self, GamepadMap * gamepadMap, InputMap * inputMap, ...) __attribute__((sentinel)); bool InputController_vinit(InputController * self, GamepadMap * gamepadMap, InputMap * inputMap, va_list args); void InputController_dispose(InputController * self); // If peek is set to true, these functions only return a boolean indicating whether a state change would happen from the input. // If peek is set to false, INPUT_CONTROLLER_EVENT_* events are sent to registered event handlers, and the return value indicates // whether any registered event handler returned true. bool InputController_keyDown(InputController * self, unsigned int keyCode, unsigned int modifiers, double timestamp, bool peek); bool InputController_keyUp(InputController * self, unsigned int keyCode, double timestamp, bool peek); bool InputController_keyModifiersChanged(InputController * self, unsigned int modifiers, unsigned int lastModifiers, double timestamp, bool peek); bool InputController_mouseDown(InputController * self, unsigned int buttonNumber, double timestamp, bool peek); bool InputController_mouseUp(InputController * self, unsigned int buttonNumber, double timestamp, bool peek); bool InputController_mouseMoved(InputController * self, float deltaX, float deltaY, double timestamp, bool peek); // Call for both move and drag events bool InputController_mouseScrollWheel(InputController * self, int deltaX, int deltaY, double timestamp, bool peek); bool InputController_gamepadButtonDown(InputController * self, struct Gamepad_device * device, unsigned int buttonID, double timestamp, bool peek); bool InputController_gamepadButtonUp(InputController * self, struct Gamepad_device * device, unsigned int buttonID, double timestamp, bool peek); bool InputController_gamepadAxisMoved(InputController * self, struct Gamepad_device * device, unsigned int axisID, float value, float lastValue, double timestamp, bool peek); bool InputController_startAction(InputController * self, Atom actionID, double timestamp, bool peek, InputMap_bindingGeneric binding); bool InputController_stopAction(InputController * self, Atom actionID, double timestamp, bool peek); bool InputController_motion(InputController * self, Atom actionID, double timestamp, fixed16_16 valueX, fixed16_16 valueY, fixed16_16 rawValueX, fixed16_16 rawValueY, bool peek); bool InputController_isActionActive(InputController * self, Atom actionID); Vector2x InputController_getMotionState(InputController * self, Atom actionID); void InputController_reset(InputController * self); void InputController_setRepeatRate(InputController * self, double initialDelay, double repeatInterval); // referenceTime should be a monotonically-increasing value which indicates the actual time at which this function is called. // Shell_getCurrentTime() returns an appropriate value for this. // timeElapsed represents the effective uptime on key repeat since the last call to this function. This should usually be // the difference between the previously passed referenceTime and its current value, but it can be less if there was a // pause in input processing, and you wish to resume without incurring every repeat event that would have been dispatched // during the pause time. void InputController_processRepeats(InputController * self, double referenceTime, double timeElapsed); #ifdef __cplusplus } #endif #endif