// This code is distributed under MIT license. // Copyright (c) 2015 George Mamaladze // See license.txt or https://mit-license.org/ using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; using Gma.System.MouseKeyHook.WinApi; namespace Gma.System.MouseKeyHook.Implementation { /// /// Contains a snapshot of a keyboard state at certain moment and provides methods /// of querying whether specific keys are pressed or locked. /// /// /// This class is basically a managed wrapper of GetKeyboardState API function /// http://msdn.microsoft.com/en-us/library/ms646299 /// public class KeyboardState { private readonly byte[] m_KeyboardStateNative; private KeyboardState(byte[] keyboardStateNative) { m_KeyboardStateNative = keyboardStateNative; } /// /// Makes a snapshot of a keyboard state to the moment of call and returns an /// instance of class. /// /// An instance of class representing a snapshot of keyboard state at certain moment. public static KeyboardState GetCurrent() { var keyboardStateNative = new byte[256]; KeyboardNativeMethods.GetKeyboardState(keyboardStateNative); return new KeyboardState(keyboardStateNative); } internal byte[] GetNativeState() { return m_KeyboardStateNative; } /// /// Indicates whether specified key was down at the moment when snapshot was created or not. /// /// Key (corresponds to the virtual code of the key) /// true if key was down, false - if key was up. public bool IsDown(Keys key) { if ((int)key < 256) return IsDownRaw(key); if (key == Keys.Alt) return IsDownRaw(Keys.LMenu) || IsDownRaw(Keys.RMenu); if (key == Keys.Shift) return IsDownRaw(Keys.LShiftKey) || IsDownRaw(Keys.RShiftKey); if (key == Keys.Control) return IsDownRaw(Keys.LControlKey) || IsDownRaw(Keys.RControlKey); return false; } private bool IsDownRaw(Keys key) { var keyState = GetKeyState(key); var isDown = GetHighBit(keyState); return isDown; } /// /// Indicate weather specified key was toggled at the moment when snapshot was created or not. /// /// Key (corresponds to the virtual code of the key) /// /// true if toggle key like (CapsLock, NumLocke, etc.) was on. false if it was off. /// Ordinal (non toggle) keys return always false. /// public bool IsToggled(Keys key) { var keyState = GetKeyState(key); var isToggled = GetLowBit(keyState); return isToggled; } /// /// Indicates weather every of specified keys were down at the moment when snapshot was created. /// The method returns false if even one of them was up. /// /// Keys to verify whether they were down or not. /// true - all were down. false - at least one was up. public bool AreAllDown(IEnumerable keys) { return keys.All(IsDown); } private byte GetKeyState(Keys key) { var virtualKeyCode = (int) key; if (virtualKeyCode < 0 || virtualKeyCode > 255) throw new ArgumentOutOfRangeException("key", key, "The value must be between 0 and 255."); return m_KeyboardStateNative[virtualKeyCode]; } private static bool GetHighBit(byte value) { return value >> 7 != 0; } private static bool GetLowBit(byte value) { return (value & 1) != 0; } } }