Skip to content

Instantly share code, notes, and snippets.

@christianrondeau
Last active August 29, 2015 14:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save christianrondeau/bdd03a3dc32a7a718d62 to your computer and use it in GitHub Desktop.
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
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