|
|
//========= 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; }
|