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.

KeyEventArgsExt.cs 6.0 KiB

8 月之前
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. // This code is distributed under MIT license.
  2. // Copyright (c) 2015 George Mamaladze
  3. // See license.txt or https://mit-license.org/
  4. using System;
  5. using System.Runtime.InteropServices;
  6. using System.Windows.Forms;
  7. using Gma.System.MouseKeyHook.Implementation;
  8. using Gma.System.MouseKeyHook.WinApi;
  9. namespace Gma.System.MouseKeyHook
  10. {
  11. /// <summary>
  12. /// Provides extended argument data for the <see cref='KeyListener.KeyDown' /> or
  13. /// <see cref='KeyListener.KeyUp' /> event.
  14. /// </summary>
  15. public class KeyEventArgsExt : KeyEventArgs
  16. {
  17. /// <summary>
  18. /// Initializes a new instance of the <see cref="KeyEventArgsExt" /> class.
  19. /// </summary>
  20. /// <param name="keyData"></param>
  21. public KeyEventArgsExt(Keys keyData)
  22. : base(keyData)
  23. {
  24. }
  25. internal KeyEventArgsExt(Keys keyData, int scanCode, int timestamp, bool isKeyDown, bool isKeyUp,
  26. bool isExtendedKey)
  27. : this(keyData)
  28. {
  29. ScanCode = scanCode;
  30. Timestamp = timestamp;
  31. IsKeyDown = isKeyDown;
  32. IsKeyUp = isKeyUp;
  33. IsExtendedKey = isExtendedKey;
  34. }
  35. /// <summary>
  36. /// The hardware scan code.
  37. /// </summary>
  38. public int ScanCode { get; }
  39. /// <summary>
  40. /// The system tick count of when the event occurred.
  41. /// </summary>
  42. public int Timestamp { get; }
  43. /// <summary>
  44. /// True if event signals key down..
  45. /// </summary>
  46. public bool IsKeyDown { get; }
  47. /// <summary>
  48. /// True if event signals key up.
  49. /// </summary>
  50. public bool IsKeyUp { get; }
  51. /// <summary>
  52. /// True if event signals, that the key is an extended key
  53. /// </summary>
  54. public bool IsExtendedKey { get; }
  55. internal static KeyEventArgsExt FromRawDataApp(CallbackData data)
  56. {
  57. var wParam = data.WParam;
  58. var lParam = data.LParam;
  59. //http://msdn.microsoft.com/en-us/library/ms644984(v=VS.85).aspx
  60. const uint maskKeydown = 0x40000000; // for bit 30
  61. const uint maskKeyup = 0x80000000; // for bit 31
  62. const uint maskExtendedKey = 0x1000000; // for bit 24
  63. var timestamp = Environment.TickCount;
  64. var flags = (uint) lParam.ToInt64();
  65. //bit 30 Specifies the previous key state. The value is 1 if the key is down before the message is sent; it is 0 if the key is up.
  66. var wasKeyDown = (flags & maskKeydown) > 0;
  67. //bit 31 Specifies the transition state. The value is 0 if the key is being pressed and 1 if it is being released.
  68. var isKeyReleased = (flags & maskKeyup) > 0;
  69. //bit 24 Specifies the extended key state. The value is 1 if the key is an extended key, otherwise the value is 0.
  70. var isExtendedKey = (flags & maskExtendedKey) > 0;
  71. var keyData = AppendModifierStates((Keys) wParam);
  72. var scanCode = (int) (((flags & 0x10000) | (flags & 0x20000) | (flags & 0x40000) | (flags & 0x80000) |
  73. (flags & 0x100000) | (flags & 0x200000) | (flags & 0x400000) | (flags & 0x800000)) >>
  74. 16);
  75. var isKeyDown = !isKeyReleased;
  76. var isKeyUp = wasKeyDown && isKeyReleased;
  77. return new KeyEventArgsExt(keyData, scanCode, timestamp, isKeyDown, isKeyUp, isExtendedKey);
  78. }
  79. internal static KeyEventArgsExt FromRawDataGlobal(CallbackData data)
  80. {
  81. var wParam = data.WParam;
  82. var lParam = data.LParam;
  83. var keyboardHookStruct =
  84. (KeyboardHookStruct) Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
  85. var keyData = AppendModifierStates((Keys) keyboardHookStruct.VirtualKeyCode);
  86. var keyCode = (int) wParam;
  87. var isKeyDown = keyCode == Messages.WM_KEYDOWN || keyCode == Messages.WM_SYSKEYDOWN;
  88. var isKeyUp = keyCode == Messages.WM_KEYUP || keyCode == Messages.WM_SYSKEYUP;
  89. const uint maskExtendedKey = 0x1;
  90. var isExtendedKey = (keyboardHookStruct.Flags & maskExtendedKey) > 0;
  91. return new KeyEventArgsExt(keyData, keyboardHookStruct.ScanCode, keyboardHookStruct.Time, isKeyDown,
  92. isKeyUp, isExtendedKey);
  93. }
  94. // # It is not possible to distinguish Keys.LControlKey and Keys.RControlKey when they are modifiers
  95. // Check for Keys.Control instead
  96. // Same for Shift and Alt(Menu)
  97. // See more at http://www.tech-archive.net/Archive/DotNet/microsoft.public.dotnet.framework.windowsforms/2008-04/msg00127.html #
  98. // A shortcut to make life easier
  99. private static bool CheckModifier(int vKey)
  100. {
  101. return (KeyboardNativeMethods.GetKeyState(vKey) & 0x8000) > 0;
  102. }
  103. private static Keys AppendModifierStates(Keys keyData)
  104. {
  105. // Is Control being held down?
  106. var control = CheckModifier(KeyboardNativeMethods.VK_CONTROL);
  107. // Is Shift being held down?
  108. var shift = CheckModifier(KeyboardNativeMethods.VK_SHIFT);
  109. // Is Alt being held down?
  110. var alt = CheckModifier(KeyboardNativeMethods.VK_MENU);
  111. // Windows keys
  112. // # combine LWin and RWin key with other keys will potentially corrupt the data
  113. // notable F5 | Keys.LWin == F12, see https://globalmousekeyhook.codeplex.com/workitem/1188
  114. // and the KeyEventArgs.KeyData don't recognize combined data either
  115. // Function (Fn) key
  116. // # CANNOT determine state due to conversion inside keyboard
  117. // See http://en.wikipedia.org/wiki/Fn_key#Technical_details #
  118. return keyData |
  119. (control ? Keys.Control : Keys.None) |
  120. (shift ? Keys.Shift : Keys.None) |
  121. (alt ? Keys.Alt : Keys.None);
  122. }
  123. }
  124. }