From 5780aabd0e07fc08a6530ebab39594b3e90d6772 Mon Sep 17 00:00:00 2001 From: danij Date: Sat, 1 Nov 2014 21:28:48 +0000 Subject: [PATCH] InputSystem|Client: InputDevice initialization cleanup --- doomsday/client/include/ui/dd_input.h | 18 +- doomsday/client/src/ui/b_context.cpp | 19 ++- doomsday/client/src/ui/clientwindow.cpp | 7 +- doomsday/client/src/ui/dd_input.cpp | 214 +++++++++++++----------- doomsday/client/src/ui/p_control.cpp | 52 ++---- 5 files changed, 170 insertions(+), 140 deletions(-) diff --git a/doomsday/client/include/ui/dd_input.h b/doomsday/client/include/ui/dd_input.h index 5c73fbf6f4..a8bfad5acb 100644 --- a/doomsday/client/include/ui/dd_input.h +++ b/doomsday/client/include/ui/dd_input.h @@ -299,7 +299,12 @@ class InputDevice */ InputDeviceButtonControl &button(de::dint id) const; - void initButtons(de::dint count); + /** + * Add a @a button control to the input device. + * + * @param button Button control to add. Ownership is given to the device. + */ + void addButton(InputDeviceButtonControl *button); /** * Returns the number of button controls of the device. @@ -320,7 +325,12 @@ class InputDevice */ InputDeviceHatControl &hat(de::dint id) const; - void initHats(de::dint count); + /** + * Add a @a hat control to the input device. + * + * @param hat Hat control to add. Ownership is given to the device. + */ + void addHat(InputDeviceHatControl *hat); /** * Returns the number of hat controls of the device. @@ -586,10 +596,6 @@ void I_InitAllDevices(); */ void I_ShutdownAllDevices(); -void I_ResetAllDevices(); - -void I_ClearAllDeviceContextAssociations(); - /** * Lookup an InputDevice by it's unique @a id. */ diff --git a/doomsday/client/src/ui/b_context.cpp b/doomsday/client/src/ui/b_context.cpp index 7b67717753..2b2393890f 100644 --- a/doomsday/client/src/ui/b_context.cpp +++ b/doomsday/client/src/ui/b_context.cpp @@ -55,9 +55,18 @@ void B_DestroyAllContexts() void B_UpdateAllDeviceStateAssociations() { - I_ClearAllDeviceContextAssociations(); + // Clear all existing associations. + I_ForAllDevices([] (InputDevice &device) + { + device.forAllControls([] (InputDeviceControl &control) + { + control.clearBindContextAssociation(); + return LoopContinue; + }); + return LoopContinue; + }); - // We need to iterate through all the device bindings in all context. + // We need to iterate through all the device bindings in all contexts. for(int i = 0; i < bindContextCount; ++i) { bcontext_t *bc = bindContexts[i]; @@ -279,7 +288,11 @@ void B_ActivateContext(bcontext_t *bc, dd_bool doActivate) if(bc->flags & BCF_ACQUIRE_ALL) { - I_ResetAllDevices(); + I_ForAllDevices([] (InputDevice &device) + { + device.reset(); + return LoopContinue; + }); } } diff --git a/doomsday/client/src/ui/clientwindow.cpp b/doomsday/client/src/ui/clientwindow.cpp index 7c38e6c987..ec44dcdee4 100644 --- a/doomsday/client/src/ui/clientwindow.cpp +++ b/doomsday/client/src/ui/clientwindow.cpp @@ -454,7 +454,12 @@ DENG2_PIMPL(ClientWindow) if(!hasFocus) { I_ClearEvents(); - I_ResetAllDevices(); + I_ForAllDevices([] (InputDevice &device) + { + device.reset(); + return LoopContinue; + }); + canvas.trapMouse(false); } else if(self.isFullScreen() && !taskBar->isOpen()) diff --git a/doomsday/client/src/ui/dd_input.cpp b/doomsday/client/src/ui/dd_input.cpp index 8601c61701..21eb869c59 100644 --- a/doomsday/client/src/ui/dd_input.cpp +++ b/doomsday/client/src/ui/dd_input.cpp @@ -752,15 +752,11 @@ InputDeviceButtonControl &InputDevice::button(dint id) const throw MissingControlError("InputDevice::button", "Invalid id:" + String::number(id)); } -void InputDevice::initButtons(int count) +void InputDevice::addButton(InputDeviceButtonControl *button) { - DENG2_ASSERT(d->buttons.isEmpty()); - for(int i = 0; i < count; ++i) - { - auto *button = new InputDeviceButtonControl; - d->buttons.append(button); - button->setDevice(this); - } + if(!button) return; + d->buttons.append(button); + button->setDevice(this); } int InputDevice::buttonCount() const @@ -780,15 +776,11 @@ InputDeviceHatControl &InputDevice::hat(dint id) const throw MissingControlError("InputDevice::hat", "Invalid id:" + String::number(id)); } -void InputDevice::initHats(int count) +void InputDevice::addHat(InputDeviceHatControl *hat) { - DENG2_ASSERT(d->hats.isEmpty()); - for(int i = 0; i < count; ++i) - { - auto *hat = new InputDeviceHatControl; - d->hats.append(hat); - hat->setDevice(this); - } + if(!hat) return; + d->hats.append(hat); + hat->setDevice(this); } int InputDevice::hatCount() const @@ -866,24 +858,31 @@ static byte devRendMouseState; ///< cvar static byte devRendJoyState; ///< cvar #endif -void I_InitAllDevices() +static InputDevice *makeKeyboard(String const &name, String const &title = "") { - // Allow re-init. - I_ShutdownAllDevices(); + InputDevice *keyboard = new InputDevice(name); + + keyboard->setTitle(title); + + // DDKEYs are used as button indices. + for(int i = 0; i < 256; ++i) + { + keyboard->addButton(new InputDeviceButtonControl); + } + + return keyboard; +} + +static InputDevice *makeMouse(String const &name, String const &title = "") +{ + InputDevice *mouse = new InputDevice(name); - // The keyboard is always assumed to be present. - // DDKEYs are used as key indices. - InputDevice *keyboard; - devices.append(keyboard = new InputDevice("key")); - keyboard->activate(); - keyboard->setTitle("Keyboard"); - keyboard->initButtons(256); + mouse->setTitle(title); - // The mouse may not be active. - InputDevice *mouse; - devices.append(mouse = new InputDevice("mouse")); - mouse->setTitle("Mouse"); - mouse->initButtons(IMB_MAXBUTTONS); + for(int i = 0; i < IMB_MAXBUTTONS; ++i) + { + mouse->addButton(new InputDeviceButtonControl); + } // Some of the mouse buttons have symbolic names. mouse->button(IMB_LEFT ).setName("left"); @@ -905,65 +904,112 @@ void I_InitAllDevices() //axis->setFilter(1); // On by default. axis->setScale(1.f/1000); - // Register console variables for the axis settings. - mouse->consoleRegister(); + return mouse; +} - if(Mouse_IsPresent()) - mouse->activate(); +static InputDevice *makeJoystick(String const &name, String const &title = "") +{ + InputDevice *joy = new InputDevice(name); - // TODO: Add support for several joysticks. + joy->setTitle(title); + + for(int i = 0; i < IJOY_MAXBUTTONS; ++i) { - InputDevice *joy; - devices.append(joy = new InputDevice("joy")); - joy->setTitle("Joystick"); - joy->initButtons(IJOY_MAXBUTTONS); + joy->addButton(new InputDeviceButtonControl); + } - for(int i = 0; i < IJOY_MAXAXES; ++i) + for(int i = 0; i < IJOY_MAXAXES; ++i) + { + char name[32]; + if(i < 4) { - char name[32]; - if(i < 4) - { - strcpy(name, i == 0? "x" : i == 1? "y" : i == 2? "z" : "w"); - } - else - { - sprintf(name, "axis%02i", i + 1); - } - joy->addAxis(axis = new InputDeviceAxisControl(name, InputDeviceAxisControl::Stick)); - axis->setScale(1.0f / IJOY_AXISMAX); - axis->setDeadZone(DEFAULT_JOYSTICK_DEADZONE); + strcpy(name, i == 0? "x" : i == 1? "y" : i == 2? "z" : "w"); } + else + { + sprintf(name, "axis%02i", i + 1); + } + auto *axis = new InputDeviceAxisControl(name, InputDeviceAxisControl::Stick); + joy->addAxis(axis); + axis->setScale(1.0f / IJOY_AXISMAX); + axis->setDeadZone(DEFAULT_JOYSTICK_DEADZONE); + } - // Register console variables for the axis settings. - joy->consoleRegister(); + for(int i = 0; i < IJOY_MAXHATS; ++i) + { + joy->addHat(new InputDeviceHatControl); + } - joy->initHats(IJOY_MAXHATS); + return joy; +} - // The joystick may not be active. - if(Joystick_IsPresent()) - joy->activate(); +static InputDevice *makeHeadTracker(String const &name, String const &title) +{ + InputDevice *head = new InputDevice(name); - devices.append(new InputDevice("joy2")); - devices.append(new InputDevice("joy3")); - devices.append(new InputDevice("joy4")); - } + head->setTitle(title); + + auto *axis = new InputDeviceAxisControl("yaw", InputDeviceAxisControl::Stick); + head->addAxis(axis); + axis->setRawInput(); + + head->addAxis(axis = new InputDeviceAxisControl("pitch", InputDeviceAxisControl::Stick)); + axis->setRawInput(); - // Set up a head tracking device. + head->addAxis(axis = new InputDeviceAxisControl("roll", InputDeviceAxisControl::Stick)); + axis->setRawInput(); + + return head; +} + +/** + * @param device InputDevice to add. + * @return Same as @a device for caller convenience. + */ +static InputDevice *addDevice(InputDevice *device) +{ + if(device) { - InputDevice *head; - devices.append(head = new InputDevice("head")); - head->setTitle("Head Tracker"); + if(!devices.contains(device)) + { + // Ensure the name is unique. + for(InputDevice *otherDevice : devices) + { + if(!otherDevice->name().compareWithoutCase(device->name())) + { + throw Error("InputSystem::addInputDevice", "Multiple devices with name:" + device->name() + " cannot coexist"); + } + } + + // Add this device to the collection. + devices.append(device); + } + } + return device; +} + +void I_InitAllDevices() +{ + // Allow re-init. + I_ShutdownAllDevices(); - head->addAxis(axis = new InputDeviceAxisControl("yaw", InputDeviceAxisControl::Stick)); - axis->setRawInput(); + addDevice(makeKeyboard("key", "Keyboard"))->activate(); // A keyboard is assumed to always be present. - head->addAxis(axis = new InputDeviceAxisControl("pitch", InputDeviceAxisControl::Stick)); - axis->setRawInput(); + addDevice(makeMouse("mouse", "Mouse"))->activate(Mouse_IsPresent()); // A mouse may not be present. - head->addAxis(axis = new InputDeviceAxisControl("roll", InputDeviceAxisControl::Stick)); - axis->setRawInput(); + addDevice(makeJoystick("joy", "Joystick"))->activate(Joystick_IsPresent()); // A joystick may not be present. - head->consoleRegister(); + /// @todo: Add support for multiple joysticks (just some generics, for now). + addDevice(new InputDevice("joy2")); + addDevice(new InputDevice("joy3")); + addDevice(new InputDevice("joy4")); + + addDevice(makeHeadTracker("head", "Head Tracker")); // Head trackers are activated later. + + // Register console variables for the controls of all devices. + for(InputDevice *device : devices) + { + device->consoleRegister(); } } @@ -1000,14 +1046,6 @@ LoopResult I_ForAllDevices(std::function func) return LoopContinue; } -void I_ResetAllDevices() -{ - for(InputDevice *dev : devices) - { - dev->reset(); - } -} - bool I_ShiftDown() { return shiftDown; @@ -1064,18 +1102,6 @@ void I_TrackInput(ddevent_t *ev) } } -void I_ClearAllDeviceContextAssociations() -{ - for(InputDevice *dev : devices) - { - dev->forAllControls([] (InputDeviceControl &control) - { - control.clearBindContextAssociation(); - return LoopContinue; - }); - } -} - #if 0 static int DD_KeyOrCode(char *token) { diff --git a/doomsday/client/src/ui/p_control.cpp b/doomsday/client/src/ui/p_control.cpp index 7289626a58..520481b9bf 100644 --- a/doomsday/client/src/ui/p_control.cpp +++ b/doomsday/client/src/ui/p_control.cpp @@ -1,7 +1,7 @@ -/** @file +/** @file p_control.cpp Player Controls. * * @authors Copyright © 2003-2013 Jaakko Keränen - * @authors Copyright © 2006-2013 Daniel Swanson + * @authors Copyright © 2006-2014 Daniel Swanson * * @par License * GPL: http://www.gnu.org/licenses/gpl.html @@ -17,12 +17,6 @@ * http://www.gnu.org/licenses */ -/** - * Player Controls. - */ - -// HEADER FILES ------------------------------------------------------------ - #ifdef WIN32_MSVC # pragma warning (disable:4100) // lots of unused arguments #endif @@ -45,7 +39,7 @@ #endif #include "ui/p_control.h" -// MACROS ------------------------------------------------------------------ +using namespace de; /* // Number of triggered impulses buffered into each player's control state @@ -55,7 +49,6 @@ #define SLOW_TURN_TIME (6.0f / 35) */ -// TYPES ------------------------------------------------------------------- /** * The control descriptors contain a mapping between symbolic control @@ -112,19 +105,10 @@ typedef struct controlcounter_s { doubleclick_t doubleClicks[DDMAXPLAYERS]; } controlcounter_t; -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - D_CMD(ListPlayerControls); D_CMD(ClearControlAccumulation); D_CMD(Impulse); -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- /* // Control class names - [singular, plural]. const char *ctlClassNames[NUM_CONTROL_CLASSES][NUM_CONTROL_CLASSES] = { @@ -133,15 +117,11 @@ const char *ctlClassNames[NUM_CONTROL_CLASSES][NUM_CONTROL_CLASSES] = { {{"Impulse"}, {"Impulses"}} };*/ -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - static playercontrol_t* playerControls; static controlcounter_t** controlCounts; static int playerControlCount; static int doubleClickThresholdMilliseconds = 300; -// CODE -------------------------------------------------------------------- - static playercontrol_t* P_AllocPlayerControl(void) { playerControls = (playercontrol_t *) M_Realloc(playerControls, sizeof(playercontrol_t) * @@ -294,7 +274,7 @@ void P_MaintainControlDoubleClicks(int playerNum, int control, float pos) if(newState == db->previousClickState && nowTime - db->previousClickTime < (uint) MAX_OF(0, doubleClickThresholdMilliseconds)) { - Str *symbolicName = Str_NewStd(); + ddstring_s *symbolicName = Str_NewStd(); db->triggered = true; @@ -476,10 +456,9 @@ DENG_EXTERN_C void P_Impulse(int playerNum, int control) #endif } -void P_ImpulseByName(int playerNum, const char* control) +void P_ImpulseByName(int playerNum, char const *control) { - playercontrol_t* pc = P_PlayerControlByName(control); - if(pc) + if(playercontrol_t *pc = P_PlayerControlByName(control)) { P_Impulse(playerNum, pc->id); } @@ -488,26 +467,27 @@ void P_ImpulseByName(int playerNum, const char* control) void P_ControlTicker(timespan_t time) { // Check for triggered double-clicks, and generate the appropriate impulses. - } #ifdef __CLIENT__ D_CMD(ClearControlAccumulation) { - int i, p; - playercontrol_t* pc; - - I_ResetAllDevices(); + I_ForAllDevices([] (InputDevice &device) + { + device.reset(); + return LoopContinue; + }); - for(i = 0; i < playerControlCount; ++i) + for(int i = 0; i < playerControlCount; ++i) { - pc = &playerControls[i]; - for(p = 0; p < DDMAXPLAYERS; ++p) + playercontrol_t *pc = &playerControls[i]; + for(int p = 0; p < DDMAXPLAYERS; ++p) { if(pc->type == CTLT_NUMERIC) - P_GetControlState(p, pc->id, NULL, NULL); + P_GetControlState(p, pc->id, nullptr, nullptr); else if(pc->type == CTLT_IMPULSE) P_GetImpulseControlState(p, pc->id); + // Also clear the double click state. P_GetControlDoubleClick(p, pc->id); }