You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
398 lines
11 KiB
398 lines
11 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
|
|
#include "stdafx.h" |
|
#include "Keyboard.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include <tier0/memdbgon.h> |
|
|
|
|
|
// |
|
// Defines key state bit masks. |
|
// |
|
#define KEYSTATE_DOWN 0x0000FFFF |
|
#define KEYSTATE_IMPULSE_DOWN 0x00010000 |
|
#define KEYSTATE_IMPULSE_UP 0x00020000 |
|
|
|
|
|
// |
|
// List of allowed modifier keys and their associated bit masks. |
|
// |
|
static KeyMap_t ModifierKeyTable[] = |
|
{ |
|
{ VK_SHIFT, KEY_MOD_SHIFT, 0 }, |
|
{ VK_CONTROL, KEY_MOD_CONTROL, 0 }, |
|
{ VK_MENU, KEY_MOD_ALT, 0 } |
|
}; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Constructor. |
|
//----------------------------------------------------------------------------- |
|
CKeyboard::CKeyboard(void) |
|
{ |
|
g_uKeyMaps = 0; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Destructor. |
|
//----------------------------------------------------------------------------- |
|
CKeyboard::~CKeyboard(void) |
|
{ |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Adds a key binding to the |
|
// Input : uChar - The virtual keycode of the primary key that must be held down. |
|
// uModifierKeys - Bitflags specifying which modifier keys must be |
|
// held down along with the key specified by uChar. |
|
// uLogicalKey - An application-specific value that indicates which |
|
// logical function |
|
//----------------------------------------------------------------------------- |
|
void CKeyboard::AddKeyMap(unsigned int uChar, unsigned int uModifierKeys, unsigned int uLogicalKey) |
|
{ |
|
g_uKeyMap[g_uKeyMaps].uChar = uChar; |
|
g_uKeyMap[g_uKeyMaps].uModifierKeys = uModifierKeys; |
|
g_uKeyMap[g_uKeyMaps].uLogicalKey = uLogicalKey; |
|
g_uKeyMaps++; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Clears the KEYSTATE_IMPULSE_UP and KEYSTATE_IMPULSE_DOWN flags from |
|
// all physical and logical keys. |
|
//----------------------------------------------------------------------------- |
|
void CKeyboard::ClearImpulseFlags(void) |
|
{ |
|
int nKey; |
|
|
|
// |
|
// Clear the impulse flags for all the physical keys. |
|
// |
|
for (nKey = 0; nKey < sizeof(g_uPhysicalKeyState) / sizeof(g_uPhysicalKeyState[0]); nKey++) |
|
{ |
|
g_uPhysicalKeyState[nKey] &= ~(KEYSTATE_IMPULSE_DOWN | KEYSTATE_IMPULSE_UP); |
|
} |
|
|
|
// |
|
// Clear the impulse flags for all the logical keys. |
|
// |
|
for (nKey = 0; nKey < sizeof(g_uLogicalKeyState) / sizeof(g_uLogicalKeyState[0]); nKey++) |
|
{ |
|
g_uLogicalKeyState[nKey] &= ~(KEYSTATE_IMPULSE_DOWN | KEYSTATE_IMPULSE_UP); |
|
} |
|
} |
|
|
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Zeros out the key state for all physical and logical keys. |
|
//----------------------------------------------------------------------------- |
|
void CKeyboard::ClearKeyStates(void) |
|
{ |
|
int nKey; |
|
|
|
// |
|
// Clear the physical key states. |
|
// |
|
for (nKey = 0; nKey < sizeof(g_uPhysicalKeyState) / sizeof(g_uPhysicalKeyState[0]); nKey++) |
|
{ |
|
g_uPhysicalKeyState[nKey] = 0; |
|
} |
|
|
|
// |
|
// Clear the logical key states. |
|
// |
|
for (nKey = 0; nKey < sizeof(g_uLogicalKeyState) / sizeof(g_uLogicalKeyState[0]); nKey++) |
|
{ |
|
g_uLogicalKeyState[nKey] = 0; |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Gets a floating point value indicating about how long the logical |
|
// key has been held down during this sample period. |
|
// Input : uLogicalKey - Logical key to check. |
|
// Output : Returns one of the following values: |
|
// 0.25 if a key was pressed and released during the sample period, |
|
// 0.5 if it was pressed and held, |
|
// 0 if held then released, and |
|
// 1.0 if held for the entire time. |
|
//----------------------------------------------------------------------------- |
|
float CKeyboard::GetKeyScale(unsigned int uLogicalKey) |
|
{ |
|
if (uLogicalKey >= MAX_LOGICAL_KEYS) |
|
{ |
|
return(0); |
|
} |
|
|
|
unsigned int uKeyState = g_uLogicalKeyState[uLogicalKey]; |
|
|
|
bool bImpulseDown = (uKeyState & KEYSTATE_IMPULSE_DOWN) != 0; |
|
bool bImpulseUp = (uKeyState & KEYSTATE_IMPULSE_UP) != 0; |
|
bool bDown = (uKeyState & KEYSTATE_DOWN) != 0; |
|
float fValue = 0; |
|
|
|
// |
|
// If we have a leading edge and no trailing edge, the key should be down. |
|
// |
|
if (bImpulseDown && !bImpulseUp) |
|
{ |
|
if (bDown) |
|
{ |
|
// |
|
// Pressed and held this frame. |
|
// |
|
fValue = 0.5; |
|
} |
|
} |
|
|
|
// |
|
// If we have a trailing edge and no leading edge, the key should be up. |
|
// |
|
if (bImpulseUp && !bImpulseDown) |
|
{ |
|
if (!bDown) |
|
{ |
|
// |
|
// Released this frame. |
|
// |
|
fValue = 0; |
|
} |
|
} |
|
|
|
// |
|
// If we have neither a leading edge nor a trailing edge, the key was either |
|
// up the whole frame or down the whole frame. |
|
// |
|
if (!bImpulseDown && !bImpulseUp) |
|
{ |
|
if (bDown) |
|
{ |
|
// |
|
// Held the entire frame |
|
// |
|
fValue = 1.0; |
|
} |
|
else |
|
{ |
|
// |
|
// Up the entire frame. |
|
// |
|
fValue = 0; |
|
} |
|
} |
|
|
|
// |
|
// If we have both a leading and trailing edge, it was either released and repressed |
|
// this frame, or pressed and released this frame. |
|
// |
|
if (bImpulseDown && bImpulseUp) |
|
{ |
|
if (bDown) |
|
{ |
|
// |
|
// Released and re-pressed this frame. |
|
// |
|
fValue = 0.75; |
|
} |
|
else |
|
{ |
|
// |
|
// Pressed and released this frame. |
|
// |
|
fValue = 0.25; |
|
} |
|
} |
|
|
|
return fValue; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Returns the bit mask associated with the given modifier key. |
|
// Input : uModifierKey - The virtual key code corresponding to the modifier key. |
|
// Output : The modifier key's bitmask. |
|
//----------------------------------------------------------------------------- |
|
unsigned int CKeyboard::GetModifierKeyBit(unsigned int uChar) |
|
{ |
|
for (int nKey = 0; nKey < sizeof(ModifierKeyTable) / sizeof(ModifierKeyTable[0]); nKey++) |
|
{ |
|
if (ModifierKeyTable[nKey].uChar == uChar) |
|
{ |
|
return(ModifierKeyTable[nKey].uModifierKeys); |
|
} |
|
} |
|
|
|
return(0); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Checks to see if all of the modifier keys specified by bits in uModifierKeys |
|
// are currently held down. |
|
// Input : uModifierKeys - Contains bits indicating which modifier keys to check: |
|
// KEY_MOD_SHIFT |
|
// KEY_MOD_CONTROL |
|
// KEY_MOD_ALT |
|
// Output : Returns true on success, false on failure. |
|
//----------------------------------------------------------------------------- |
|
bool CKeyboard::IsKeyPressed(unsigned int uChar, unsigned int uModifierKeys) |
|
{ |
|
if (!(g_uPhysicalKeyState[uChar] & KEYSTATE_DOWN)) |
|
{ |
|
return(false); |
|
} |
|
|
|
bool bKeyPressed = true; |
|
|
|
for (int nKey = 0; nKey < sizeof(ModifierKeyTable) / sizeof(ModifierKeyTable[0]); nKey++) |
|
{ |
|
if (g_uPhysicalKeyState[ModifierKeyTable[nKey].uChar] & KEYSTATE_DOWN) |
|
{ |
|
if (!(uModifierKeys & ModifierKeyTable[nKey].uModifierKeys)) |
|
{ |
|
bKeyPressed = false; |
|
} |
|
} |
|
else if (uModifierKeys & ModifierKeyTable[nKey].uModifierKeys) |
|
{ |
|
bKeyPressed = false; |
|
} |
|
} |
|
|
|
return(bKeyPressed); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Determines whether a key is an allowed modifier key, ie, whether it |
|
// can be used in conjunction with other keys when performing key |
|
// bindings. |
|
// Input : uChar - Virtual key to check. |
|
// Output : Returns true if this key is a modifier key, false if not. |
|
//----------------------------------------------------------------------------- |
|
bool CKeyboard::IsModifierKey(unsigned int uChar) |
|
{ |
|
return((uChar == VK_SHIFT) || (uChar == VK_CONTROL) || (uChar == VK_MENU)); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Given a key press/release event, updates the status of all logical |
|
// keys. |
|
// Input : uChar - The key whose state has changed. |
|
// bPressed - True if the key was pressed, false if it was released. |
|
//----------------------------------------------------------------------------- |
|
void CKeyboard::UpdateLogicalKeys(unsigned int uChar, bool bPressed) |
|
{ |
|
// |
|
// Determine whether the key is a modifier key. If so, find its modifier bit. |
|
// |
|
bool bIsModifierKey = IsModifierKey(uChar); |
|
unsigned int uModifierKeyBit = 0; |
|
if (bIsModifierKey) |
|
{ |
|
uModifierKeyBit = GetModifierKeyBit(uChar); |
|
} |
|
|
|
// |
|
// For every key in the keymap that depends upon this physical key, update |
|
// the state of the corresponding logical key based on this event. |
|
// |
|
for (unsigned int nKey = 0; nKey < g_uKeyMaps; nKey++) |
|
{ |
|
unsigned int uPhysicalKey = g_uKeyMap[nKey].uChar; |
|
unsigned int uLogicalKey = g_uKeyMap[nKey].uLogicalKey; |
|
unsigned int uModifierKeys = g_uKeyMap[nKey].uModifierKeys; |
|
|
|
if ((uPhysicalKey == uChar) || (uModifierKeys & uModifierKeyBit)) |
|
{ |
|
// |
|
// Check the state of all modifier keys to which this logical key |
|
// is bound to determine whether the logical key is pressed or not. |
|
// |
|
bool bLogicalKeyPressed = IsKeyPressed(g_uKeyMap[nKey].uChar, g_uKeyMap[nKey].uModifierKeys); |
|
|
|
// |
|
// Update the logical key state. |
|
// |
|
if (bPressed) |
|
{ |
|
if (bLogicalKeyPressed) |
|
{ |
|
if (!(g_uLogicalKeyState[uLogicalKey] & KEYSTATE_DOWN)) |
|
{ |
|
g_uLogicalKeyState[uLogicalKey] |= KEYSTATE_IMPULSE_DOWN; |
|
} |
|
|
|
g_uLogicalKeyState[uLogicalKey]++; |
|
} |
|
} |
|
else |
|
{ |
|
if (g_uLogicalKeyState[uLogicalKey] & KEYSTATE_DOWN) |
|
{ |
|
g_uLogicalKeyState[uLogicalKey]--; |
|
} |
|
|
|
if (!(g_uLogicalKeyState[uLogicalKey] & KEYSTATE_DOWN)) |
|
{ |
|
g_uLogicalKeyState[uLogicalKey] |= KEYSTATE_IMPULSE_UP; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Called by the client when a WM_KEYDOWN message is received. |
|
// Input : Per CWnd::OnKeyDown. |
|
//----------------------------------------------------------------------------- |
|
void CKeyboard::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) |
|
{ |
|
if ((!(nFlags & 0x4000)) || (!(g_uPhysicalKeyState[nChar] & KEYSTATE_DOWN))) |
|
{ |
|
g_uPhysicalKeyState[nChar] |= KEYSTATE_DOWN; |
|
g_uPhysicalKeyState[nChar] |= KEYSTATE_IMPULSE_DOWN; |
|
|
|
UpdateLogicalKeys(nChar, true); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Called by the client when a WM_KEYUP message is received. |
|
// Input : Per CWnd::OnKeyDown. |
|
//----------------------------------------------------------------------------- |
|
void CKeyboard::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) |
|
{ |
|
if (g_uPhysicalKeyState[nChar] & KEYSTATE_DOWN) |
|
{ |
|
g_uPhysicalKeyState[nChar] &= ~KEYSTATE_DOWN; |
|
} |
|
|
|
g_uPhysicalKeyState[nChar] |= KEYSTATE_IMPULSE_UP; |
|
|
|
UpdateLogicalKeys(nChar, false); |
|
} |
|
|
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Deletes all key bindings. |
|
//----------------------------------------------------------------------------- |
|
void CKeyboard::RemoveAllKeyMaps(void) |
|
{ |
|
g_uKeyMaps = 0; |
|
} |
|
|
|
|