Last active
August 29, 2015 14:10
-
-
Save christianrondeau/bdd03a3dc32a7a718d62 to your computer and use it in GitHub Desktop.
A failing example of hooking `Win` + `Tab`: Behaves as if the `Win` key was still down
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Diagnostics; | |
using System.Runtime.InteropServices; | |
using System.Windows.Forms; | |
namespace WinTabHookExample | |
{ | |
public static class Program | |
{ | |
[StructLayout(LayoutKind.Sequential)] | |
public struct Kbdllhookstruct | |
{ | |
public int VkCode; | |
public int ScanCode; | |
public int Flags; | |
public int Time; | |
public IntPtr Extra; | |
} | |
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] | |
private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId); | |
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] | |
[return: MarshalAs(UnmanagedType.Bool)] | |
private static extern bool UnhookWindowsHookEx(IntPtr hhk); | |
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] | |
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam); | |
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] | |
private static extern IntPtr GetModuleHandle(string lpModuleName); | |
private const int HC_ACTION = 0; | |
private const int WH_KEYBOARD_LL = 13; | |
private const int WM_KEYDOWN = 0x0100; | |
private const int WM_KEYUP = 0x0101; | |
private const int VK_LWIN = 0x5B; | |
private const int VK_TAB = 0x09; | |
private static IntPtr _hookID = IntPtr.Zero; | |
private static bool _isWinDown; | |
private static bool _isWinTabDetected; | |
private static int _winTabPressCounter; | |
private static Form1 _mainForm; | |
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam); | |
[STAThread] | |
static void Main() | |
{ | |
try | |
{ | |
var proc = new LowLevelKeyboardProc(HookCallback); | |
using (var curProcess = Process.GetCurrentProcess()) | |
{ | |
using (var curModule = curProcess.MainModule) | |
{ | |
_hookID = SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0); | |
} | |
} | |
Application.EnableVisualStyles(); | |
Application.SetCompatibleTextRenderingDefault(false); | |
_mainForm = new Form1 {Width = 640}; | |
Application.Run(_mainForm); | |
} | |
finally | |
{ | |
UnhookWindowsHookEx(_hookID); | |
} | |
} | |
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) | |
{ | |
if (nCode != HC_ACTION) | |
return CallNextHookEx(_hookID, nCode, wParam, lParam); | |
var keyInfo = (Kbdllhookstruct)Marshal.PtrToStructure(lParam, typeof(Kbdllhookstruct)); | |
if (keyInfo.VkCode == VK_LWIN) | |
{ | |
if (wParam == (IntPtr)WM_KEYDOWN) | |
{ | |
_isWinDown = true; | |
} | |
else | |
{ | |
_isWinDown = false; | |
if (_isWinTabDetected) | |
{ | |
_isWinTabDetected = false; | |
return (IntPtr)1; | |
} | |
} | |
} | |
else if (keyInfo.VkCode == VK_TAB && _isWinDown) | |
{ | |
_isWinTabDetected = true; | |
if (wParam == (IntPtr)WM_KEYDOWN) | |
{ | |
return (IntPtr)1; | |
} | |
else | |
{ | |
_isWinTabDetected = true; | |
_mainForm.Text = "Win + Tab was pressed " + (++_winTabPressCounter) + " times"; | |
return (IntPtr)1; | |
} | |
} | |
return CallNextHookEx(_hookID, nCode, wParam, lParam); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment