diff --git a/docs/rh-log.txt b/docs/rh-log.txt index dee4983b2..f9fc090d3 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,4 +1,13 @@ May 26, 2009 +- Split DirectInput keyboard handling into a separate file and class. I also + switched it to buffered input, and the pause key seems to be properly + cooked, so I don't need to look for it with WM_KEYDOWN/UP. Tab doesn't + need to be special-cased either, because buffered input never passes on + the Tab key when you press Alt+Tab. I have no idea why I special-cased + Num Lock, but it seems to be working fine. By setting the exclusive mode + to background, I can also avoid special code for releasing all keys when + the window loses focus, because I'll still receive those events while the + window is in the background. - Fixed: The Heretic "take weapons" cheat did not remove all the weapons at once. This is because destroying one weapon has a potential to destroy a sister weapon as well. If the sister weapon is the next one in line (as it diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a716327cf..ab9281586 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -398,6 +398,7 @@ if( WIN32 ) win32/i_cd.cpp win32/i_crash.cpp win32/i_input.cpp + win32/i_keyboard.cpp win32/i_mouse.cpp win32/i_main.cpp win32/i_movie.cpp diff --git a/src/c_bind.cpp b/src/c_bind.cpp index a6d8488ea..b2912e1ad 100644 --- a/src/c_bind.cpp +++ b/src/c_bind.cpp @@ -191,14 +191,14 @@ const char *KeyNames[NUM_KEYS] = NULL, NULL, NULL, NULL, NULL, NULL, "voldown", NULL, //A8 "volup", NULL, "webhome", "kp,", NULL, "kp/", NULL, "sysrq", //B0 "ralt", NULL, NULL, NULL, NULL, NULL, NULL, NULL, //B8 - NULL, NULL, NULL, NULL, NULL, NULL, NULL, "home", //C0 + NULL, NULL, NULL, NULL, NULL, "pause", NULL, "home", //C0 "uparrow", "pgup", NULL, "leftarrow",NULL, "rightarrow",NULL, "end", //C8 "downarrow","pgdn", "ins", "del", NULL, NULL, NULL, NULL, //D0 NULL, NULL, NULL, "lwin", "rwin", "apps", "power", "sleep", //D8 NULL, NULL, NULL, "wake", NULL, "search", "favorites","refresh", //E0 "webstop", "webforward","webback", "mycomputer","mail", "mediaselect",NULL, NULL, //E8 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, //F0 - NULL, NULL, NULL, NULL, NULL, NULL, NULL, "pause", //F8 + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, //F8 // non-keyboard buttons that can be bound "mouse1", "mouse2", "mouse3", "mouse4", // 8 mouse buttons diff --git a/src/doomdef.h b/src/doomdef.h index 008adee9a..bc48a78a0 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -104,6 +104,7 @@ enum ESkillLevels // DOOM keyboard definition. Everything below 0x100 matches // a DirectInput key code. // +#define KEY_PAUSE 0xc5 // DIK_PAUSE #define KEY_RIGHTARROW 0xcd // DIK_RIGHT #define KEY_LEFTARROW 0xcb // DIK_LEFT #define KEY_UPARROW 0xc8 // DIK_UP @@ -126,7 +127,6 @@ enum ESkillLevels #define KEY_F12 0x58 // DIK_F12 #define KEY_BACKSPACE 0x0e // DIK_BACK -#define KEY_PAUSE 0xff #define KEY_EQUALS 0x0d // DIK_EQUALS #define KEY_MINUS 0x0c // DIK_MINUS diff --git a/src/win32/i_input.cpp b/src/win32/i_input.cpp index 8a6596680..84acb5a5c 100644 --- a/src/win32/i_input.cpp +++ b/src/win32/i_input.cpp @@ -124,12 +124,11 @@ extern bool SpawnEAXWindow; static HMODULE DInputDLL; -static void KeyRead (); -static BOOL I_StartupKeyboard (); static HRESULT InitJoystick (); bool GUICapture; extern FMouse *Mouse; +extern FInputDevice *Keyboard; bool VidResizing; @@ -294,8 +293,6 @@ CVAR (Float, joy_forwardspeed, -1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Float, joy_sidespeed, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Float, joy_upspeed, -1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -// set this to false to make keypad-enter a usable separate key! -CVAR (Bool, k_mergekeys, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Bool, k_allowfullscreentoggle, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) static FBaseCVar * const JoyConfigVars[] = @@ -307,31 +304,9 @@ static FBaseCVar * const JoyConfigVars[] = }; static BYTE KeyState[256]; -static BYTE DIKState[2][NUM_KEYS]; -static int KeysReadCount; +/*static BYTE DIKState[2][NUM_KEYS]; static int ActiveDIKState; -// Convert DIK_* code to ASCII using Qwerty keymap -static const BYTE Convert [256] = -{ - // 0 1 2 3 4 5 6 7 8 9 A B C D E F - 0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 8, 9, // 0 - 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', 13, 0, 'a', 's', // 1 - 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', 39, '`', 0,'\\', 'z', 'x', 'c', 'v', // 2 - 'b', 'n', 'm', ',', '.', '/', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, // 3 - 0, 0, 0, 0, 0, 0, 0, '7', '8', '9', '-', '4', '5', '6', '+', '1', // 4 - '2', '3', '0', '.', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7 - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '=', 0, 0, // 8 - 0, '@', ':', '_', 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, // 9 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A - 0, 0, 0, ',', 0, '/', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C - 0, 0, 0, 0, 0, 0, 0, 0 - -}; static void FlushDIKState (int low=0, int high=NUM_KEYS-1) { @@ -352,7 +327,7 @@ static void FlushDIKState (int low=0, int high=NUM_KEYS-1) } } } - +*/ extern int chatmodeon; static void I_CheckGUICapture () @@ -373,21 +348,32 @@ static void I_CheckGUICapture () GUICapture = wantCapt; if (wantCapt) { - FlushDIKState (); +// FlushDIKState (); } } } +bool CallHook(FInputDevice *device, HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result) +{ + if (device == NULL) + { + return false; + } + *result = 0; + return device->WndProcHook(hWnd, message, wParam, lParam, result); +} + LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { - if (Mouse != NULL) - { - LRESULT result = 0; + LRESULT result; - if (Mouse->WndProcHook(hWnd, message, wParam, lParam, &result)) - { - return result; - } + if (CallHook(Keyboard, hWnd, message, wParam, lParam, &result)) + { + return result; + } + if (CallHook(Mouse, hWnd, message, wParam, lParam, &result)) + { + return result; } event_t event; @@ -424,7 +410,7 @@ LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_KILLFOCUS: if (g_pKey) g_pKey->Unacquire (); - FlushDIKState (); +// FlushDIKState (); HaveFocus = false; I_CheckNativeMouse (true); // Make sure mouse gets released right away break; @@ -510,6 +496,7 @@ LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) } else { +#if 0 if (message == WM_KEYUP) { event.type = EV_KeyUp; @@ -544,6 +531,7 @@ LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) DIKState[ActiveDIKState][event.data1] = (event.type == EV_KeyDown); D_PostEvent (&event); } +#endif } break; @@ -1248,11 +1236,9 @@ bool I_InitInput (void *hwnd) // Free all input resources void I_ShutdownInput () { - if (g_pKey) + if (Keyboard != NULL) { - g_pKey->Unacquire (); - g_pKey->Release (); - g_pKey = NULL; + delete Keyboard; } if (Mouse != NULL) { @@ -1281,120 +1267,6 @@ void I_ShutdownInput () } } -// Initialize the keyboard -static BOOL I_StartupKeyboard (void) -{ - HRESULT hr; - - // Obtain an interface to the system key device. - if (g_pdi3) - { - hr = g_pdi3->CreateDevice (GUID_SysKeyboard, (LPDIRECTINPUTDEVICE*)&g_pKey, NULL); - } - else - { - hr = g_pdi->CreateDevice (GUID_SysKeyboard, &g_pKey, NULL); - } - - if (FAILED(hr)) - { - I_FatalError ("Could not create keyboard device"); - } - - // Set the data format to "keyboard format". - hr = g_pKey->SetDataFormat (&c_dfDIKeyboard); - - if (FAILED(hr)) - { - I_FatalError ("Could not set keyboard data format"); - } - - // Set the cooperative level. - hr = g_pKey->SetCooperativeLevel (Window, DISCL_FOREGROUND|DISCL_NONEXCLUSIVE); - - if (FAILED(hr)) - { - I_FatalError("Could not set keyboard cooperative level"); - } - - g_pKey->Acquire (); - return TRUE; -} - -static void KeyRead () -{ - HRESULT hr; - event_t event; - BYTE *fromState, *toState; - int i; - - if (g_pKey == NULL) - { - return; - } - - memset (&event, 0, sizeof(event)); - fromState = DIKState[ActiveDIKState]; - toState = DIKState[ActiveDIKState ^ 1]; - - hr = g_pKey->GetDeviceState (256, toState); - if (hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED) - { - hr = g_pKey->Acquire (); - if (hr != DI_OK) - { - return; - } - hr = g_pKey->GetDeviceState (256, toState); - } - if (hr != DI_OK) - { - return; - } - - // Successfully got the buffer - KeysReadCount++; - ActiveDIKState ^= 1; - - // Copy key states not handled here from the old to the new buffer - memcpy (toState + 256, fromState + 256, NUM_KEYS - 256); - toState[DIK_TAB] = fromState[DIK_TAB]; - toState[DIK_NUMLOCK] = fromState[DIK_NUMLOCK]; - - if (k_mergekeys) - { - // "Merge" multiple keys that are considered to be the same. - // Also clear out the alternate versions after merging. - toState[DIK_RETURN] |= toState[DIK_NUMPADENTER]; - toState[DIK_LMENU] |= toState[DIK_RMENU]; - toState[DIK_LCONTROL] |= toState[DIK_RCONTROL]; - toState[DIK_LSHIFT] |= toState[DIK_RSHIFT]; - - toState[DIK_NUMPADENTER] = 0; - toState[DIK_RMENU] = 0; - toState[DIK_RCONTROL] = 0; - toState[DIK_RSHIFT] = 0; - } - - // Now generate events for any keys that differ between the states - if (!GUICapture) - { - for (i = 1; i < 256; i++) - { - if (toState[i] != fromState[i]) - { - event.type = toState[i] ? EV_KeyDown : EV_KeyUp; - event.data1 = i; - event.data2 = Convert[i]; - event.data3 = (toState[DIK_LSHIFT] ? GKM_SHIFT : 0) | - (toState[DIK_LCONTROL] ? GKM_CTRL : 0) | - (toState[DIK_LMENU] ? GKM_ALT : 0); - D_PostEvent (&event); - } - } - } -} - void I_GetEvent () { MSG mess; @@ -1414,8 +1286,10 @@ void I_GetEvent () } } - KeyRead (); - + if (Keyboard != NULL) + { + Keyboard->ProcessInput(); + } if (Mouse != NULL) { Mouse->ProcessInput(); diff --git a/src/win32/i_input.h b/src/win32/i_input.h index 5c797551b..026a3de38 100644 --- a/src/win32/i_input.h +++ b/src/win32/i_input.h @@ -86,6 +86,7 @@ protected: void I_StartupMouse(); void I_CheckNativeMouse(bool prefer_native); +void I_StartupKeyboard(); // USB HID usage page numbers #define HID_GENERIC_DESKTOP_PAGE 0x01 diff --git a/src/win32/i_keyboard.cpp b/src/win32/i_keyboard.cpp new file mode 100644 index 000000000..16842321f --- /dev/null +++ b/src/win32/i_keyboard.cpp @@ -0,0 +1,301 @@ +// HEADER FILES ------------------------------------------------------------ + +#define WIN32_LEAN_AND_MEAN +#define DIRECTINPUT_VERSION 0x800 +#define _WIN32_WINNT 0x0501 +#include +#include + +#define USE_WINDOWS_DWORD +#include "i_input.h" +#include "i_system.h" +#include "d_event.h" +#include "d_gui.h" +#include "c_cvars.h" +#include "doomdef.h" +#include "doomstat.h" +#include "win32iface.h" +#include "rawinput.h" + +// MACROS ------------------------------------------------------------------ + +#define DINPUT_BUFFERSIZE 32 + +// TYPES ------------------------------------------------------------------- + +class FDInputKeyboard : public FInputDevice +{ +public: + FDInputKeyboard(); + ~FDInputKeyboard(); + + bool GetDevice(); + void ProcessInput(); + bool WndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result); + +protected: + LPDIRECTINPUTDEVICE8 Device; + BYTE KeyStates[256/8]; + + int CheckKey(int keynum) const + { + return KeyStates[keynum >> 3] & (1 << (keynum & 7)); + } + void SetKey(int keynum, bool down) + { + if (down) + { + KeyStates[keynum >> 3] |= 1 << (keynum & 7); + } + else + { + KeyStates[keynum >> 3] &= ~(1 << (keynum & 7)); + } + } +}; + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +extern HWND Window; +extern LPDIRECTINPUT8 g_pdi; +extern LPDIRECTINPUT g_pdi3; +extern bool GUICapture; +extern bool HaveFocus; + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +// Convert DIK_* code to ASCII using Qwerty keymap +static const BYTE Convert [256] = +{ + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 8, 9, // 0 + 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', 13, 0, 'a', 's', // 1 + 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', 39, '`', 0,'\\', 'z', 'x', 'c', 'v', // 2 + 'b', 'n', 'm', ',', '.', '/', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, // 3 + 0, 0, 0, 0, 0, 0, 0, '7', '8', '9', '-', '4', '5', '6', '+', '1', // 4 + '2', '3', '0', '.', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7 + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '=', 0, 0, // 8 + 0, '@', ':', '_', 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, // 9 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A + 0, 0, 0, ',', 0, '/', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C + 0, 0, 0, 0, 0, 0, 0, 0 + +}; + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +FInputDevice *Keyboard; + +// Set this to false to make keypad-enter a usable separate key. +CVAR (Bool, k_mergekeys, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) + +// CODE -------------------------------------------------------------------- + +//========================================================================== +// +// FDInputKeyboard - Constructor +// +//========================================================================== + +FDInputKeyboard::FDInputKeyboard() +{ + Device = NULL; + memset(KeyStates, 0, sizeof(KeyStates)); +} + +//========================================================================== +// +// FDInputKeyboard - Destructor +// +//========================================================================== + +FDInputKeyboard::~FDInputKeyboard() +{ + if (Device != NULL) + { + Device->Release(); + Device = NULL; + } +} + +//========================================================================== +// +// FDInputKeyboard :: GetDevice +// +// Create the device interface and initialize it. +// +//========================================================================== + +bool FDInputKeyboard::GetDevice() +{ + HRESULT hr; + + if (g_pdi3 != NULL) + { // DirectInput3 interface + hr = g_pdi3->CreateDevice(GUID_SysKeyboard, (LPDIRECTINPUTDEVICE*)&Device, NULL); + } + else if (g_pdi != NULL) + { // DirectInput8 interface + hr = g_pdi->CreateDevice(GUID_SysKeyboard, &Device, NULL); + } + else + { + hr = -1; + } + if (FAILED(hr)) + { + return false; + } + + // Yes, this is a keyboard. + hr = Device->SetDataFormat(&c_dfDIKeyboard); + if (FAILED(hr)) + { +ufailit: + Device->Release(); + Device = NULL; + return false; + } + // Set cooperative level. + hr = Device->SetCooperativeLevel(Window, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND); + if (FAILED(hr)) + { + goto ufailit; + } + // Set buffer size so we can use buffered input. + DIPROPDWORD prop; + prop.diph.dwSize = sizeof(prop); + prop.diph.dwHeaderSize = sizeof(prop.diph); + prop.diph.dwObj = 0; + prop.diph.dwHow = DIPH_DEVICE; + prop.dwData = DINPUT_BUFFERSIZE; + hr = Device->SetProperty(DIPROP_BUFFERSIZE, &prop.diph); + if (FAILED(hr)) + { + goto ufailit; + } + Device->Acquire(); + return true; +} + +//========================================================================== +// +// FDInputKeyboard :: ProcessInput +// +//========================================================================== + +void FDInputKeyboard::ProcessInput() +{ + DIDEVICEOBJECTDATA od; + DWORD dwElements; + HRESULT hr; + int key; + bool foreground = (GetForegroundWindow() == Window); + + event_t ev = { 0 }; + for (;;) + { + DWORD cbObjectData = g_pdi3 ? sizeof(DIDEVICEOBJECTDATA_DX3) : sizeof(DIDEVICEOBJECTDATA); + dwElements = 1; + hr = Device->GetDeviceData(cbObjectData, &od, &dwElements, 0); + if (hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED) + { + Device->Acquire(); + hr = Device->GetDeviceData(cbObjectData, &od, &dwElements, 0); + } + if (FAILED(hr) || !dwElements) + { + break; + } + + key = od.dwOfs; +// Printf("buffer ofs=%02x data=%02x\n", od.dwOfs, od.dwData); + if (key >= 1 && key <= 255) + { + if (k_mergekeys) + { + // "Merge" multiple keys that are considered to be the same. + if (key == DIK_NUMPADENTER) + { + key = DIK_RETURN; + } + else if (key == DIK_RMENU) + { + key = DIK_LMENU; + } + else if (key == DIK_RCONTROL) + { + key = DIK_LCONTROL; + } + else if (key == DIK_RSHIFT) + { + key = DIK_LSHIFT; + } + } + // Generate an event, but only if it isn't a repeat of the existing state. + if (od.dwData & 0x80) + { + if (!foreground || GUICapture) + { // Do not generate key down events if we are in the background + // or in "GUI Capture" mode. + continue; + } + if (CheckKey(key)) + { // Key is already down. + continue; + } + SetKey(key, true); + ev.type = EV_KeyDown; + } + else + { + if (!CheckKey(key)) + { // Key is already up. + continue; + } + SetKey(key, false); + ev.type = EV_KeyUp; + } + ev.data1 = key; + ev.data2 = Convert[key]; + D_PostEvent(&ev); + } + } +} + +//========================================================================== +// +// FDInputKeyboard :: WndProcHook +// +//========================================================================== + +bool FDInputKeyboard::WndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result) +{ + return false; +} + +//========================================================================== +// +// I_StartupKeyboard +// +//========================================================================== + +void I_StartupKeyboard() +{ + Keyboard = new FDInputKeyboard; + if (!Keyboard->GetDevice()) + { + delete Keyboard; + } +} + diff --git a/src/win32/i_mouse.cpp b/src/win32/i_mouse.cpp index 10bc5711f..b7253a21d 100644 --- a/src/win32/i_mouse.cpp +++ b/src/win32/i_mouse.cpp @@ -762,7 +762,6 @@ void FDInputMouse::ProcessInput() DIDEVICEOBJECTDATA od; DWORD dwElements; HRESULT hr; - int count = 0; int dx, dy; dx = 0; @@ -787,8 +786,6 @@ void FDInputMouse::ProcessInput() if (FAILED(hr) || !dwElements) break; - count++; - /* Look at the element to see what happened */ // GCC does not like putting the DIMOFS_ macros in case statements, // so use ifs instead. diff --git a/zdoom.vcproj b/zdoom.vcproj index da9a1fbef..4c2d8f67b 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -1976,6 +1976,10 @@ RelativePath=".\src\win32\i_input.h" > + +