Einar Egilsson

Instant Rimshot

Posted: Last updated:

It's been a while since I've written anything here, I've been working on my master project like crazy, have a 6 month old baby and so haven't had much time for programming pet projects. Tonight I spent a half hour making perhaps the most useless application I'll ever make. It's based on the single-serving website http://instantrimshot.com which only has one huge red button, if you press it a rimshot sound is played. I thought it might be fun to have that available as a keyboard shortcut in windows, and then I started wondering how it could be done in C#.

The only way to get a global keyboard working in .NET is by calling into the Win32 API. To register a global hotkey there is the aptly named function RegisterHotKey. That requires you to have a window handle however, and I wanted to make the application as simple as possible, so I used a lower level API call, SetWindowsHookEx which lets you get notified of all keyboard activity on the system. I then check what keys are pressed and when the combination Ctrl+Shift+I is pressed the sound is played. There is only one way to exit the app, and that is by pressing the keyboard combination Ctrl+Shift+Alt+I, that cleans up the hook before exiting. So, the code is shown below, you can download the source or just download the program itself. Enjoy!

using System; using System.IO; using System.Media; using System.Reflection; using System.Runtime.InteropServices; using System.Windows.Forms; class InstantRimshot { const int WH_KEYBOARD_LL = 13; const int WM_KEYDOWN = 0x100; delegate int Hook(int code, IntPtr wParam, IntPtr lParam); [DllImport("user32.dll")] static extern IntPtr SetWindowsHookEx(int code, Hook func, IntPtr hInstance, int threadID); [DllImport("user32.dll")] static extern int UnhookWindowsHookEx(IntPtr hookHandle); [DllImport("user32.dll")] static extern int CallNextHookEx(IntPtr hhook, int code, IntPtr wParam, IntPtr lParam); static bool IsPressed(Keys check) { return ((Control.ModifierKeys & check) == check); } static void Main() { Stream sound = Assembly.GetExecutingAssembly() .GetManifestResourceStream("InstantRimshot.rimshot.wav"); SoundPlayer player = new SoundPlayer(sound); player.Load(); IntPtr hookHandle = IntPtr.Zero; hookHandle = SetWindowsHookEx(WH_KEYBOARD_LL, delegate(int code, IntPtr wParam, IntPtr lParam) { if (code >= 0 && wParam == (IntPtr) WM_KEYDOWN) { Keys vkCode = (Keys)Marshal.ReadInt32(lParam); if (Keys.I == vkCode && IsPressed(Keys.Control) && IsPressed(Keys.Shift)) { if (IsPressed(Keys.Alt)) { UnhookWindowsHookEx(hookHandle); Application.Exit(); return CallNextHookEx(hookHandle, code, wParam, lParam); } else { player.Play(); } } } return CallNextHookEx(hookHandle, code, wParam, lParam); }, IntPtr.Zero, 0); Application.Run(); } }

If you read this far you should probably follow me on Twitter or check out my other blog posts. I no longer have comments on this blog, but you can send me an email if you have some comments about this page.