summaryrefslogtreecommitdiff
path: root/hammer/keyboard.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'hammer/keyboard.cpp')
-rw-r--r--hammer/keyboard.cpp398
1 files changed, 398 insertions, 0 deletions
diff --git a/hammer/keyboard.cpp b/hammer/keyboard.cpp
new file mode 100644
index 0000000..764bfdd
--- /dev/null
+++ b/hammer/keyboard.cpp
@@ -0,0 +1,398 @@
+//========= 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;
+}
+