From 04e3caed3792ff6d1e3fbce5b149a7d5ea7a1808 Mon Sep 17 00:00:00 2001 From: danij Date: Tue, 14 Feb 2012 09:16:58 +0000 Subject: [PATCH] Added virtual input device state visuals for debugging controls Presently these visuals are only available in _DEBUG builds. Enable them using the following cvars: rend-dev-input-joy-state rend-dev-input-key-state rend-dev-input-mouse-state The keyboard visual employs the standard American English key layout to match the engine's assumed key layout on Windows. The other visuals simply list the controls in a logical order. Todo for later: Extend these visuals so they can be used by users in an interactive control setup UI within the engine. Todo for later: Implement a drawer for axis and hat controls. --- doomsday/engine/portable/include/b_main.h | 8 +- doomsday/engine/portable/include/dd_input.h | 99 ++- doomsday/engine/portable/src/b_main.c | 17 +- doomsday/engine/portable/src/dd_input.c | 791 ++++++++++++++++++-- doomsday/engine/portable/src/net_main.c | 3 + 5 files changed, 837 insertions(+), 81 deletions(-) diff --git a/doomsday/engine/portable/include/b_main.h b/doomsday/engine/portable/include/b_main.h index 11b19c343a..912a88dc92 100644 --- a/doomsday/engine/portable/include/b_main.h +++ b/doomsday/engine/portable/include/b_main.h @@ -48,9 +48,13 @@ struct dbinding_s* B_BindControl(const char* controlDesc, const char* device); struct dbinding_s* B_GetControlDeviceBindings(int localNum, int control, struct bcontext_s** bContext); // Utils -/// \todo: move to b_util.h +/// @todo: move to b_util.h int B_NewIdentifier(void); + +const char* B_ShortNameForKey2(int ddKey, boolean forceLowercase); const char* B_ShortNameForKey(int ddkey); + int B_KeyForShortName(const char* key); + int DD_GetKeyCode(const char* key); -#endif /* LIBDENG_BIND_MAIN_H */ +#endif /// LIBDENG_BIND_MAIN_H diff --git a/doomsday/engine/portable/include/dd_input.h b/doomsday/engine/portable/include/dd_input.h index 8c5137ce3a..42f0556524 100644 --- a/doomsday/engine/portable/include/dd_input.h +++ b/doomsday/engine/portable/include/dd_input.h @@ -31,6 +31,10 @@ #define NUMKKEYS 256 +#if _DEBUG +# include "point.h" // For the debug visual. +#endif + // Input devices. enum { @@ -43,6 +47,14 @@ enum NUM_INPUT_DEVICES // Theoretical maximum. }; +// Input device control types +typedef enum { + IDC_KEY, + IDC_AXIS, + IDC_HAT, + NUM_INPUT_DEVICE_CONTROL_TYPES +} inputdev_controltype_t; + typedef enum ddeventtype_e { E_TOGGLE, // Two-state device E_AXIS, // Axis position @@ -153,6 +165,7 @@ typedef struct inputdevhat_s { #define ID_ACTIVE 0x1 // The input device is active. typedef struct inputdev_s { + char niceName[40]; // Human-friendly name of the device. char name[20]; // Symbolic name of the device. int flags; uint numAxes; // Number of axes in this input device. @@ -196,15 +209,85 @@ void I_InitVirtualInputDevices(void); void I_ShutdownInputDevices(void); void I_ClearDeviceContextAssociations(void); void I_DeviceReset(uint ident); -inputdev_t *I_GetDevice(uint ident, boolean ifactive); -inputdev_t *I_GetDeviceByName(const char *name, boolean ifactive); -boolean I_ParseDeviceAxis(const char* str, uint* deviceID, uint* axis); -inputdevaxis_t *I_GetAxisByID(inputdev_t *device, uint id); -int I_GetAxisByName(inputdev_t *device, const char *name); -int I_GetKeyByName(inputdev_t* device, const char* name); -float I_TransformAxis(inputdev_t* dev, uint axis, float rawPos); -boolean I_IsDeviceKeyDown(uint ident, uint code); + +inputdev_t* I_GetDevice(uint ident, boolean ifactive); +inputdev_t* I_GetDeviceByName(const char* name, boolean ifactive); + +float I_TransformAxis(inputdev_t* dev, uint axis, float rawPos); + +/** + * Check through the axes registered for the given device, see if there is + * one identified by the given name. + * + * @return @c false, if the string is invalid. + */ +boolean I_ParseDeviceAxis(const char* str, uint* deviceID, uint* axis); + +/** + * Retrieve the index of a device's axis by name. + * + * @param device Ptr to input device info, to get the axis index from. + * @param name Ptr to string containing the name to be searched for. + * + * @return Index of the device axis named; or -1, if not found. + */ +int I_GetAxisByName(inputdev_t* device, const char* name); + +/** + * Retrieve a ptr to the device axis specified by id. + * + * @param device Ptr to input device info, to get the axis ptr from. + * @param id Axis index, to search for. + * + * @return Ptr to the device axis OR @c NULL, if not found. + */ +inputdevaxis_t* I_GetAxisByID(inputdev_t* device, uint id); + +/** + * Retrieve the index of a device's key by name. + * + * @param device Ptr to input device info, to get the key index from. + * @param name Ptr to string containing the name to be searched for. + * + * @return Index of the device key named; or -1, if not found. + */ +int I_GetKeyByName(inputdev_t* device, const char* name); + +/** + * Retrieve a ptr to the device key specified by id. + * + * @param device Ptr to input device info, to get the key ptr from. + * @param id Key index, to search for. + * + * @return Ptr to the device key OR @c NULL, if not found. + */ +inputdevkey_t* I_GetKeyByID(inputdev_t* device, uint id); + +/** + * @return The key state from the downKeys array. + */ +boolean I_IsKeyDown(inputdev_t* device, uint id); + +/** + * Retrieve a ptr to the device hat specified by id. + * + * @param device Ptr to input device info, to get the hat ptr from. + * @param id Hat index, to search for. + * + * @return Ptr to the device hat OR @c NULL, if not found. + */ +inputdevhat_t* I_GetHatByID(inputdev_t* device, uint id); + void I_SetUIMouseMode(boolean on); void I_TrackInput(ddevent_t *ev, timespan_t ticLength); +#if _DEBUG +/** + * Render a visual representation of the current state of all input devices. + */ +void Rend_AllInputDeviceStateVisuals(void); +#else +# define Rend_AllInputDeviceStateVisuals +#endif + #endif /* LIBDENG_CORE_INPUT_H */ diff --git a/doomsday/engine/portable/src/b_main.c b/doomsday/engine/portable/src/b_main.c index 60b36af973..def4cc0200 100644 --- a/doomsday/engine/portable/src/b_main.c +++ b/doomsday/engine/portable/src/b_main.c @@ -1091,21 +1091,21 @@ binding_t *B_Bind(ddevent_t *ev, char *command, int control, uint bindContext) } #endif -const char *B_ShortNameForKey(int ddkey) +const char* B_ShortNameForKey2(int ddKey, boolean forceLowercase) { - uint idx; static char nameBuffer[40]; + uint idx; for(idx = 0; keyNames[idx].key; ++idx) { - if(ddkey == keyNames[idx].key) + if(ddKey == keyNames[idx].key) return keyNames[idx].name; } - if(isalnum(ddkey)) + if(isalnum(ddKey)) { // Printable character, fabricate a single-character name. - nameBuffer[0] = tolower(ddkey); + nameBuffer[0] = forceLowercase? tolower(ddKey) : ddKey; nameBuffer[1] = 0; return nameBuffer; } @@ -1113,6 +1113,11 @@ const char *B_ShortNameForKey(int ddkey) return NULL; } +const char* B_ShortNameForKey(int ddKey) +{ + return B_ShortNameForKey2(ddKey, true/*force lowercase*/); +} + int B_KeyForShortName(const char *key) { uint idx; @@ -1449,7 +1454,7 @@ static void queEventsForHeldControls(uint deviceID, uint classID) // being pressed that have a binding in the context being // enabled/disabled (classID) if(!(com->command[EVS_DOWN] != NULL && bind->controlID >= 0 && - I_IsDeviceKeyDown(deviceID, (uint) bind->controlID))) + I_IsKeyDown(dev, (uint) bind->controlID))) continue; break; diff --git a/doomsday/engine/portable/src/dd_input.c b/doomsday/engine/portable/src/dd_input.c index 59b57c18e0..549399b4aa 100644 --- a/doomsday/engine/portable/src/dd_input.c +++ b/doomsday/engine/portable/src/dd_input.c @@ -37,10 +37,16 @@ #include "de_infine.h" #include "de_system.h" #include "de_misc.h" -#include "de_ui.h" + +// For the debug visuals: +#if _DEBUG +# include "de_graphics.h" +# include "de_refresh.h" +# include "de_render.h" +# include "de_ui.h" +#endif #include "con_busy.h" -#include "gl_main.h" // MACROS ------------------------------------------------------------------ @@ -125,7 +131,14 @@ static repeater_t keyReps[MAX_DOWNKEYS]; static float oldPOV = IJOY_POV_CENTER; static char* eventStrings[MAXEVENTS]; static boolean uiMouseMode = false; // Can mouse data be modified? -static byte useSharpToggleEvents = true; + +static byte useSharpToggleEvents = true; ///< cvar + +#if _DEBUG +static byte devRendKeyState = false; ///< cvar +static byte devRendMouseState = false; ///< cvar +static byte devRendJoyState = false; ///< cvar +#endif // CODE -------------------------------------------------------------------- @@ -139,6 +152,12 @@ void DD_RegisterInput(void) C_VAR_INT("input-mouse-filter", &mouseFilter, 0, 0, MAX_AXIS_FILTER - 1); C_VAR_INT("input-mouse-frequency", &mouseFreq, CVF_NO_MAX, 0, 0); +#if _DEBUG + C_VAR_BYTE("rend-dev-input-joy-state", &devRendJoyState, CVF_NO_ARCHIVE, 0, 1); + C_VAR_BYTE("rend-dev-input-key-state", &devRendKeyState, CVF_NO_ARCHIVE, 0, 1); + C_VAR_BYTE("rend-dev-input-mouse-state", &devRendMouseState, CVF_NO_ARCHIVE, 0, 1); +#endif + // Ccmds #if 0 C_CMD("dumpkeymap", "s", DumpKeyMap); @@ -211,11 +230,13 @@ void I_InitVirtualInputDevices(void) // DDKEYs are used as key indices. dev = &inputDevices[IDEV_KEYBOARD]; dev->flags = ID_ACTIVE; + strcpy(dev->niceName, "Keyboard"); strcpy(dev->name, "key"); I_DeviceAllocKeys(dev, 256); // The mouse may not be active. dev = &inputDevices[IDEV_MOUSE]; + strcpy(dev->niceName, "Mouse"); strcpy(dev->name, "mouse"); I_DeviceAllocKeys(dev, IMB_MAXBUTTONS); @@ -248,6 +269,7 @@ void I_InitVirtualInputDevices(void) // TODO: Add support for several joysticks. dev = &inputDevices[IDEV_JOY1]; + strcpy(dev->niceName, "Joystick"); strcpy(dev->name, "joy"); I_DeviceAllocKeys(dev, IJOY_MAXBUTTONS); @@ -399,35 +421,16 @@ inputdev_t *I_GetDeviceByName(const char *name, boolean ifactive) return dev; } -/** - * Retrieve a ptr to the device axis specified by id. - * - * @param device Ptr to input device info, to get the axis ptr from. - * @param id Axis index, to search for. - * - * @return Ptr to the device axis OR @c NULL, if not - * found. - */ -inputdevaxis_t *I_GetAxisByID(inputdev_t *device, uint id) +inputdevaxis_t* I_GetAxisByID(inputdev_t* device, uint id) { - if(!device || id > device->numAxes - 1) + if(!device || id == 0 || id > device->numAxes - 1) return NULL; - return &device->axes[id-1]; } -/** - * Retrieve the index of a device's axis by name. - * - * @param device Ptr to input device info, to get the axis index from. - * @param name Ptr to string containing the name to be searched for. - * - * @return Index of the device axis named; or -1, if not found. - */ -int I_GetAxisByName(inputdev_t *device, const char *name) +int I_GetAxisByName(inputdev_t* device, const char* name) { - uint i; - + uint i; for(i = 0; i < device->numAxes; ++i) { if(!stricmp(device->axes[i].name, name)) @@ -436,10 +439,16 @@ int I_GetAxisByName(inputdev_t *device, const char *name) return -1; } -int I_GetKeyByName(inputdev_t* device, const char* name) +inputdevkey_t* I_GetKeyByID(inputdev_t* device, uint id) { - int i; + if(!device || id == 0 || id > device->numKeys - 1) + return NULL; + return &device->keys[id-1]; +} +int I_GetKeyByName(inputdev_t* device, const char* name) +{ + int i; for(i = 0; i < (int)device->numKeys; ++i) { if(device->keys[i].name && !stricmp(device->keys[i].name, name)) @@ -448,12 +457,13 @@ int I_GetKeyByName(inputdev_t* device, const char* name) return -1; } -/** - * Check through the axes registered for the given device, see if there is - * one identified by the given name. - * - * @return @c false, if the string is invalid. - */ +inputdevhat_t* I_GetHatByID(inputdev_t* device, uint id) +{ + if(!device || id == 0 || id > device->numHats - 1) + return NULL; + return &device->hats[id-1]; +} + boolean I_ParseDeviceAxis(const char* str, uint* deviceID, uint* axis) { char name[30], *ptr; @@ -640,8 +650,8 @@ void I_TrackInput(ddevent_t *ev, timespan_t ticLength) void I_ClearDeviceContextAssociations(void) { - uint i, j; - inputdev_t *dev; + inputdev_t* dev; + uint i, j; for(i = 0; i < NUM_INPUT_DEVICES; ++i) { @@ -668,30 +678,21 @@ void I_ClearDeviceContextAssociations(void) } } -/** - * @return The key state from the downKeys array. - */ -boolean I_IsDeviceKeyDown(uint ident, uint code) +boolean I_IsKeyDown(inputdev_t* dev, uint id) { - inputdev_t *dev; - - if((dev = I_GetDevice(ident, true)) != NULL) + if(dev && id >= 0 && id < dev->numKeys) { - if(code >= dev->numKeys) - return false; - - return dev->keys[code].isDown; + return dev->keys[id].isDown; } - return false; } /** - * @return Either key number or the scan code for the given token. + * @return Either key number or the scan code for the given token. */ -int DD_KeyOrCode(char *token) +int DD_KeyOrCode(char* token) { - char *end = M_FindWhite(token); + char* end = M_FindWhite(token); if(end - token > 1) { @@ -1448,7 +1449,668 @@ void DD_ReadJoystick(void) } } -static void I_PrintAxisConfig(inputdev_t *device, inputdevaxis_t *axis) +#if _DEBUG +static void initDrawStateForVisual(const Point2Raw* origin) +{ + FR_PushAttrib(); + + // Ignore zero offsets. + if(origin && !(origin->x == 0 && origin->y == 0)) + { + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glTranslatef(origin->x, origin->y, 0); + } +} + +static void endDrawStateForVisual(const Point2Raw* origin) +{ + // Ignore zero offsets. + if(origin && !(origin->x == 0 && origin->y == 0)) + { + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + } + + FR_PopAttrib(); +} + +void Rend_RenderKeyStateVisual(inputdev_t* device, uint keyID, const Point2Raw* _origin, + RectRaw* geometry) +{ +#define BORDER 4 + + const Point2Raw textOffset = { BORDER, BORDER }; + const float upColor[] = { .3f, .3f, .3f, .6f }; + const float downColor[] = { .3f, .3f, 1, .6f }; + const float expiredMarkColor[] = { 1, 0, 0, 1 }; + const char* keyLabel = NULL; + const inputdevkey_t* key; + char keyLabelBuf[2]; + Point2Raw origin; + RectRaw textGeom; + ddstring_t label; + + if(geometry) + { + geometry->origin.x = geometry->origin.y = 0; + geometry->size.width = geometry->size.height = 0; + } + + key = I_GetKeyByID(device, keyID+1); + if(!key) return; + + origin.x = _origin? _origin->x : 0; + origin.y = _origin? _origin->y : 0; + + Str_Init(&label); + + // Compose the key label. + if(key->name) + { + // Use the symbolic name. + keyLabel = key->name; + } + else if(device == I_GetDevice(IDEV_KEYBOARD, false)) + { + // Perhaps a printable ASCII character? + // Apply all active modifiers to the key. + byte asciiCode = DD_ModKey((byte)keyID); + if(asciiCode > 32 && asciiCode < 127) + { + keyLabelBuf[0] = asciiCode; + keyLabelBuf[1] = '\0'; + keyLabel = keyLabelBuf; + } + + // Is there symbolic name in the bindings system? + if(!keyLabel) + { + keyLabel = B_ShortNameForKey2(keyID, false/*do not force lowercase*/); + } + } + + if(keyLabel) + Str_Append(&label, keyLabel); + else + Str_Appendf(&label, "#%03u", keyID+1); + + initDrawStateForVisual(&origin); + + // Calculate the size of the visual according to the dimensions of the text. + textGeom.origin.x = textGeom.origin.y = 0; + FR_TextSize(&textGeom.size, Str_Text(&label)); + + // Enlarge by BORDER pixels. + textGeom.size.width += BORDER * 2; + textGeom.size.height += BORDER * 2; + + // Draw a background. + glColor4fv(key->isDown? downColor : upColor); + GL_DrawRect(&textGeom); + + // Draw the text. + glEnable(GL_TEXTURE_2D); + FR_DrawText(Str_Text(&label), &textOffset); + glDisable(GL_TEXTURE_2D); + + // Mark expired? + if(key->assoc.flags & IDAF_EXPIRED) + { + const int markSize = .5f + MIN_OF(textGeom.size.width, textGeom.size.height) / 3.f; + + glColor3fv(expiredMarkColor); + glBegin(GL_TRIANGLES); + glVertex2i(textGeom.size.width, 0); + glVertex2i(textGeom.size.width, markSize); + glVertex2i(textGeom.size.width-markSize, 0); + glEnd(); + } + + endDrawStateForVisual(&origin); + + Str_Free(&label); + + if(geometry) + { + memcpy(&geometry->origin, &origin, sizeof(geometry->origin)); + memcpy(&geometry->size, &textGeom.size, sizeof(geometry->size)); + } + +#undef BORDER +} + +void Rend_RenderAxisStateVisual(inputdev_t* device, uint axisID, const Point2Raw* origin, + RectRaw* geometry) +{ + const inputdevaxis_t* axis; + + if(geometry) + { + geometry->origin.x = geometry->origin.y = 0; + geometry->size.width = geometry->size.height = 0; + } + + axis = I_GetAxisByID(device, axisID+1); + if(!axis) return; + + initDrawStateForVisual(origin); + + endDrawStateForVisual(origin); +} + +void Rend_RenderHatStateVisual(inputdev_t* device, uint hatID, const Point2Raw* origin, + RectRaw* geometry) +{ + const inputdevhat_t* hat; + + if(geometry) + { + geometry->origin.x = geometry->origin.y = 0; + geometry->size.width = geometry->size.height = 0; + } + + hat = I_GetHatByID(device, hatID+1); + if(!hat) return; + + initDrawStateForVisual(origin); + + endDrawStateForVisual(origin); +} + +typedef struct { + inputdev_controltype_t type; + uint id; +} inputdev_layout_control_t; + +typedef struct { + inputdev_layout_control_t* controls; + uint numControls; +} inputdev_layout_controlgroup_t; + +// Defines the order of controls in the visual. +typedef struct { + inputdev_layout_controlgroup_t* groups; + uint numGroups; +} inputdev_layout_t; + +static void drawControlGroup(inputdev_t* device, const inputdev_layout_controlgroup_t* group, + Point2Raw* _origin, RectRaw* retGeometry) +{ +#define SPACING 2 + + Point2Raw origin; + Rect* grpGeom = NULL; + RectRaw ctrlGeom; + uint i; + + if(retGeometry) + { + retGeometry->origin.x = retGeometry->origin.y = 0; + retGeometry->size.width = retGeometry->size.height = 0; + } + + if(!device || !group) return; + + origin.x = _origin? _origin->x : 0; + origin.y = _origin? _origin->y : 0; + + for(i = 0; i < group->numControls; ++i) + { + const inputdev_layout_control_t* ctrl = group->controls + i; + + switch(ctrl->type) + { + case IDC_KEY: + Rend_RenderKeyStateVisual(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; + default: + Con_Error("drawControlGroup: Unknown inputdev_controltype %i.", (int)ctrl->type); + exit(1); // Unreachable. + } + + if(ctrlGeom.size.width > 0 && ctrlGeom.size.height > 0) + { + origin.x += ctrlGeom.size.width + SPACING; + + if(grpGeom) + Rect_UniteRaw(grpGeom, &ctrlGeom); + else + grpGeom = Rect_NewFromRaw(&ctrlGeom); + } + } + + if(grpGeom) + { + if(retGeometry) + { + Rect_Raw(grpGeom, retGeometry); + } + + Rect_Delete(grpGeom); + } + +#undef SPACING +} + +/** + * Render a visual representation of the current state of the specified device. + */ +void Rend_RenderInputDeviceStateVisual(inputdev_t* device, const inputdev_layout_t* layout, + const Point2Raw* origin, Size2Raw* retVisualDimensions) +{ +#define SPACING 2 + + Rect* visualGeom = NULL; + Point2Raw offset; + uint i; + + LIBDENG_ASSERT_IN_MAIN_THREAD(); + + if(retVisualDimensions) + { + retVisualDimensions->width = retVisualDimensions->height = 0; + } + + if(novideo || isDedicated) return; // Not for us. + if(!device || !layout) return; + + // Init render state. + FR_SetFont(fontFixed); + FR_PushAttrib(); + FR_LoadDefaultAttrib(); + FR_SetLeading(0); + FR_SetColorAndAlpha(1, 1, 1, 1); + initDrawStateForVisual(origin); + + offset.x = offset.y = 0; + + // Draw device name first. + if(device->niceName) + { + Size2Raw size; + + glEnable(GL_TEXTURE_2D); + FR_DrawText(device->niceName, NULL/*no offset*/); + glDisable(GL_TEXTURE_2D); + + FR_TextSize(&size, device->niceName); + visualGeom = Rect_NewWithOriginSize2(offset.x, offset.y, size.width, size.height); + + offset.y += size.height + SPACING; + } + + // Draw control groups. + for(i = 0; i < layout->numGroups; ++i) + { + const inputdev_layout_controlgroup_t* grp = layout->groups + i; + RectRaw grpGeometry; + + drawControlGroup(device, grp, &offset, &grpGeometry); + + if(grpGeometry.size.width > 0 && grpGeometry.size.height > 0) + { + if(visualGeom) + Rect_UniteRaw(visualGeom, &grpGeometry); + else + visualGeom = Rect_NewFromRaw(&grpGeometry); + + offset.y = Rect_Y(visualGeom) + Rect_Height(visualGeom) + SPACING; + } + } + + // Back to previous render state. + endDrawStateForVisual(origin); + FR_PopAttrib(); + + // Return the united geometry dimensions? + if(visualGeom && retVisualDimensions) + { + retVisualDimensions->width = Rect_Width(visualGeom); + retVisualDimensions->height = Rect_Height(visualGeom); + } + +#undef SPACING +} + +void Rend_AllInputDeviceStateVisuals(void) +{ +#define SPACING 2 +#define NUMITEMS(x) (sizeof(x)/sizeof((x)[0])) + + // Keyboard (Standard US English layout): + static inputdev_layout_control_t keyGroup1[] = { + { IDC_KEY, 27 }, // escape + { IDC_KEY, 132 }, // f1 + { IDC_KEY, 133 }, // f2 + { IDC_KEY, 134 }, // f3 + { IDC_KEY, 135 }, // f4 + { IDC_KEY, 136 }, // f5 + { IDC_KEY, 137 }, // f6 + { IDC_KEY, 138 }, // f7 + { IDC_KEY, 139 }, // f8 + { IDC_KEY, 140 }, // f9 + { IDC_KEY, 141 }, // f10 + { IDC_KEY, 142 }, // f11 + { IDC_KEY, 143 } // f12 + }; + static inputdev_layout_control_t keyGroup2[] = { + { IDC_KEY, 96 }, // tilde + { IDC_KEY, 49 }, // 1 + { IDC_KEY, 50 }, // 2 + { IDC_KEY, 51 }, // 3 + { IDC_KEY, 52 }, // 4 + { IDC_KEY, 53 }, // 5 + { IDC_KEY, 54 }, // 6 + { IDC_KEY, 55 }, // 7 + { IDC_KEY, 56 }, // 8 + { IDC_KEY, 57 }, // 9 + { IDC_KEY, 48 }, // 0 + { IDC_KEY, 45 }, // - + { IDC_KEY, 61 }, // = + { IDC_KEY, 127 } // backspace + }; + static inputdev_layout_control_t keyGroup3[] = { + { IDC_KEY, 9 }, // tab + { IDC_KEY, 113 }, // q + { IDC_KEY, 119 }, // w + { IDC_KEY, 101 }, // e + { IDC_KEY, 114 }, // r + { IDC_KEY, 116 }, // t + { IDC_KEY, 121 }, // y + { IDC_KEY, 117 }, // u + { IDC_KEY, 105 }, // i + { IDC_KEY, 111 }, // o + { IDC_KEY, 112 }, // p + { IDC_KEY, 91 }, // { + { IDC_KEY, 93 }, // } + { IDC_KEY, 92 }, // bslash + }; + static inputdev_layout_control_t keyGroup4[] = { + { IDC_KEY, 145 }, // capslock + { IDC_KEY, 97 }, // a + { IDC_KEY, 115 }, // s + { IDC_KEY, 100 }, // d + { IDC_KEY, 102 }, // f + { IDC_KEY, 103 }, // g + { IDC_KEY, 104 }, // h + { IDC_KEY, 106 }, // j + { IDC_KEY, 107 }, // k + { IDC_KEY, 108 }, // l + { IDC_KEY, 59 }, // semicolon + { IDC_KEY, 39 }, // apostrophe + { IDC_KEY, 13 } // return + }; + static inputdev_layout_control_t keyGroup5[] = { + { IDC_KEY, 159 }, // shift + { IDC_KEY, 122 }, // z + { IDC_KEY, 120 }, // x + { IDC_KEY, 99 }, // c + { IDC_KEY, 118 }, // v + { IDC_KEY, 98 }, // b + { IDC_KEY, 110 }, // n + { IDC_KEY, 109 }, // m + { IDC_KEY, 44 }, // comma + { IDC_KEY, 46 }, // period + { IDC_KEY, 47 }, // fslash + { IDC_KEY, 159 }, // shift + }; + static inputdev_layout_control_t keyGroup6[] = { + { IDC_KEY, 160 }, // ctrl + { IDC_KEY, 0 }, // ??? + { IDC_KEY, 161 }, // alt + { IDC_KEY, 32 }, // space + { IDC_KEY, 161 }, // alt + { IDC_KEY, 0 }, // ??? + { IDC_KEY, 0 }, // ??? + { IDC_KEY, 160 } // ctrl + }; + static inputdev_layout_control_t keyGroup7[] = { + { IDC_KEY, 170 }, // printscrn + { IDC_KEY, 146 }, // scrolllock + { IDC_KEY, 158 } // pause + }; + static inputdev_layout_control_t keyGroup8[] = { + { IDC_KEY, 162 }, // insert + { IDC_KEY, 166 }, // home + { IDC_KEY, 164 } // pageup + }; + static inputdev_layout_control_t keyGroup9[] = { + { IDC_KEY, 163 }, // delete + { IDC_KEY, 167 }, // end + { IDC_KEY, 165 }, // pagedown + }; + static inputdev_layout_control_t keyGroup10[] = { + { IDC_KEY, 130 }, // up + { IDC_KEY, 129 }, // left + { IDC_KEY, 131 }, // down + { IDC_KEY, 128 }, // right + }; + static inputdev_layout_control_t keyGroup11[] = { + { IDC_KEY, 144 }, // numlock + { IDC_KEY, 172 }, // divide + { IDC_KEY, 42 }, // multiply + { IDC_KEY, 168 } // subtract + }; + static inputdev_layout_control_t keyGroup12[] = { + { IDC_KEY, 147 }, // pad 7 + { IDC_KEY, 148 }, // pad 8 + { IDC_KEY, 149 }, // pad 9 + { IDC_KEY, 169 }, // add + }; + static inputdev_layout_control_t keyGroup13[] = { + { IDC_KEY, 150 }, // pad 4 + { IDC_KEY, 151 }, // pad 5 + { IDC_KEY, 152 } // pad 6 + }; + static inputdev_layout_control_t keyGroup14[] = { + { IDC_KEY, 153 }, // pad 1 + { IDC_KEY, 154 }, // pad 2 + { IDC_KEY, 155 }, // pad 3 + { IDC_KEY, 171 } // enter + }; + static inputdev_layout_control_t keyGroup15[] = { + { IDC_KEY, 156 }, // pad 0 + { IDC_KEY, 157 } // pad . + }; + static inputdev_layout_controlgroup_t keyGroups[] = { + { keyGroup1, NUMITEMS(keyGroup1) }, + { keyGroup2, NUMITEMS(keyGroup2) }, + { keyGroup3, NUMITEMS(keyGroup3) }, + { keyGroup4, NUMITEMS(keyGroup4) }, + { keyGroup5, NUMITEMS(keyGroup5) }, + { keyGroup6, NUMITEMS(keyGroup6) }, + { keyGroup7, NUMITEMS(keyGroup7) }, + { keyGroup8, NUMITEMS(keyGroup8) }, + { keyGroup9, NUMITEMS(keyGroup9) }, + { keyGroup10, NUMITEMS(keyGroup10) }, + { keyGroup11, NUMITEMS(keyGroup11) }, + { keyGroup12, NUMITEMS(keyGroup12) }, + { keyGroup13, NUMITEMS(keyGroup13) }, + { keyGroup14, NUMITEMS(keyGroup14) }, + { keyGroup15, NUMITEMS(keyGroup15) } + }; + static inputdev_layout_t keyLayout = { keyGroups, NUMITEMS(keyGroups) }; + + // Mouse: + static inputdev_layout_control_t mouseGroup1[] = { + { IDC_AXIS, 0 }, // x-axis + { IDC_AXIS, 1 }, // y-axis + }; + static inputdev_layout_control_t mouseGroup2[] = { + { IDC_KEY, 0 }, // left + { IDC_KEY, 1 }, // middle + { IDC_KEY, 2 } // right + }; + static inputdev_layout_control_t mouseGroup3[] = { + { IDC_KEY, 3 }, // wheelup + { IDC_KEY, 4 } // wheeldown + }; + static inputdev_layout_control_t mouseGroup4[] = { + { IDC_KEY, 5 }, + { IDC_KEY, 6 }, + { IDC_KEY, 7 }, + { IDC_KEY, 8 }, + { IDC_KEY, 9 }, + { IDC_KEY, 10 }, + { IDC_KEY, 11 }, + { IDC_KEY, 12 }, + { IDC_KEY, 13 }, + { IDC_KEY, 14 }, + { IDC_KEY, 15 } + }; + static inputdev_layout_controlgroup_t mouseGroups[] = { + { mouseGroup1, NUMITEMS(mouseGroup1) }, + { mouseGroup2, NUMITEMS(mouseGroup2) }, + { mouseGroup3, NUMITEMS(mouseGroup3) }, + { mouseGroup4, NUMITEMS(mouseGroup4) } + }; + static inputdev_layout_t mouseLayout = { mouseGroups, NUMITEMS(mouseGroups) }; + + // Joystick: + static inputdev_layout_control_t joyGroup1[] = { + { IDC_AXIS, 0 }, // x-axis + { IDC_AXIS, 1 }, // y-axis + { IDC_AXIS, 2 }, // z-axis + { IDC_AXIS, 3 } // w-axis + }; + static inputdev_layout_control_t joyGroup2[] = { + { IDC_AXIS, 4 }, + { IDC_AXIS, 5 }, + { IDC_AXIS, 6 }, + { IDC_AXIS, 7 }, + { IDC_AXIS, 8 }, + { IDC_AXIS, 9 }, + { IDC_AXIS, 10 }, + { IDC_AXIS, 11 }, + { IDC_AXIS, 12 }, + { IDC_AXIS, 13 }, + { IDC_AXIS, 14 }, + { IDC_AXIS, 15 }, + { IDC_AXIS, 16 }, + { IDC_AXIS, 17 } + }; + static inputdev_layout_control_t joyGroup3[] = { + { IDC_AXIS, 18 }, + { IDC_AXIS, 19 }, + { IDC_AXIS, 20 }, + { IDC_AXIS, 21 }, + { IDC_AXIS, 22 }, + { IDC_AXIS, 23 }, + { IDC_AXIS, 24 }, + { IDC_AXIS, 25 }, + { IDC_AXIS, 26 }, + { IDC_AXIS, 27 }, + { IDC_AXIS, 28 }, + { IDC_AXIS, 29 }, + { IDC_AXIS, 30 }, + { IDC_AXIS, 31 } + }; + static inputdev_layout_control_t joyGroup4[] = { + { IDC_HAT, 0 }, + { IDC_HAT, 1 }, + { IDC_HAT, 2 }, + { IDC_HAT, 3 } + }; + static inputdev_layout_control_t joyGroup5[] = { + { IDC_KEY, 0 }, + { IDC_KEY, 1 }, + { IDC_KEY, 2 }, + { IDC_KEY, 3 }, + { IDC_KEY, 4 }, + { IDC_KEY, 5 }, + { IDC_KEY, 6 }, + { IDC_KEY, 7 } + }; + static inputdev_layout_control_t joyGroup6[] = { + { IDC_KEY, 8 }, + { IDC_KEY, 9 }, + { IDC_KEY, 10 }, + { IDC_KEY, 11 }, + { IDC_KEY, 12 }, + { IDC_KEY, 13 }, + { IDC_KEY, 14 }, + { IDC_KEY, 15 }, + }; + static inputdev_layout_control_t joyGroup7[] = { + { IDC_KEY, 16 }, + { IDC_KEY, 17 }, + { IDC_KEY, 18 }, + { IDC_KEY, 19 }, + { IDC_KEY, 20 }, + { IDC_KEY, 21 }, + { IDC_KEY, 22 }, + { IDC_KEY, 23 }, + }; + static inputdev_layout_control_t joyGroup8[] = { + { IDC_KEY, 24 }, + { IDC_KEY, 25 }, + { IDC_KEY, 26 }, + { IDC_KEY, 27 }, + { IDC_KEY, 28 }, + { IDC_KEY, 29 }, + { IDC_KEY, 30 }, + { IDC_KEY, 31 }, + }; + static inputdev_layout_controlgroup_t joyGroups[] = { + { joyGroup1, NUMITEMS(joyGroup1) }, + { joyGroup2, NUMITEMS(joyGroup2) }, + { joyGroup3, NUMITEMS(joyGroup3) }, + { joyGroup4, NUMITEMS(joyGroup4) }, + { joyGroup5, NUMITEMS(joyGroup5) }, + { joyGroup6, NUMITEMS(joyGroup6) }, + { joyGroup7, NUMITEMS(joyGroup7) }, + { joyGroup8, NUMITEMS(joyGroup8) } + }; + static inputdev_layout_t joyLayout = { joyGroups, NUMITEMS(joyGroups) }; + + Point2Raw origin = { 2, 2 }; + Size2Raw dimensions; + + LIBDENG_ASSERT_IN_MAIN_THREAD(); + + if(novideo || isDedicated) return; // Not for us. + + // Disabled? + if(!devRendKeyState && !devRendMouseState && !devRendJoyState) return; + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrtho(0, theWindow->geometry.size.width, theWindow->geometry.size.height, 0, -1, 1); + + if(devRendKeyState) + { + Rend_RenderInputDeviceStateVisual(I_GetDevice(IDEV_KEYBOARD, false), &keyLayout, &origin, &dimensions); + origin.y += dimensions.height + SPACING; + } + + if(devRendMouseState) + { + Rend_RenderInputDeviceStateVisual(I_GetDevice(IDEV_MOUSE, false), &mouseLayout, &origin, &dimensions); + origin.y += dimensions.height + SPACING; + } + + if(devRendJoyState) + { + Rend_RenderInputDeviceStateVisual(I_GetDevice(IDEV_JOY1, false), &joyLayout, &origin, &dimensions); + } + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + +#undef NUMITEMS +#undef SPACING +} +#endif + +static void I_PrintAxisConfig(inputdev_t* device, inputdevaxis_t* axis) { Con_Printf("%s-%s Config:\n" " Type: %s\n" @@ -1465,10 +2127,9 @@ static void I_PrintAxisConfig(inputdev_t *device, inputdevaxis_t *axis) D_CMD(AxisPrintConfig) { - uint deviceID; - uint axisID; - inputdev_t *device; - inputdevaxis_t *axis; + uint deviceID, axisID; + inputdev_t* device; + inputdevaxis_t* axis; if(!I_ParseDeviceAxis(argv[1], &deviceID, &axisID)) { @@ -1485,10 +2146,9 @@ D_CMD(AxisPrintConfig) D_CMD(AxisChangeOption) { - uint deviceID; - uint axisID; - inputdev_t *device; - inputdevaxis_t *axis; + uint deviceID, axisID; + inputdev_t* device; + inputdevaxis_t* axis; if(!I_ParseDeviceAxis(argv[1], &deviceID, &axisID)) { @@ -1522,6 +2182,7 @@ D_CMD(AxisChangeValue) uint deviceID, axisID; inputdevaxis_t* axis; inputdev_t* device; + if(!I_ParseDeviceAxis(argv[1], &deviceID, &axisID)) { Con_Printf("'%s' is not a valid device or device axis.\n", argv[1]); @@ -1530,7 +2191,7 @@ D_CMD(AxisChangeValue) device = I_GetDevice(deviceID, false); axis = I_GetAxisByID(device, axisID); - if(NULL != axis) + if(axis) { // Values: if(!stricmp(argv[2], "filter")) @@ -1556,8 +2217,8 @@ D_CMD(AxisChangeValue) */ D_CMD(ListInputDevices) { - uint i, j; - inputdev_t *dev; + inputdev_t* dev; + uint i, j; Con_Printf("Input Devices:\n"); for(i = 0; i < NUM_INPUT_DEVICES; ++i) @@ -1566,8 +2227,8 @@ D_CMD(ListInputDevices) if(!dev->name || !(dev->flags & ID_ACTIVE)) continue; - Con_Printf("%s (%i keys, %i axes)\n", dev->name, dev->numKeys, - dev->numAxes); + Con_Printf("%s (%i keys, %i axes)\n", dev->name, dev->numKeys, dev->numAxes); + for(j = 0; j < dev->numAxes; ++j) { Con_Printf(" Axis #%i: %s\n", j, dev->axes[j].name); diff --git a/doomsday/engine/portable/src/net_main.c b/doomsday/engine/portable/src/net_main.c index ed3928bff0..52a691c4e9 100644 --- a/doomsday/engine/portable/src/net_main.c +++ b/doomsday/engine/portable/src/net_main.c @@ -710,6 +710,9 @@ void Net_Drawer(void) // Draw the light range debug display. R_DrawLightRange(); + // Draw the input device debug display. + Rend_AllInputDeviceStateVisuals(); + // Draw the demo recording overlay. Net_DrawDemoOverlay(); }