mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-24 04:51:19 +00:00
- Added Raw Input keyboard handling.
SVN r1614 (trunk)
This commit is contained in:
parent
7fea07dff7
commit
a11073341c
4 changed files with 397 additions and 152 deletions
|
@ -1,4 +1,7 @@
|
||||||
May 26, 2009
|
May 27, 2009
|
||||||
|
- Added Raw Input keyboard handling.
|
||||||
|
|
||||||
|
May 26, 2009
|
||||||
- Split DirectInput keyboard handling into a separate file and class. I also
|
- 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
|
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
|
cooked, so I don't need to look for it with WM_KEYDOWN/UP. Tab doesn't
|
||||||
|
|
|
@ -128,7 +128,7 @@ static HRESULT InitJoystick ();
|
||||||
|
|
||||||
bool GUICapture;
|
bool GUICapture;
|
||||||
extern FMouse *Mouse;
|
extern FMouse *Mouse;
|
||||||
extern FInputDevice *Keyboard;
|
extern FKeyboard *Keyboard;
|
||||||
|
|
||||||
bool VidResizing;
|
bool VidResizing;
|
||||||
|
|
||||||
|
@ -153,13 +153,6 @@ LPDIRECTINPUT g_pdi3;
|
||||||
|
|
||||||
static LPDIRECTINPUTDEVICE8 g_pJoy;
|
static LPDIRECTINPUTDEVICE8 g_pJoy;
|
||||||
|
|
||||||
// These can also be earlier IDirectInputDevice interfaces.
|
|
||||||
// Since IDirectInputDevice8 just added new methods to it
|
|
||||||
// without rearranging the old ones, I just maintain one
|
|
||||||
// pointer for each device instead of two.
|
|
||||||
|
|
||||||
static LPDIRECTINPUTDEVICE8 g_pKey;
|
|
||||||
|
|
||||||
TArray<GUIDName> JoystickNames;
|
TArray<GUIDName> JoystickNames;
|
||||||
|
|
||||||
static DIDEVCAPS JoystickCaps;
|
static DIDEVCAPS JoystickCaps;
|
||||||
|
@ -304,30 +297,7 @@ static FBaseCVar * const JoyConfigVars[] =
|
||||||
};
|
};
|
||||||
|
|
||||||
static BYTE KeyState[256];
|
static BYTE KeyState[256];
|
||||||
/*static BYTE DIKState[2][NUM_KEYS];
|
|
||||||
static int ActiveDIKState;
|
|
||||||
|
|
||||||
|
|
||||||
static void FlushDIKState (int low=0, int high=NUM_KEYS-1)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
event_t event;
|
|
||||||
BYTE *state = DIKState[ActiveDIKState];
|
|
||||||
|
|
||||||
memset (&event, 0, sizeof(event));
|
|
||||||
event.type = EV_KeyUp;
|
|
||||||
for (i = low; i <= high; ++i)
|
|
||||||
{
|
|
||||||
if (state[i])
|
|
||||||
{
|
|
||||||
state[i] = 0;
|
|
||||||
event.data1 = i;
|
|
||||||
event.data2 = i < 256 ? Convert[i] : 0;
|
|
||||||
D_PostEvent (&event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
extern int chatmodeon;
|
extern int chatmodeon;
|
||||||
|
|
||||||
static void I_CheckGUICapture ()
|
static void I_CheckGUICapture ()
|
||||||
|
@ -346,9 +316,9 @@ static void I_CheckGUICapture ()
|
||||||
if (wantCapt != GUICapture)
|
if (wantCapt != GUICapture)
|
||||||
{
|
{
|
||||||
GUICapture = wantCapt;
|
GUICapture = wantCapt;
|
||||||
if (wantCapt)
|
if (wantCapt && Keyboard != NULL)
|
||||||
{
|
{
|
||||||
// FlushDIKState ();
|
Keyboard->AllKeysUp();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -408,18 +378,11 @@ LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case WM_KILLFOCUS:
|
case WM_KILLFOCUS:
|
||||||
if (g_pKey) g_pKey->Unacquire ();
|
|
||||||
|
|
||||||
// FlushDIKState ();
|
|
||||||
HaveFocus = false;
|
HaveFocus = false;
|
||||||
I_CheckNativeMouse (true); // Make sure mouse gets released right away
|
I_CheckNativeMouse (true); // Make sure mouse gets released right away
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WM_SETFOCUS:
|
case WM_SETFOCUS:
|
||||||
if (g_pKey)
|
|
||||||
{
|
|
||||||
g_pKey->Acquire();
|
|
||||||
}
|
|
||||||
HaveFocus = true;
|
HaveFocus = true;
|
||||||
I_CheckNativeMouse (false);
|
I_CheckNativeMouse (false);
|
||||||
break;
|
break;
|
||||||
|
@ -494,45 +457,6 @@ LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
if (message == WM_KEYUP)
|
|
||||||
{
|
|
||||||
event.type = EV_KeyUp;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (lParam & 0x40000000)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
event.type = EV_KeyDown;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (wParam)
|
|
||||||
{
|
|
||||||
case VK_PAUSE:
|
|
||||||
event.data1 = KEY_PAUSE;
|
|
||||||
break;
|
|
||||||
case VK_TAB:
|
|
||||||
event.data1 = DIK_TAB;
|
|
||||||
event.data2 = '\t';
|
|
||||||
break;
|
|
||||||
case VK_NUMLOCK:
|
|
||||||
event.data1 = DIK_NUMLOCK;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (event.data1)
|
|
||||||
{
|
|
||||||
DIKState[ActiveDIKState][event.data1] = (event.type == EV_KeyDown);
|
|
||||||
D_PostEvent (&event);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WM_CHAR:
|
case WM_CHAR:
|
||||||
|
|
|
@ -84,6 +84,36 @@ protected:
|
||||||
WORD ButtonState; // bit mask of current button states (1=down, 0=up)
|
WORD ButtonState; // bit mask of current button states (1=down, 0=up)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class FKeyboard : public FInputDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FKeyboard();
|
||||||
|
~FKeyboard();
|
||||||
|
|
||||||
|
void AllKeysUp();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool CheckAndSetKey(int keynum, INTBOOL down);
|
||||||
|
void PostKeyEvent(int keynum, INTBOOL down, bool foreground);
|
||||||
|
};
|
||||||
|
|
||||||
void I_StartupMouse();
|
void I_StartupMouse();
|
||||||
void I_CheckNativeMouse(bool prefer_native);
|
void I_CheckNativeMouse(bool prefer_native);
|
||||||
void I_StartupKeyboard();
|
void I_StartupKeyboard();
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
// TYPES -------------------------------------------------------------------
|
// TYPES -------------------------------------------------------------------
|
||||||
|
|
||||||
class FDInputKeyboard : public FInputDevice
|
class FDInputKeyboard : public FKeyboard
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FDInputKeyboard();
|
FDInputKeyboard();
|
||||||
|
@ -35,23 +35,20 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
LPDIRECTINPUTDEVICE8 Device;
|
LPDIRECTINPUTDEVICE8 Device;
|
||||||
BYTE KeyStates[256/8];
|
};
|
||||||
|
|
||||||
int CheckKey(int keynum) const
|
class FRawKeyboard : public FKeyboard
|
||||||
{
|
{
|
||||||
return KeyStates[keynum >> 3] & (1 << (keynum & 7));
|
public:
|
||||||
}
|
FRawKeyboard();
|
||||||
void SetKey(int keynum, bool down)
|
~FRawKeyboard();
|
||||||
{
|
|
||||||
if (down)
|
bool GetDevice();
|
||||||
{
|
void ProcessInput();
|
||||||
KeyStates[keynum >> 3] |= 1 << (keynum & 7);
|
bool WndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result);
|
||||||
}
|
|
||||||
else
|
protected:
|
||||||
{
|
USHORT E1Prefix;
|
||||||
KeyStates[keynum >> 3] &= ~(1 << (keynum & 7));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
|
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
|
||||||
|
@ -71,7 +68,7 @@ extern bool HaveFocus;
|
||||||
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
||||||
|
|
||||||
// Convert DIK_* code to ASCII using Qwerty keymap
|
// Convert DIK_* code to ASCII using Qwerty keymap
|
||||||
static const BYTE Convert [256] =
|
static const BYTE Convert[256] =
|
||||||
{
|
{
|
||||||
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
// 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
|
0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 8, 9, // 0
|
||||||
|
@ -94,13 +91,163 @@ static const BYTE Convert [256] =
|
||||||
|
|
||||||
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
||||||
|
|
||||||
FInputDevice *Keyboard;
|
FKeyboard *Keyboard;
|
||||||
|
|
||||||
// Set this to false to make keypad-enter a usable separate key.
|
// Set this to false to make keypad-enter a usable separate key.
|
||||||
CVAR (Bool, k_mergekeys, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
CVAR (Bool, k_mergekeys, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
|
|
||||||
// CODE --------------------------------------------------------------------
|
// CODE --------------------------------------------------------------------
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FKeyboard - Constructor
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FKeyboard::FKeyboard()
|
||||||
|
{
|
||||||
|
memset(KeyStates, 0, sizeof(KeyStates));
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FKeyboard - Destructor
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FKeyboard::~FKeyboard()
|
||||||
|
{
|
||||||
|
AllKeysUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FKeyboard :: CheckAndSetKey
|
||||||
|
//
|
||||||
|
// Returns true if the key was already in the desired, false if it wasn't.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
bool FKeyboard::CheckAndSetKey(int keynum, INTBOOL down)
|
||||||
|
{
|
||||||
|
BYTE *statebyte = &KeyStates[keynum >> 3];
|
||||||
|
BYTE mask = 1 << (keynum & 7);
|
||||||
|
if (down)
|
||||||
|
{
|
||||||
|
if (*statebyte & mask)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
*statebyte |= mask;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (*statebyte & mask)
|
||||||
|
{
|
||||||
|
*statebyte &= ~mask;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FKeyboard :: AllKeysUp
|
||||||
|
//
|
||||||
|
// For every key currently marked as down, send a key up event and clear it.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void FKeyboard::AllKeysUp()
|
||||||
|
{
|
||||||
|
event_t ev = { 0 };
|
||||||
|
ev.type = EV_KeyUp;
|
||||||
|
|
||||||
|
for (int i = 0; i < 256/8; ++i)
|
||||||
|
{
|
||||||
|
if (KeyStates[i] != 0)
|
||||||
|
{
|
||||||
|
BYTE states = KeyStates[i];
|
||||||
|
int j = 0;
|
||||||
|
KeyStates[i] = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (states & 1)
|
||||||
|
{
|
||||||
|
ev.data1 = (i << 3) + j;
|
||||||
|
ev.data2 = Convert[ev.data1];
|
||||||
|
D_PostEvent(&ev);
|
||||||
|
}
|
||||||
|
states >>= 1;
|
||||||
|
++j;
|
||||||
|
}
|
||||||
|
while (states != 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FKeyboard :: PostKeyEvent
|
||||||
|
//
|
||||||
|
// Posts a keyboard event, but only if the state is different from what we
|
||||||
|
// currently think it is. (For instance, raw keyboard input sends key
|
||||||
|
// down events every time the key automatically repeats, so we want to
|
||||||
|
// discard those.)
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void FKeyboard::PostKeyEvent(int key, INTBOOL down, bool foreground)
|
||||||
|
{
|
||||||
|
event_t ev = { 0 };
|
||||||
|
|
||||||
|
// Printf("key=%02x down=%02x\n", key, down);
|
||||||
|
// "Merge" multiple keys that are considered to be the same. If the
|
||||||
|
// original unmerged key is down, it also needs to go up. (In case
|
||||||
|
// somebody was holding the key down when they changed this setting.)
|
||||||
|
if (k_mergekeys)
|
||||||
|
{
|
||||||
|
if (key == DIK_NUMPADENTER || key == DIK_RMENU || key == DIK_RCONTROL)
|
||||||
|
{
|
||||||
|
k_mergekeys = false;
|
||||||
|
PostKeyEvent(key, false, foreground);
|
||||||
|
k_mergekeys = true;
|
||||||
|
key &= 0x7F;
|
||||||
|
}
|
||||||
|
else if (key == DIK_RSHIFT)
|
||||||
|
{
|
||||||
|
k_mergekeys = false;
|
||||||
|
PostKeyEvent(key, false, foreground);
|
||||||
|
k_mergekeys = true;
|
||||||
|
key = DIK_LSHIFT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate the event, if appropriate.
|
||||||
|
if (down)
|
||||||
|
{
|
||||||
|
if (!foreground || GUICapture)
|
||||||
|
{ // Do not generate key down events if we are in the background
|
||||||
|
// or in "GUI Capture" mode.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ev.type = EV_KeyDown;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ev.type = EV_KeyUp;
|
||||||
|
}
|
||||||
|
if (CheckAndSetKey(key, down))
|
||||||
|
{ // Key is already down or up.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ev.data1 = key;
|
||||||
|
ev.data2 = Convert[key];
|
||||||
|
D_PostEvent(&ev);
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// FDInputKeyboard - Constructor
|
// FDInputKeyboard - Constructor
|
||||||
|
@ -110,7 +257,6 @@ CVAR (Bool, k_mergekeys, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
FDInputKeyboard::FDInputKeyboard()
|
FDInputKeyboard::FDInputKeyboard()
|
||||||
{
|
{
|
||||||
Device = NULL;
|
Device = NULL;
|
||||||
memset(KeyStates, 0, sizeof(KeyStates));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -199,10 +345,8 @@ void FDInputKeyboard::ProcessInput()
|
||||||
DIDEVICEOBJECTDATA od;
|
DIDEVICEOBJECTDATA od;
|
||||||
DWORD dwElements;
|
DWORD dwElements;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
int key;
|
|
||||||
bool foreground = (GetForegroundWindow() == Window);
|
bool foreground = (GetForegroundWindow() == Window);
|
||||||
|
|
||||||
event_t ev = { 0 };
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
DWORD cbObjectData = g_pdi3 ? sizeof(DIDEVICEOBJECTDATA_DX3) : sizeof(DIDEVICEOBJECTDATA);
|
DWORD cbObjectData = g_pdi3 ? sizeof(DIDEVICEOBJECTDATA_DX3) : sizeof(DIDEVICEOBJECTDATA);
|
||||||
|
@ -218,57 +362,9 @@ void FDInputKeyboard::ProcessInput()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
key = od.dwOfs;
|
if (od.dwOfs >= 1 && od.dwOfs <= 255)
|
||||||
// Printf("buffer ofs=%02x data=%02x\n", od.dwOfs, od.dwData);
|
|
||||||
if (key >= 1 && key <= 255)
|
|
||||||
{
|
{
|
||||||
if (k_mergekeys)
|
PostKeyEvent(od.dwOfs, od.dwData & 0x80, foreground);
|
||||||
{
|
|
||||||
// "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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -284,6 +380,192 @@ bool FDInputKeyboard::WndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FRawKeyboard - Constructor
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FRawKeyboard::FRawKeyboard()
|
||||||
|
{
|
||||||
|
E1Prefix = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FRawKeyboard - Destructor
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FRawKeyboard::~FRawKeyboard()
|
||||||
|
{
|
||||||
|
if (MyRegisterRawInputDevices != NULL)
|
||||||
|
{
|
||||||
|
RAWINPUTDEVICE rid;
|
||||||
|
rid.usUsagePage = HID_GENERIC_DESKTOP_PAGE;
|
||||||
|
rid.usUsage = HID_GDP_KEYBOARD;
|
||||||
|
rid.dwFlags = RIDEV_REMOVE;
|
||||||
|
rid.hwndTarget = NULL;
|
||||||
|
MyRegisterRawInputDevices(&rid, 1, sizeof(rid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FRawKeyboard :: GetDevice
|
||||||
|
//
|
||||||
|
// Ensure the API is present and we can listen for keyboard input.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
bool FRawKeyboard::GetDevice()
|
||||||
|
{
|
||||||
|
RAWINPUTDEVICE rid;
|
||||||
|
|
||||||
|
if (MyRegisterRawInputDevices == NULL)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
rid.usUsagePage = HID_GENERIC_DESKTOP_PAGE;
|
||||||
|
rid.usUsage = HID_GDP_KEYBOARD;
|
||||||
|
rid.dwFlags = RIDEV_INPUTSINK;
|
||||||
|
rid.hwndTarget = Window;
|
||||||
|
if (!MyRegisterRawInputDevices(&rid, 1, sizeof(rid)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FRawKeyboard :: ProcessInput
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void FRawKeyboard::ProcessInput()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FRawKeyboard :: WndProcHook
|
||||||
|
//
|
||||||
|
// Convert scan codes to DirectInput key codes. For the most part, this is
|
||||||
|
// straight forward: Scan codes without any prefix are passed unmodified.
|
||||||
|
// Scan codes with an 0xE0 prefix byte are generally passed by ORing them
|
||||||
|
// with 0x80. And scan codes with an 0xE1 prefix are the annowing Pause key
|
||||||
|
// which will generate another scan code that looks like Num Lock.
|
||||||
|
//
|
||||||
|
// This is a bit complicated only because the state of PC key codes is a bit
|
||||||
|
// of a mess. Keyboards may use simpler codes internally, but for the sake
|
||||||
|
// of compatibility, programs are presented with XT-compatible codes. This
|
||||||
|
// means that keys which were originally a shifted form of another key and
|
||||||
|
// were split off into a separate key all their own, or which were formerly
|
||||||
|
// a separate key and are now part of another key (most notable PrtScn and
|
||||||
|
// SysRq), will still generate code sequences that XT-era software will
|
||||||
|
// still perceive as the original sequences to use those keys.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
bool FRawKeyboard::WndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result)
|
||||||
|
{
|
||||||
|
if (message != WM_INPUT)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
BYTE buffer[40];
|
||||||
|
UINT size = sizeof(buffer);
|
||||||
|
int keycode;
|
||||||
|
|
||||||
|
if (MyGetRawInputData((HRAWINPUT)lParam, RID_INPUT, buffer, &size, sizeof(RAWINPUTHEADER)) > 0)
|
||||||
|
{
|
||||||
|
RAWINPUT *raw = (RAWINPUT *)buffer;
|
||||||
|
if (raw->header.dwType != RIM_TYPEKEYBOARD)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
keycode = raw->data.keyboard.MakeCode;
|
||||||
|
if (keycode == 0 && (raw->data.keyboard.Flags & RI_KEY_E0))
|
||||||
|
{ // Even if the make code is 0, we might still be able to extract a
|
||||||
|
// useful key from the message.
|
||||||
|
if (raw->data.keyboard.VKey >= VK_BROWSER_BACK && raw->data.keyboard.VKey <= VK_LAUNCH_APP2)
|
||||||
|
{
|
||||||
|
static const BYTE MediaKeys[VK_LAUNCH_APP2 - VK_BROWSER_BACK + 1] =
|
||||||
|
{
|
||||||
|
DIK_WEBBACK, DIK_WEBFORWARD, DIK_WEBREFRESH, DIK_WEBSTOP,
|
||||||
|
DIK_WEBSEARCH, DIK_WEBFAVORITES, DIK_WEBHOME,
|
||||||
|
|
||||||
|
DIK_MUTE, DIK_VOLUMEDOWN, DIK_VOLUMEUP,
|
||||||
|
DIK_NEXTTRACK, DIK_PREVTRACK, DIK_MEDIASTOP, DIK_PLAYPAUSE,
|
||||||
|
|
||||||
|
DIK_MAIL, DIK_MEDIASELECT, DIK_MYCOMPUTER, DIK_CALCULATOR
|
||||||
|
};
|
||||||
|
keycode = MediaKeys[raw->data.keyboard.VKey - VK_BROWSER_BACK];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (keycode < 1 || keycode > 0xFF)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (raw->data.keyboard.Flags & RI_KEY_E1)
|
||||||
|
{
|
||||||
|
E1Prefix = raw->data.keyboard.MakeCode;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (raw->data.keyboard.Flags & RI_KEY_E0)
|
||||||
|
{
|
||||||
|
if (keycode == DIK_LSHIFT || keycode == DIK_RSHIFT)
|
||||||
|
{ // Ignore fake shifts.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
keycode |= 0x80;
|
||||||
|
}
|
||||||
|
// The sequence for an unshifted pause is E1 1D 45 (E1 Prefix +
|
||||||
|
// Control + Num Lock).
|
||||||
|
if (E1Prefix)
|
||||||
|
{
|
||||||
|
if (E1Prefix == 0x1D && keycode == DIK_NUMLOCK)
|
||||||
|
{
|
||||||
|
keycode = DIK_PAUSE;
|
||||||
|
E1Prefix = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
E1Prefix = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If you press Ctrl+Pause, the keyboard sends the Break make code
|
||||||
|
// E0 46 instead of the Pause make code.
|
||||||
|
if (keycode == 0xC6)
|
||||||
|
{
|
||||||
|
keycode = DIK_PAUSE;
|
||||||
|
}
|
||||||
|
// If you press Ctrl+PrtScn (to get SysRq), the keyboard sends
|
||||||
|
// the make code E0 37. If you press PrtScn without any modifiers,
|
||||||
|
// it sends E0 2A E0 37. And if you press Alt+PrtScn, it sends 54
|
||||||
|
// (which is undefined in the charts I can find.)
|
||||||
|
if (keycode == 0x54)
|
||||||
|
{
|
||||||
|
keycode = DIK_SYSRQ;
|
||||||
|
}
|
||||||
|
// If you press any keys in the island between the main keyboard
|
||||||
|
// and the numeric keypad with Num Lock turned on, they generate
|
||||||
|
// a fake shift before their actual codes. They do not generate this
|
||||||
|
// fake shift if Num Lock is off. We unconditionally discard fake
|
||||||
|
// shifts above, so we don't need to do anything special for these,
|
||||||
|
// since they are also prefixed by E0 so we can tell them apart from
|
||||||
|
// their keypad counterparts.
|
||||||
|
|
||||||
|
// Okay, we're done translating the keycode. Post it (or ignore it.)
|
||||||
|
PostKeyEvent(keycode, !(raw->data.keyboard.Flags & RI_KEY_BREAK),
|
||||||
|
GET_RAWINPUT_CODE_WPARAM(wParam) == RIM_INPUT);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// I_StartupKeyboard
|
// I_StartupKeyboard
|
||||||
|
@ -292,6 +574,12 @@ bool FDInputKeyboard::WndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM
|
||||||
|
|
||||||
void I_StartupKeyboard()
|
void I_StartupKeyboard()
|
||||||
{
|
{
|
||||||
|
Keyboard = new FRawKeyboard;
|
||||||
|
if (Keyboard->GetDevice())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
delete Keyboard;
|
||||||
Keyboard = new FDInputKeyboard;
|
Keyboard = new FDInputKeyboard;
|
||||||
if (!Keyboard->GetDevice())
|
if (!Keyboard->GetDevice())
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue