From 038737423b492eadb3505cdd4511cb916887af02 Mon Sep 17 00:00:00 2001 From: danij Date: Sat, 1 Nov 2014 18:41:19 +0000 Subject: [PATCH] Refactor|InputSystem|Client: Hide the meaning of InputDevice(Control) IDs at API level Users of the InputDevices should not assume anything from the IDs assigned to devices and/or their controls. --- doomsday/client/include/ui/b_command.h | 4 +- doomsday/client/include/ui/b_context.h | 5 +- doomsday/client/include/ui/b_device.h | 4 +- doomsday/client/include/ui/b_main.h | 4 +- doomsday/client/include/ui/b_util.h | 23 +- doomsday/client/include/ui/dd_input.h | 121 +++++++--- doomsday/client/src/ui/b_command.cpp | 35 ++- doomsday/client/src/ui/b_context.cpp | 122 ++++------ doomsday/client/src/ui/b_device.cpp | 25 +- doomsday/client/src/ui/b_util.cpp | 35 ++- doomsday/client/src/ui/dd_input.cpp | 305 +++++++++++++++---------- doomsday/client/src/ui/p_control.cpp | 21 +- 12 files changed, 393 insertions(+), 311 deletions(-) diff --git a/doomsday/client/include/ui/b_command.h b/doomsday/client/include/ui/b_command.h index a41cdde0fe..8dbf62e8aa 100644 --- a/doomsday/client/include/ui/b_command.h +++ b/doomsday/client/include/ui/b_command.h @@ -24,6 +24,8 @@ #include "b_util.h" #include "dd_input.h" +struct bcontext_t; + typedef struct evbinding_s { struct evbinding_s *prev; ///< Previous in list of bindings. struct evbinding_s *next; ///< Next in list of bindings. @@ -86,6 +88,6 @@ evbinding_t *B_FindCommandBinding(evbinding_t const *listRoot, char const *comma * @return Action to be triggered, or @c nullptr. Caller gets ownership. */ de::Action *EventBinding_ActionForEvent(evbinding_t *eb, ddevent_t const *event, - struct bcontext_s *eventClass, bool respectHigherAssociatedContexts); + bcontext_t *eventClass, bool respectHigherAssociatedContexts); #endif // CLIENT_INPUTSYSTEM_EVENTBINDING_H diff --git a/doomsday/client/include/ui/b_context.h b/doomsday/client/include/ui/b_context.h index 5b0aeec263..13f40cc930 100644 --- a/doomsday/client/include/ui/b_context.h +++ b/doomsday/client/include/ui/b_context.h @@ -39,14 +39,15 @@ typedef struct controlbinding_s { higher-priority contexts override it. */ #define BCF_ACQUIRE_ALL 0x08 ///< Context will acquire all unacquired states. -typedef struct bcontext_s { +struct bcontext_t +{ char *name; ///< Name of the binding context. byte flags; evbinding_t commandBinds; ///< List of command bindings. controlbinding_t controlBinds; int (*ddFallbackResponder)(ddevent_t const *ddev); int (*fallbackResponder)(event_t *event); -} bcontext_t; +}; /** * Marks all device states with the highest-priority binding context to diff --git a/doomsday/client/include/ui/b_device.h b/doomsday/client/include/ui/b_device.h index 6e8931d281..bdbb189943 100644 --- a/doomsday/client/include/ui/b_device.h +++ b/doomsday/client/include/ui/b_device.h @@ -22,6 +22,8 @@ #include "b_util.h" +struct bcontext_t; + typedef enum cbdevtype_e { CBD_TOGGLE = E_TOGGLE, CBD_AXIS = E_AXIS, @@ -65,7 +67,7 @@ void B_DestroyDeviceBinding(dbinding_t *cb); void B_DeviceBindingToString(dbinding_t const *b, ddstring_t *str); void B_EvaluateDeviceBindingList(int localNum, dbinding_t *listRoot, float *pos, - float *relativeOffset, struct bcontext_s *controlClass, dd_bool allowTriggered); + float *relativeOffset, bcontext_t *controlClass, dd_bool allowTriggered); #endif // CLIENT_INPUTSYSTEM_DEVICEBINDING_H diff --git a/doomsday/client/include/ui/b_main.h b/doomsday/client/include/ui/b_main.h index 0ea12bb3e3..b01daad79a 100644 --- a/doomsday/client/include/ui/b_main.h +++ b/doomsday/client/include/ui/b_main.h @@ -23,6 +23,8 @@ #include #include "dd_input.h" +struct bcontext_t; + #define DEFAULT_BINDING_CONTEXT_NAME "game" #define CONSOLE_BINDING_CONTEXT_NAME "console" #define UI_BINDING_CONTEXT_NAME "deui" @@ -69,7 +71,7 @@ struct evbinding_s *B_BindCommand(char const *eventDesc, char const *command); struct dbinding_s *B_BindControl(char const *controlDesc, char const *device); -struct dbinding_s *B_GetControlDeviceBindings(int localNum, int control, struct bcontext_s **bContext); +struct dbinding_s *B_GetControlDeviceBindings(int localNum, int control, bcontext_t **bContext); bool B_UnbindCommand(char const *command); diff --git a/doomsday/client/include/ui/b_util.h b/doomsday/client/include/ui/b_util.h index d84a679500..5695e86005 100644 --- a/doomsday/client/include/ui/b_util.h +++ b/doomsday/client/include/ui/b_util.h @@ -23,8 +23,11 @@ #include "dd_types.h" #include "dd_input.h" +struct bcontext_t; + // Event Binding Toggle State -typedef enum ebstate_e { +enum ebstate_t +{ EBTOG_UNDEFINED, EBTOG_DOWN, EBTOG_REPEAT, @@ -34,18 +37,20 @@ typedef enum ebstate_e { EBAXIS_BEYOND, EBAXIS_BEYOND_POSITIVE, EBAXIS_BEYOND_NEGATIVE -} ebstate_t; +}; -typedef enum stateconditiontype_e { +enum stateconditiontype_t +{ SCT_STATE, ///< Related to the state of the engine. SCT_TOGGLE_STATE, ///< Toggle is in a specific state. SCT_MODIFIER_STATE, ///< Modifier is in a specific state. SCT_AXIS_BEYOND, ///< Axis is past a specific position. SCT_ANGLE_AT ///< Angle is pointing to a specific direction. -} stateconditiontype_t; +}; // Device state condition. -typedef struct statecondition_s { +struct statecondition_t +{ uint device; ///< Which device? stateconditiontype_t type; int id; ///< Toggle/axis/angle identifier in the device. @@ -55,7 +60,7 @@ typedef struct statecondition_s { uint negate:1; ///< Test the inverse (e.g., not in a specific state). uint multiplayer:1; ///< Only for multiplayer. } flags; -} statecondition_t; +}; dd_bool B_ParseToggleState(char const *toggleName, ebstate_t *state); @@ -65,7 +70,7 @@ dd_bool B_ParseKeyId(char const *desc, int *id); dd_bool B_ParseMouseTypeAndId(char const *desc, ddeventtype_t *type, int *id); -dd_bool B_ParseJoystickTypeAndId(int device, char const *desc, ddeventtype_t *type, int *id); +dd_bool B_ParseJoystickTypeAndId(InputDevice const &device, char const *desc, ddeventtype_t *type, int *id); dd_bool B_ParseAnglePosition(char const *desc, float *pos); @@ -78,11 +83,11 @@ dd_bool B_CheckAxisPos(ebstate_t test, float testPos, float pos); * @param localNum Local player number. * @param context Relevant binding context, if any (may be @c nullptr). */ -dd_bool B_CheckCondition(statecondition_t *cond, int localNum, struct bcontext_s *context); +dd_bool B_CheckCondition(statecondition_t *cond, int localNum, bcontext_t *context); dd_bool B_EqualConditions(statecondition_t const *a, statecondition_t const *b); -void B_AppendDeviceDescToString(int device, ddeventtype_t type, int id, ddstring_t *str); +void B_AppendDeviceDescToString(InputDevice const &device, ddeventtype_t type, int id, ddstring_t *str); void B_AppendToggleStateToString(ebstate_t state, ddstring_t *str); diff --git a/doomsday/client/include/ui/dd_input.h b/doomsday/client/include/ui/dd_input.h index d8f08c402b..5c73fbf6f4 100644 --- a/doomsday/client/include/ui/dd_input.h +++ b/doomsday/client/include/ui/dd_input.h @@ -20,6 +20,8 @@ #ifndef CLIENT_CORE_INPUT_H #define CLIENT_CORE_INPUT_H +#include +#include #include #include #include @@ -27,20 +29,7 @@ #include "api_event.h" -// Binding association flags: -#define IDAF_EXPIRED 0x1 /** The state has expired. The device is considered to remain - in default state until the flag gets cleared (which happens when - the real device state returns to its default). */ -#define IDAF_TRIGGERED 0x2 /** The state has been triggered. This is cleared when someone checks - the device state. (Only for toggles.) */ - -// Binding association. How the device control relates to binding contexts. -struct inputdevassoc_t -{ - struct bcontext_s *bContext; - struct bcontext_s *prevBContext; - int flags; -}; +struct bcontext_t; class InputDeviceAxisControl; class InputDeviceButtonControl; @@ -66,12 +55,35 @@ class InputDevice /// No InputDevice is associated with the control. @ingroup errors DENG2_ERROR(MissingDeviceError); + /** + * How the control state relates to binding contexts. + */ + enum BindContextAssociationFlag { + /// The state has expired. The control is considered to remain in default + /// state until the flag gets cleared (which happens when the real control + /// state returns to its default). + Expired = 0x1, + + /// The state has been triggered. This is cleared when someone checks + /// the control state. (Only for toggles). + Triggered = 0x2, + + DefaultFlags = 0 + }; + Q_DECLARE_FLAGS(BindContextAssociation, BindContextAssociationFlag) + public: explicit Control(InputDevice *device = nullptr); - virtual ~Control() {} + virtual ~Control(); DENG2_AS_IS_METHODS() + /** + * Returns @c true if the control is presently in its default state. + * (e.g., button is not pressed, axis is at center, etc...). + */ + virtual bool inDefaultState() const = 0; + /** * Reset the control back to its default state. Note that any attributed * property values (name, device and binding association) are unaffected. @@ -127,10 +139,44 @@ class InputDevice void setDevice(InputDevice *newDevice); /** - * Provides access to the binding association data of the control. + * Returns the bcontext_t attributed to the control; otherwise @c nullptr. + * + * @see hasBindContext(), setBindContext() + */ + bcontext_t *bindContext() const; + + /** + * Returns @c true of a bcontext_t is attributed to the control. + * + * @see bindContext(), setBindContext() + */ + inline bool hasBindContext() const { return bindContext() != nullptr; } + + /** + * Change the attributed bcontext_t to @a newContext. + * + * @param newContext bcontext_t to attribute. Ownership is unaffected. + * + * @see hasBindContext(), bindContext() + */ + void setBindContext(bcontext_t *newContext); + + /** + * Returns the BindContextAssociation flags for the control. + */ + BindContextAssociation bindContextAssociation() const; + + /** + * Change the BindContextAssociation flags for the control. + * + * @param flagsToChange Association flags to change. + * @param op Logical operation to perform. */ - inputdevassoc_t &association(); - inputdevassoc_t const &association() const; + void setBindContextAssociation(BindContextAssociation const &flagsToChange, + de::FlagOp op = de::SetFlags); + + void clearBindContextAssociation(); + void expireBindContextAssociationIfChanged(); /** * Register the console commands and variables of the control. @@ -138,9 +184,7 @@ class InputDevice virtual void consoleRegister() {} private: - InputDevice *_device; - de::String _name; ///< Symbolic - inputdevassoc_t _assoc; ///< Binding association. + DENG2_PRIVATE(d) }; public: @@ -196,7 +240,10 @@ class InputDevice */ void reset(); - void clearAllControlContextAssociations(); + /** + * Iterate through all the controls of the device. + */ + de::LoopResult forAllControls(std::function func); /** * Translate a symbolic axis @a name to the associated unique axis id. @@ -205,6 +252,11 @@ class InputDevice */ de::dint toAxisId(de::String const &name) const; + /** + * Returns @c true if @a id is a known axis control. + */ + bool hasAxis(de::dint id) const; + /** * Lookup an axis control by unique @a id. * @@ -233,6 +285,11 @@ class InputDevice */ de::dint toButtonId(de::String const &name) const; + /** + * Returns @c true if @a id is a known button control. + */ + bool hasButton(de::dint id) const; + /** * Lookup a button control by unique @a id. * @@ -249,6 +306,11 @@ class InputDevice */ de::dint buttonCount() const; + /** + * Returns @c true if @a id is a known hat control. + */ + bool hasHat(de::dint id) const; + /** * Lookup a hat control by unique @a id. * @@ -274,6 +336,8 @@ class InputDevice DENG2_PRIVATE(d) }; +Q_DECLARE_OPERATORS_FOR_FLAGS(InputDevice::Control::BindContextAssociation) + typedef InputDevice::Control InputDeviceControl; // Input device axis flags for use with cvars: @@ -341,9 +405,9 @@ class InputDeviceAxisControl : public InputDeviceControl de::duint time() const; void update(timespan_t ticLength); - void clearContextAssociation(); de::String description() const; + bool inDefaultState() const; void reset(); void consoleRegister(); @@ -377,9 +441,8 @@ class InputDeviceButtonControl : public InputDeviceControl */ de::duint time() const; - void clearContextAssociation(); - de::String description() const; + bool inDefaultState() const; void reset(); private: @@ -413,9 +476,8 @@ class InputDeviceHatControl : public InputDeviceControl */ de::duint time() const; - void clearContextAssociation(); - de::String description() const; + bool inDefaultState() const; private: de::dint _pos = -1; ///< Current position. @c -1= centered. @@ -540,6 +602,11 @@ InputDevice &I_Device(int id); */ InputDevice *I_DevicePtr(int id); +/** + * Iterate through all the InputDevices. + */ +de::LoopResult I_ForAllDevices(std::function func); + /** * Initializes the key mappings to the default values. */ diff --git a/doomsday/client/src/ui/b_command.cpp b/doomsday/client/src/ui/b_command.cpp index 117c66c90c..76d2e2b0a5 100644 --- a/doomsday/client/src/ui/b_command.cpp +++ b/doomsday/client/src/ui/b_command.cpp @@ -28,6 +28,8 @@ #include +using namespace de; + void B_InitCommandBindingList(evbinding_t *listRoot) { DENG2_ASSERT(listRoot); @@ -135,7 +137,7 @@ static dd_bool B_ParseEvent(evbinding_t *eb, char const *desc) // Next part defined button, axis, or hat. desc = Str_CopyDelim(str, desc, '-'); - if(!B_ParseJoystickTypeAndId(eb->device, Str_Text(str), &eb->type, &eb->id)) + if(!B_ParseJoystickTypeAndId(I_Device(eb->device), Str_Text(str), &eb->type, &eb->id)) { return false; } @@ -337,10 +339,10 @@ static void B_SubstituteInCommand(char const *command, ddevent_t const *event, } } -de::Action *EventBinding_ActionForEvent(evbinding_t *eb, ddevent_t const *event, - struct bcontext_s *eventClass, bool respectHigherAssociatedContexts) +Action *EventBinding_ActionForEvent(evbinding_t *eb, ddevent_t const *event, + bcontext_t *bindContext, bool respectHigherAssociatedContexts) { - DENG2_ASSERT(eb); + DENG2_ASSERT(eb && bindContext); if(eb->device != event->device) return nullptr; if(eb->type != event->type) return nullptr; @@ -355,23 +357,24 @@ de::Action *EventBinding_ActionForEvent(evbinding_t *eb, ddevent_t const *event, return nullptr; } } + DENG2_ASSERT(dev); switch(event->type) { - case E_TOGGLE: - DENG2_ASSERT(dev && eventClass); - + case E_TOGGLE: { if(eb->id != event->toggle.id) return nullptr; + InputDeviceButtonControl &button = dev->button(eb->id); + if(respectHigherAssociatedContexts) { - if(eventClass && dev->button(eb->id).association().bContext != eventClass) + if(button.bindContext() != bindContext) return nullptr; // Shadowed by a more important active class. } // We're checking it, so clear the triggered flag. - dev->button(eb->id).association().flags &= ~IDAF_TRIGGERED; + button.setBindContextAssociation(InputDeviceControl::Triggered, UnsetFlags); // Is the state as required? switch(eb->state) @@ -402,15 +405,13 @@ de::Action *EventBinding_ActionForEvent(evbinding_t *eb, ddevent_t const *event, default: return nullptr; } - break; + break; } case E_AXIS: - DENG2_ASSERT(dev && eventClass); - if(eb->id != event->axis.id) return nullptr; - if(eventClass && dev->axis(eb->id).association().bContext != eventClass) + if(bindContext && dev->axis(eb->id).bindContext() != bindContext) return nullptr; // Shadowed by a more important active class. // Is the position as required? @@ -421,12 +422,10 @@ de::Action *EventBinding_ActionForEvent(evbinding_t *eb, ddevent_t const *event, break; case E_ANGLE: - DENG2_ASSERT(dev && eventClass); - if(eb->id != event->angle.id) return nullptr; - if(eventClass && dev->hat(eb->id).association().bContext != eventClass) + if(bindContext && dev->hat(eb->id).bindContext() != bindContext) return nullptr; // Shadowed by a more important active class. // Is the position as required? @@ -454,7 +453,7 @@ de::Action *EventBinding_ActionForEvent(evbinding_t *eb, ddevent_t const *event, Str_Reserve(&command, strlen(eb->command)); B_SubstituteInCommand(eb->command, event, eb, &command); - de::Action *act = new CommandAction(Str_Text(&command), CMDS_BIND); + Action *act = new CommandAction(Str_Text(&command), CMDS_BIND); Str_Free(&command); return act; @@ -465,7 +464,7 @@ void B_EventBindingToString(evbinding_t const *eb, ddstring_t *str) DENG2_ASSERT(eb && str); Str_Clear(str); - B_AppendDeviceDescToString(eb->device, eb->type, eb->id, str); + B_AppendDeviceDescToString(I_Device(eb->device), eb->type, eb->id, str); switch(eb->type) { diff --git a/doomsday/client/src/ui/b_context.cpp b/doomsday/client/src/ui/b_context.cpp index 9723ad2b0d..7b67717753 100644 --- a/doomsday/client/src/ui/b_context.cpp +++ b/doomsday/client/src/ui/b_context.cpp @@ -75,25 +75,25 @@ void B_UpdateAllDeviceStateAssociations() { case E_TOGGLE: { InputDeviceButtonControl &button = dev.button(eb->id); - if(!button.association().bContext) + if(!button.hasBindContext()) { - button.association().bContext = bc; + button.setBindContext(bc); } break; } case E_AXIS: { InputDeviceAxisControl &axis = dev.axis(eb->id); - if(!axis.association().bContext) + if(!axis.hasBindContext()) { - axis.association().bContext = bc; + axis.setBindContext(bc); } break; } case E_ANGLE: { InputDeviceHatControl &hat = dev.hat(eb->id); - if(!hat.association().bContext) + if(!hat.hasBindContext()) { - hat.association().bContext = bc; + hat.setBindContext(bc); } break; } @@ -119,25 +119,25 @@ void B_UpdateAllDeviceStateAssociations() { case CBD_TOGGLE: { InputDeviceButtonControl &button = dev.button(db->id); - if(!button.association().bContext) + if(!button.hasBindContext()) { - button.association().bContext = bc; + button.setBindContext(bc); } break; } case CBD_AXIS: { InputDeviceAxisControl &axis = dev.axis(db->id); - if(!axis.association().bContext) + if(!axis.hasBindContext()) { - axis.association().bContext = bc; + axis.setBindContext(bc); } break; } case CBD_ANGLE: { InputDeviceHatControl &hat = dev.hat(db->id); - if(!hat.association().bContext) + if(!hat.hasBindContext()) { - hat.association().bContext = bc; + hat.setBindContext(bc); } break; } @@ -152,96 +152,54 @@ void B_UpdateAllDeviceStateAssociations() // relevant states. if(bc->flags & BCF_ACQUIRE_KEYBOARD) { - InputDevice &dev = I_Device(IDEV_KEYBOARD); - - for(int k = 0; k < dev.buttonCount(); ++k) + InputDevice &device = I_Device(IDEV_KEYBOARD); + if(device.isActive()) { - InputDeviceButtonControl &button = dev.button(k); - if(!button.association().bContext) + device.forAllControls([&bc] (InputDeviceControl &control) { - button.association().bContext = bc; - } + if(!control.hasBindContext()) + { + control.setBindContext(bc); + } + return LoopContinue; + }); } } if(bc->flags & BCF_ACQUIRE_ALL) { - for(int k = 0; k < NUM_INPUT_DEVICES; ++k) + I_ForAllDevices([&bc] (InputDevice &device) { - InputDevice *dev = I_DevicePtr(k); - if(!dev || !dev->isActive()) continue; - - for(int m = 0; m < dev->buttonCount(); ++m) - { - InputDeviceButtonControl &button = dev->button(m); - if(!button.association().bContext) - { - button.association().bContext = bc; - } - } - for(int m = 0; m < dev->axisCount(); ++m) - { - InputDeviceAxisControl &axis = dev->axis(m); - if(!axis.association().bContext) - { - axis.association().bContext = bc; - } - } - for(int m = 0; m < dev->hatCount(); ++m) + if(device.isActive()) { - InputDeviceHatControl &hat = dev->hat(m); - if(!hat.association().bContext) + device.forAllControls([&bc] (InputDeviceControl &control) { - hat.association().bContext = bc; - } + if(!control.hasBindContext()) + { + control.setBindContext(bc); + } + return LoopContinue; + }); } - } + return LoopContinue; + }); } } // Now that we know what are the updated context associations, let's check // the devices and see if any of the states need to be expired. - for(int i = 0; i < NUM_INPUT_DEVICES; ++i) + I_ForAllDevices([] (InputDevice &device) { - InputDevice &dev = I_Device(i); - - for(int k = 0; k < dev.buttonCount(); ++k) + device.forAllControls([] (InputDeviceControl &control) { - InputDeviceButtonControl &button = dev.button(k); - inputdevassoc_t &assoc = button.association(); - - if(assoc.bContext != assoc.prevBContext && button.isDown()) - { - // No longer valid. - assoc.flags |= IDAF_EXPIRED; - assoc.flags &= ~IDAF_TRIGGERED; // Not any more. - } - } - - for(int k = 0; k < dev.axisCount(); ++k) - { - InputDeviceAxisControl &axis = dev.axis(k); - inputdevassoc_t &assoc = axis.association(); - - if(assoc.bContext != assoc.prevBContext && axis.position() != 0) + if(!control.inDefaultState()) { - // No longer valid. - assoc.flags |= IDAF_EXPIRED; + control.expireBindContextAssociationIfChanged(); } - } - - for(int k = 0; k < dev.hatCount(); ++k) - { - InputDeviceHatControl &hat = dev.hat(k); - inputdevassoc_t &assoc = hat.association(); - - if(assoc.bContext != assoc.prevBContext && hat.position() >= 0) - { - // No longer valid. - assoc.flags |= IDAF_EXPIRED; - } - } - } + return LoopContinue; + }); + return LoopContinue; + }); } static void B_SetContextCount(int count) diff --git a/doomsday/client/src/ui/b_device.cpp b/doomsday/client/src/ui/b_device.cpp index cd454f25c0..7f3328fde6 100644 --- a/doomsday/client/src/ui/b_device.cpp +++ b/doomsday/client/src/ui/b_device.cpp @@ -25,6 +25,8 @@ #include "ui/b_main.h" #include "ui/b_context.h" +using namespace de; + #define EVTYPE_TO_CBDTYPE(evt) ((evt) == E_AXIS? CBD_AXIS : (evt) == E_TOGGLE? CBD_TOGGLE : CBD_ANGLE) #define CBDTYPE_TO_EVTYPE(cbt) ((cbt) == CBD_AXIS? E_AXIS : (cbt) == CBD_TOGGLE? E_TOGGLE : E_ANGLE) @@ -108,7 +110,7 @@ dd_bool B_ParseDevice(dbinding_t *cb, char const *desc) // Next part defined button, axis, or hat. desc = Str_CopyDelim(str, desc, '-'); - if(!B_ParseJoystickTypeAndId(cb->device, Str_Text(str), &type, &cb->id)) + if(!B_ParseJoystickTypeAndId(I_Device(cb->device), Str_Text(str), &type, &cb->id)) { return false; } @@ -275,27 +277,27 @@ void B_EvaluateDeviceBindingList(int localNum, dbinding_t *listRoot, float *pos, case CBD_TOGGLE: { InputDeviceButtonControl *button = &dev->button(cb->id); - if(controlClass && button->association().bContext != controlClass) + if(controlClass && button->bindContext() != controlClass) continue; // Shadowed by a more important active class. // Expired? - if(button->association().flags & IDAF_EXPIRED) + if(button->bindContextAssociation() & InputDeviceControl::Expired) break; devicePos = (button->isDown() || - (allowTriggered && (button->association().flags & IDAF_TRIGGERED))? 1.0f : 0.0f); + (allowTriggered && (button->bindContextAssociation() & InputDeviceControl::Triggered))? 1.0f : 0.0f); deviceTime = button->time(); // We've checked it, so clear the flag. - button->association().flags &= ~IDAF_TRIGGERED; + button->setBindContextAssociation(InputDeviceControl::Triggered, UnsetFlags); break; } case CBD_AXIS: { InputDeviceAxisControl *axis = &dev->axis(cb->id); - if(controlClass && axis->association().bContext != controlClass) + if(controlClass && axis->bindContext() != controlClass) { - if(!B_FindDeviceBinding(axis->association().bContext, cb->device, CBD_AXIS, cb->id)) + if(!B_FindDeviceBinding(axis->bindContext(), cb->device, CBD_AXIS, cb->id)) { // The overriding context doesn't bind to the axis, though. if(axis->type() == InputDeviceAxisControl::Pointer) @@ -307,8 +309,7 @@ void B_EvaluateDeviceBindingList(int localNum, dbinding_t *listRoot, float *pos, continue; // Shadowed by a more important active class. } - // Expired? - if(axis->association().flags & IDAF_EXPIRED) + if(axis->bindContextAssociation() & InputDeviceControl::Expired) break; if(axis->type() == InputDeviceAxisControl::Pointer) @@ -326,10 +327,10 @@ void B_EvaluateDeviceBindingList(int localNum, dbinding_t *listRoot, float *pos, case CBD_ANGLE: { InputDeviceHatControl *hat = &dev->hat(cb->id); - if(controlClass && hat->association().bContext != controlClass) + if(controlClass && hat->bindContext() != controlClass) continue; // Shadowed by a more important active class. - if(hat->association().flags & IDAF_EXPIRED) + if(hat->bindContextAssociation() & InputDeviceControl::Expired) break; devicePos = (hat->position() == cb->angle? 1.0f : 0.0f); @@ -392,7 +393,7 @@ void B_DeviceBindingToString(dbinding_t const *b, ddstring_t *str) Str_Clear(str); // Name of the device and the key/axis/hat. - B_AppendDeviceDescToString(b->device, CBDTYPE_TO_EVTYPE(b->type), b->id, str); + B_AppendDeviceDescToString(I_Device(b->device), CBDTYPE_TO_EVTYPE(b->type), b->id, str); if(b->type == CBD_ANGLE) { diff --git a/doomsday/client/src/ui/b_util.cpp b/doomsday/client/src/ui/b_util.cpp index 498daf4aca..c3fc768136 100644 --- a/doomsday/client/src/ui/b_util.cpp +++ b/doomsday/client/src/ui/b_util.cpp @@ -152,7 +152,7 @@ dd_bool B_ParseMouseTypeAndId(char const *desc, ddeventtype_t *type, int *id) { *type = E_TOGGLE; *id = strtoul(desc + 6, nullptr, 10) - 1; - if(*id >= 0 && *id < I_Device(IDEV_MOUSE).buttonCount()) + if(I_Device(IDEV_MOUSE).hasButton(*id)) return true; LOG_INPUT_WARNING("Mouse button %i does not exist") << *id; @@ -168,26 +168,25 @@ dd_bool B_ParseMouseTypeAndId(char const *desc, ddeventtype_t *type, int *id) return false; } -dd_bool B_ParseDeviceAxisTypeAndId(int device, char const *desc, ddeventtype_t *type, int *id) +dd_bool B_ParseDeviceAxisTypeAndId(InputDevice const &device, char const *desc, ddeventtype_t *type, int *id) { DENG2_ASSERT(desc && type && id); - InputDevice &dev = I_Device(device); *type = E_AXIS; - *id = dev.toAxisId(desc); + *id = device.toAxisId(desc); if(*id >= 0) return true; - LOG_INPUT_WARNING("Axis \"%s\" is not defined in device '%s'") << desc << dev.name(); + LOG_INPUT_WARNING("Axis \"%s\" is not defined in device '%s'") << desc << device.name(); return false; } -dd_bool B_ParseJoystickTypeAndId(int device, char const *desc, ddeventtype_t *type, int *id) +dd_bool B_ParseJoystickTypeAndId(InputDevice const &device, char const *desc, ddeventtype_t *type, int *id) { if(!strncasecmp(desc, "button", 6) && strlen(desc) > 6) { *type = E_TOGGLE; *id = strtoul(desc + 6, nullptr, 10) - 1; - if(*id >= 0 && *id < I_Device(device).buttonCount()) + if(device.hasButton(*id)) return true; LOG_INPUT_WARNING("Joystick button %i does not exist") << *id; @@ -197,7 +196,7 @@ dd_bool B_ParseJoystickTypeAndId(int device, char const *desc, ddeventtype_t *ty { *type = E_ANGLE; *id = strtoul(desc + 3, nullptr, 10) - 1; - if(*id >= 0 && *id < I_Device(device).hatCount()) + if(device.hasHat(*id)) return true; LOG_INPUT_WARNING("Joystick hat %i does not exist") << *id; @@ -319,7 +318,7 @@ dd_bool B_ParseStateCondition(statecondition_t *cond, char const *desc) // What is being targeted? desc = Str_CopyDelim(str, desc, '-'); ddeventtype_t type; - if(!B_ParseJoystickTypeAndId(cond->device, Str_Text(str), &type, &cond->id)) + if(!B_ParseJoystickTypeAndId(I_Device(cond->device), Str_Text(str), &type, &cond->id)) { return false; } @@ -466,25 +465,23 @@ dd_bool B_EqualConditions(statecondition_t const *a, statecondition_t const *b) a->flags.multiplayer == b->flags.multiplayer); } -void B_AppendDeviceDescToString(int device, ddeventtype_t type, int id, ddstring_t *str) +void B_AppendDeviceDescToString(InputDevice const &device, ddeventtype_t type, int id, ddstring_t *str) { - InputDevice &dev = I_Device(device); - if(type != E_SYMBOLIC) { // Name of the device. - Str_Append(str, dev.name().toUtf8().constData()); + Str_Append(str, device.name().toUtf8().constData()); Str_Append(str, "-"); } switch(type) { case E_TOGGLE: - if(!dev.button(id).name().isEmpty()) + if(!device.button(id).name().isEmpty()) { - Str_Append(str, dev.button(id).name().toUtf8().constData()); + Str_Append(str, device.button(id).name().toUtf8().constData()); } - else if(device == IDEV_KEYBOARD) + else if(&device == I_DevicePtr(IDEV_KEYBOARD)) { char const *name = B_ShortNameForKey(id); if(name) @@ -499,7 +496,7 @@ void B_AppendDeviceDescToString(int device, ddeventtype_t type, int id, ddstring break; case E_AXIS: - Str_Append(str, dev.axis(id).name().toUtf8().constData()); + Str_Append(str, device.axis(id).name().toUtf8().constData()); break; case E_ANGLE: @@ -567,7 +564,7 @@ void B_AppendConditionToString(statecondition_t const *cond, ddstring_t *str) } else { - B_AppendDeviceDescToString(cond->device, + B_AppendDeviceDescToString(I_Device(cond->device), ( cond->type == SCT_TOGGLE_STATE? E_TOGGLE : cond->type == SCT_AXIS_BEYOND ? E_AXIS : E_ANGLE), @@ -598,7 +595,7 @@ void B_AppendEventToString(ddevent_t const *ev, ddstring_t *str) { DENG2_ASSERT(ev); - B_AppendDeviceDescToString(ev->device, ev->type, + B_AppendDeviceDescToString(I_Device(ev->device), ev->type, ( ev->type == E_TOGGLE ? ev->toggle.id : ev->type == E_AXIS ? ev->axis.id : ev->type == E_ANGLE ? ev->angle.id diff --git a/doomsday/client/src/ui/dd_input.cpp b/doomsday/client/src/ui/dd_input.cpp index caff64a795..8601c61701 100644 --- a/doomsday/client/src/ui/dd_input.cpp +++ b/doomsday/client/src/ui/dd_input.cpp @@ -154,45 +154,6 @@ bool InputDeviceAxisControl::isInverted() const return (d->flags & IDA_INVERT) != 0; } -String InputDeviceAxisControl::description() const -{ - QStringList flags; - if(!isActive()) flags << "disabled"; - if(isInverted()) flags << "inverted"; - String flagsAsText = flags.join("|"); - - return String(_E(b) "%1 " _E(.) "(Axis-%2)\n" - //_E(l) "Filter: " _E(.)_E(i) "%3\n" _E(.) - _E(l) "Dead Zone: " _E(.)_E(i) "%3\n" _E(.) - _E(l) "Scale: " _E(.)_E(i) "%4\n" _E(.) - _E(l) "Flags: " _E(.)_E(i) "%5") - .arg(fullName()) - .arg(d->type == Stick? "Stick" : "Pointer") - //.arg(d->filter) - .arg(d->deadZone) - .arg(d->scale) - .arg(flagsAsText); -} - -void InputDeviceAxisControl::reset() -{ - if(d->type == Pointer) - { - // Clear the accumulation. - d->position = 0; - d->sharpPosition = 0; - d->prevSmoothPos = 0; - } - Smoother_Clear(d->smoother); -} - -void InputDeviceAxisControl::clearContextAssociation() -{ - inputdevassoc_t &assoc = association(); - assoc.prevBContext = assoc.bContext; - assoc.bContext = nullptr; -} - void InputDeviceAxisControl::update(timespan_t ticLength) { Smoother_Advance(d->smoother, ticLength); @@ -229,7 +190,7 @@ void InputDeviceAxisControl::update(timespan_t ticLength) } // We can clear the expiration now that an updated value is available. - association().flags &= ~IDAF_EXPIRED; + setBindContextAssociation(Expired, UnsetFlags); } ddouble InputDeviceAxisControl::position() const @@ -324,6 +285,43 @@ duint InputDeviceAxisControl::time() const return d->time; } +String InputDeviceAxisControl::description() const +{ + QStringList flags; + if(!isActive()) flags << "disabled"; + if(isInverted()) flags << "inverted"; + String flagsAsText = flags.join("|"); + + return String(_E(b) "%1 " _E(.) "(Axis-%2)\n" + //_E(l) "Filter: " _E(.)_E(i) "%3\n" _E(.) + _E(l) "Dead Zone: " _E(.)_E(i) "%3\n" _E(.) + _E(l) "Scale: " _E(.)_E(i) "%4\n" _E(.) + _E(l) "Flags: " _E(.)_E(i) "%5") + .arg(fullName()) + .arg(d->type == Stick? "Stick" : "Pointer") + //.arg(d->filter) + .arg(d->deadZone) + .arg(d->scale) + .arg(flagsAsText); +} + +bool InputDeviceAxisControl::inDefaultState() const +{ + return d->position == 0; // Centered? +} + +void InputDeviceAxisControl::reset() +{ + if(d->type == Pointer) + { + // Clear the accumulation. + d->position = 0; + d->sharpPosition = 0; + d->prevSmoothPos = 0; + } + Smoother_Clear(d->smoother); +} + void InputDeviceAxisControl::consoleRegister() { DENG2_ASSERT(hasDevice() && !name().isEmpty()); @@ -370,12 +368,12 @@ void InputDeviceButtonControl::setDown(bool yes) if(_isDown) { // This will get cleared after the state is checked by someone. - association().flags |= IDAF_TRIGGERED; + setBindContextAssociation(Triggered); } else { // We can clear the expiration when the key is released. - association().flags &= ~IDAF_EXPIRED; + setBindContextAssociation(Triggered, UnsetFlags); } } @@ -385,28 +383,25 @@ String InputDeviceButtonControl::description() const return String(_E(b) "%1 " _E(.) "(Button)").arg(fullName()); } +bool InputDeviceButtonControl::inDefaultState() const +{ + return !_isDown; // Not depressed? +} + void InputDeviceButtonControl::reset() { if(_isDown) { - association().flags |= IDAF_EXPIRED; + setBindContextAssociation(Expired); } else { _isDown = false; _time = 0; - association().flags &= ~(IDAF_TRIGGERED | IDAF_EXPIRED); + setBindContextAssociation(Triggered | Expired, UnsetFlags); } } -void InputDeviceButtonControl::clearContextAssociation() -{ - inputdevassoc_t &assoc = association(); - assoc.prevBContext = assoc.bContext; - assoc.bContext = nullptr; - assoc.flags &= ~IDAF_TRIGGERED; -} - duint InputDeviceButtonControl::time() const { return _time; @@ -433,77 +428,114 @@ void InputDeviceHatControl::setPosition(dint newPosition) // We can clear the expiration when centered. if(_pos < 0) { - association().flags &= ~IDAF_EXPIRED; + setBindContextAssociation(Expired, UnsetFlags); } } +duint InputDeviceHatControl::time() const +{ + return _time; +} + String InputDeviceHatControl::description() const { return String(_E(b) "%1 " _E(.) "(Hat)").arg(fullName()); } - -void InputDeviceHatControl::clearContextAssociation() +bool InputDeviceHatControl::inDefaultState() const { - inputdevassoc_t &assoc = association(); - assoc.prevBContext = assoc.bContext; - assoc.bContext = nullptr; + return _pos < 0; // Centered? } -duint InputDeviceHatControl::time() const +// -------------------------------------------------------------------------------- + +DENG2_PIMPL_NOREF(InputDevice::Control) { - return _time; -} + String name; ///< Symbolic + InputDevice *device = nullptr; + BindContextAssociation flags { DefaultFlags }; + bcontext_t *bindContext = nullptr; + bcontext_t *prevBindContext = nullptr; +}; -InputDevice::Control::Control(InputDevice *device) - : _device(device) +InputDevice::Control::Control(InputDevice *device) : d(new Instance) { - de::zap(_assoc); + setDevice(device); } +InputDevice::Control::~Control() +{} + String InputDevice::Control::name() const { - return _name; + return d->name; } void InputDevice::Control::setName(String const &newName) { - _name = newName; + d->name = newName; } String InputDevice::Control::fullName() const { String desc; if(hasDevice()) desc += device().name() + "-"; - desc += (_name.isEmpty()? "" : _name); + desc += (d->name.isEmpty()? "" : d->name); return desc; } InputDevice &InputDevice::Control::device() const { - if(_device) return *_device; + if(d->device) return *d->device; /// @throw MissingDeviceError Missing InputDevice attribution. throw MissingDeviceError("InputDevice::Control::device", "No InputDevice is attributed"); } bool InputDevice::Control::hasDevice() const { - return _device != 0; + return d->device != nullptr; } void InputDevice::Control::setDevice(InputDevice *newDevice) { - _device = newDevice; + d->device = newDevice; +} + +bcontext_t *InputDevice::Control::bindContext() const +{ + return d->bindContext; +} + +void InputDevice::Control::setBindContext(bcontext_t *newContext) +{ + d->bindContext = newContext; +} + +InputDevice::Control::BindContextAssociation InputDevice::Control::bindContextAssociation() const +{ + return d->flags; } -inputdevassoc_t &InputDeviceControl::association() +void InputDevice::Control::setBindContextAssociation(BindContextAssociation const &flagsToChange, FlagOp op) { - return _assoc; + applyFlagOperation(d->flags, flagsToChange, op); } -inputdevassoc_t const &InputDeviceControl::association() const +void InputDevice::Control::clearBindContextAssociation() { - return _assoc; + d->prevBindContext = d->bindContext; + d->bindContext = nullptr; + setBindContextAssociation(Triggered, UnsetFlags); +} + +void InputDevice::Control::expireBindContextAssociationIfChanged() +{ + // No change? + if(d->bindContext == d->prevBindContext) return; + + // No longer valid. + setBindContextAssociation(Expired); + setBindContextAssociation(Triggered, UnsetFlags); // Not any more. } DENG2_PIMPL(InputDevice) @@ -612,14 +644,14 @@ void InputDevice::reset() LOG_AS("InputDevice"); LOG_INPUT_VERBOSE("Reseting %s") << title(); - for(InputDeviceButtonControl *button : d->buttons) - { - button->reset(); - } for(InputDeviceAxisControl *axis : d->axes) { axis->reset(); } + for(InputDeviceButtonControl *button : d->buttons) + { + button->reset(); + } for(InputDeviceHatControl *hat : d->hats) { hat->reset(); @@ -633,20 +665,21 @@ void InputDevice::reset() } } -void InputDevice::clearAllControlContextAssociations() +LoopResult InputDevice::forAllControls(std::function func) { - for(InputDeviceButtonControl *button : d->buttons) + for(Control *axis : d->axes) { - button->clearContextAssociation(); + if(auto result = func(*axis)) return result; } - for(InputDeviceAxisControl *axis : d->axes) + for(Control *button : d->buttons) { - axis->clearContextAssociation(); + if(auto result = func(*button)) return result; } - for(InputDeviceHatControl *hat : d->hats) + for(Control *hat : d->hats) { - hat->clearContextAssociation(); + if(auto result = func(*hat)) return result; } + return LoopContinue; } void InputDevice::consoleRegister() @@ -683,12 +716,14 @@ dint InputDevice::toButtonId(String const &name) const return -1; } +bool InputDevice::hasAxis(de::dint id) const +{ + return (id >= 0 && id < d->axes.count()); +} + InputDeviceAxisControl &InputDevice::axis(dint id) const { - if(id >= 0 && id < d->axes.count()) - { - return *d->axes.at(id); - } + if(hasAxis(id)) return *d->axes.at(id); /// @throw MissingControlError The given id is invalid. throw MissingControlError("InputDevice::axis", "Invalid id:" + String::number(id)); } @@ -705,12 +740,14 @@ int InputDevice::axisCount() const return d->axes.count(); } +bool InputDevice::hasButton(de::dint id) const +{ + return (id >= 0 && id < d->buttons.count()); +} + InputDeviceButtonControl &InputDevice::button(dint id) const { - if(id >= 0 && id < d->buttons.count()) - { - return *d->buttons.at(id); - } + if(hasButton(id)) return *d->buttons.at(id); /// @throw MissingControlError The given id is invalid. throw MissingControlError("InputDevice::button", "Invalid id:" + String::number(id)); } @@ -731,12 +768,14 @@ int InputDevice::buttonCount() const return d->buttons.count(); } +bool InputDevice::hasHat(de::dint id) const +{ + return (id >= 0 && id < d->hats.count()); +} + InputDeviceHatControl &InputDevice::hat(dint id) const { - if(id >= 0 && id < d->hats.count()) - { - return *d->hats.at(id); - } + if(hasHat(id)) return *d->hats.at(id); /// @throw MissingControlError The given id is invalid. throw MissingControlError("InputDevice::hat", "Invalid id:" + String::number(id)); } @@ -952,6 +991,15 @@ InputDevice *I_DevicePtr(int id) return nullptr; } +LoopResult I_ForAllDevices(std::function func) +{ + for(InputDevice *device : devices) + { + if(auto result = func(*device)) return result; + } + return LoopContinue; +} + void I_ResetAllDevices() { for(InputDevice *dev : devices) @@ -1020,7 +1068,11 @@ void I_ClearAllDeviceContextAssociations() { for(InputDevice *dev : devices) { - dev->clearAllControlContextAssociations(); + dev->forAllControls([] (InputDeviceControl &control) + { + control.clearBindContextAssociation(); + return LoopContinue; + }); } } @@ -1322,9 +1374,15 @@ bool I_ConvertEvent(ddevent_t const *ddEvent, event_t *ev) static void updateAllDeviceAxes(timespan_t ticLength) { for(InputDevice *dev : devices) - for(int i = 0; i < dev->axisCount(); ++i) { - dev->axis(i).update(ticLength); + dev->forAllControls([&ticLength] (InputDeviceControl &control) + { + if(auto *axis = control.maybeAs()) + { + axis->update(ticLength); + } + return LoopContinue; + }); } } @@ -1709,11 +1767,10 @@ static void endDrawStateForVisual(Point2Raw const *origin) FR_PopAttrib(); } -void Rend_RenderButtonStateVisual(InputDevice *device, int buttonID, Point2Raw const *_origin, +void Rend_RenderButtonStateVisual(InputDevice &device, int buttonID, Point2Raw const *_origin, RectRaw *geometry) { #define BORDER 4 - DENG2_ASSERT(device); float const upColor[] = { .3f, .3f, .3f, .6f }; float const downColor[] = { .3f, .3f, 1, .6f }; @@ -1726,7 +1783,7 @@ void Rend_RenderButtonStateVisual(InputDevice *device, int buttonID, Point2Raw c geometry->size.width = geometry->size.height = 0; } - InputDeviceButtonControl const &button = device->button(buttonID); + InputDeviceButtonControl const &button = device.button(buttonID); Point2Raw origin; origin.x = _origin? _origin->x : 0; @@ -1742,7 +1799,7 @@ void Rend_RenderButtonStateVisual(InputDevice *device, int buttonID, Point2Raw c // Use the symbolic name. buttonLabel = button.name().toUtf8().constData(); } - else if(device == I_DevicePtr(IDEV_KEYBOARD)) + else if(&device == I_DevicePtr(IDEV_KEYBOARD)) { // Perhaps a printable ASCII character? // Apply all active modifiers to the key. @@ -1788,7 +1845,7 @@ void Rend_RenderButtonStateVisual(InputDevice *device, int buttonID, Point2Raw c glDisable(GL_TEXTURE_2D); // Mark expired? - if(button.association().flags & IDAF_EXPIRED) + if(button.bindContextAssociation() & InputDeviceControl::Expired) { int const markSize = .5f + de::min(textGeom.width(), textGeom.height()) / 3.f; @@ -1801,7 +1858,7 @@ void Rend_RenderButtonStateVisual(InputDevice *device, int buttonID, Point2Raw c } // Mark triggered? - if(button.association().flags & IDAF_TRIGGERED) + if(button.bindContextAssociation() & InputDeviceControl::Triggered) { int const markSize = .5f + de::min(textGeom.width(), textGeom.height()) / 3.f; @@ -1827,36 +1884,32 @@ void Rend_RenderButtonStateVisual(InputDevice *device, int buttonID, Point2Raw c #undef BORDER } -void Rend_RenderAxisStateVisual(InputDevice *device, int /*axisID*/, Point2Raw const *origin, +void Rend_RenderAxisStateVisual(InputDevice & /*device*/, int /*axisID*/, Point2Raw const *origin, RectRaw *geometry) { - DENG2_ASSERT(device); - if(geometry) { geometry->origin.x = geometry->origin.y = 0; geometry->size.width = geometry->size.height = 0; } - //inputdevaxis_t const &axis = device->axis(axisID); + //inputdevaxis_t const &axis = device.axis(axisID); initDrawStateForVisual(origin); endDrawStateForVisual(origin); } -void Rend_RenderHatStateVisual(InputDevice *device, int /*hatID*/, Point2Raw const *origin, +void Rend_RenderHatStateVisual(InputDevice & /*device*/, int /*hatID*/, Point2Raw const *origin, RectRaw *geometry) { - DENG2_ASSERT(device); - if(geometry) { geometry->origin.x = geometry->origin.y = 0; geometry->size.width = geometry->size.height = 0; } - //inputdevhat_t const &hat = device->hat(hatID); + //inputdevhat_t const &hat = device.hat(hatID); initDrawStateForVisual(origin); @@ -1891,7 +1944,7 @@ struct inputdev_layout_t uint numGroups; }; -static void drawControlGroup(InputDevice *device, inputdev_layout_controlgroup_t const *group, +static void drawControlGroup(InputDevice &device, inputdev_layout_controlgroup_t const *group, Point2Raw *_origin, RectRaw *retGeometry) { #define SPACING 2 @@ -1902,7 +1955,7 @@ static void drawControlGroup(InputDevice *device, inputdev_layout_controlgroup_t retGeometry->size.width = retGeometry->size.height = 0; } - if(!device || !group) return; + if(!group) return; Point2Raw origin; origin.x = _origin? _origin->x : 0; @@ -1916,11 +1969,9 @@ static void drawControlGroup(InputDevice *device, inputdev_layout_controlgroup_t switch(ctrl->type) { - case IDC_KEY: Rend_RenderButtonStateVisual(device, ctrl->id, &origin, &ctrlGeom); break; - case IDC_AXIS: Rend_RenderAxisStateVisual(device, ctrl->id, &origin, &ctrlGeom); break; - - case IDC_HAT: Rend_RenderHatStateVisual(device, ctrl->id, &origin, &ctrlGeom); break; + case IDC_KEY: Rend_RenderButtonStateVisual(device, ctrl->id, &origin, &ctrlGeom); break; + case IDC_HAT: Rend_RenderHatStateVisual(device, ctrl->id, &origin, &ctrlGeom); break; default: App_Error("drawControlGroup: Unknown inputdev_controltype_t: %i.", (int)ctrl->type); @@ -1954,7 +2005,7 @@ static void drawControlGroup(InputDevice *device, inputdev_layout_controlgroup_t /** * Render a visual representation of the current state of the specified device. */ -void Rend_RenderInputDeviceStateVisual(InputDevice *device, inputdev_layout_t const *layout, +void Rend_RenderInputDeviceStateVisual(InputDevice &device, inputdev_layout_t const *layout, Point2Raw const *origin, Size2Raw *retVisualDimensions) { #define SPACING 2 @@ -1968,7 +2019,7 @@ void Rend_RenderInputDeviceStateVisual(InputDevice *device, inputdev_layout_t co } if(novideo || isDedicated) return; // Not for us. - if(!device || !layout) return; + if(!layout) return; // Init render state. FR_SetFont(fontFixed); @@ -1982,12 +2033,12 @@ void Rend_RenderInputDeviceStateVisual(InputDevice *device, inputdev_layout_t co Rect *visualGeom = nullptr; // Draw device name first. - if(!device->title().isEmpty()) + if(!device.title().isEmpty()) { Size2Raw size; glEnable(GL_TEXTURE_2D); - Block const fullName(device->title().toUtf8()); + Block const fullName(device.title().toUtf8()); FR_DrawText(fullName.constData(), nullptr/*no offset*/); glDisable(GL_TEXTURE_2D); @@ -2339,19 +2390,19 @@ void Rend_DrawInputDeviceVisuals() if(devRendKeyState) { - Rend_RenderInputDeviceStateVisual(I_DevicePtr(IDEV_KEYBOARD), &keyLayout, &origin, &dimensions); + Rend_RenderInputDeviceStateVisual(I_Device(IDEV_KEYBOARD), &keyLayout, &origin, &dimensions); origin.y += dimensions.height + SPACING; } if(devRendMouseState) { - Rend_RenderInputDeviceStateVisual(I_DevicePtr(IDEV_MOUSE), &mouseLayout, &origin, &dimensions); + Rend_RenderInputDeviceStateVisual(I_Device(IDEV_MOUSE), &mouseLayout, &origin, &dimensions); origin.y += dimensions.height + SPACING; } if(devRendJoyState) { - Rend_RenderInputDeviceStateVisual(I_DevicePtr(IDEV_JOY1), &joyLayout, &origin, &dimensions); + Rend_RenderInputDeviceStateVisual(I_Device(IDEV_JOY1), &joyLayout, &origin, &dimensions); } glMatrixMode(GL_PROJECTION); diff --git a/doomsday/client/src/ui/p_control.cpp b/doomsday/client/src/ui/p_control.cpp index f56009a365..7289626a58 100644 --- a/doomsday/client/src/ui/p_control.cpp +++ b/doomsday/client/src/ui/p_control.cpp @@ -336,9 +336,7 @@ void P_MaintainControlDoubleClicks(int playerNum, int control, float pos) DENG_EXTERN_C int P_IsControlBound(int playerNum, int control) { #ifdef __CLIENT__ - struct bcontext_s* bc = 0; - struct dbinding_s* binds = 0; - playercontrol_t* pc = P_PlayerControlById(control); + playercontrol_t *pc = P_PlayerControlById(control); // Check that this is really a numeric control. DENG_ASSERT(pc); @@ -348,7 +346,8 @@ DENG_EXTERN_C int P_IsControlBound(int playerNum, int control) // Bindings are associated with the ordinal of the local player, not // the actual console number (playerNum) being used. That is why // P_ConsoleToLocal() is called here. - binds = B_GetControlDeviceBindings(P_ConsoleToLocal(playerNum), control, &bc); + bcontext_t *bc = nullptr; + struct dbinding_s *binds = B_GetControlDeviceBindings(P_ConsoleToLocal(playerNum), control, &bc); if(!binds) return false; // There must be bindings to active input devices. @@ -369,28 +368,26 @@ DENG_EXTERN_C int P_IsControlBound(int playerNum, int control) } #undef P_GetControlState -DENG_EXTERN_C void P_GetControlState(int playerNum, int control, float* pos, float* relativeOffset) +DENG_EXTERN_C void P_GetControlState(int playerNum, int control, float *pos, float *relativeOffset) { #ifdef __CLIENT__ - float tmp; - struct bcontext_s* bc = 0; - struct dbinding_s* binds = 0; - int localNum; - playercontrol_t* pc = P_PlayerControlById(control); + playercontrol_t *pc = P_PlayerControlById(control); // Check that this is really a numeric control. DENG_ASSERT(pc); DENG_ASSERT(pc->type == CTLT_NUMERIC || pc->type == CTLT_NUMERIC_TRIGGERED); // Ignore NULLs. + float tmp; if(!pos) pos = &tmp; if(!relativeOffset) relativeOffset = &tmp; // Bindings are associated with the ordinal of the local player, not // the actual console number (playerNum) being used. That is why // P_ConsoleToLocal() is called here. - localNum = P_ConsoleToLocal(playerNum); - binds = B_GetControlDeviceBindings(localNum, control, &bc); + int localNum = P_ConsoleToLocal(playerNum); + bcontext_t *bc = nullptr; + struct dbinding_s *binds = B_GetControlDeviceBindings(localNum, control, &bc); B_EvaluateDeviceBindingList(localNum, binds, pos, relativeOffset, bc, pc->isTriggerable); // Mark for double-clicks.