Colemak
I switched to Colemak a couple of years ago. I love it. Never going back. Not really any faster than QWERTY, but so much more comfortable.
One issue though is whenever I jump on someone else's machine or remote into some server. I want to switch the layout but I don't really want to install anything.
Here's a little seventy-line F# app that will intercept all keys on the system on which it's running and remap to Colemak:
open System
open System.Diagnostics
open System.Runtime.InteropServices
open System.Windows.Forms
[<Literal>]
let WH_KEYBOARD_LL = 13
[<StructLayout(LayoutKind.Sequential)>]
type KBDLLHOOKSTRUCT =
val vkCode : uint32
val scanCode : uint32
val flags : uint32
val time : uint32
val dwExtraInfo : nativeint
type LowLevelKeyboardProc = delegate of int * nativeint * KBDLLHOOKSTRUCT -> nativeint
[<DllImport("kernel32.dll", SetLastError = true)>]
extern nativeint GetModuleHandle(string lpModuleName)
[<DllImport("user32.dll", SetLastError = true)>]
extern bool UnhookWindowsHookEx(nativeint hhk)
[<DllImport("user32.dll", SetLastError = true)>]
extern nativeint SetWindowsHookEx(int idhook, LowLevelKeyboardProc proc, nativeint hMod, uint32 threadId)
[<DllImport("user32.dll", SetLastError = true)>]
extern nativeint CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, KBDLLHOOKSTRUCT lParam)
let SetHook (proc: LowLevelKeyboardProc) =
use curProc = Process.GetCurrentProcess ()
use curMod = curProc.MainModule
SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curMod.ModuleName), 0u)
type App(handler) as x =
inherit ApplicationContext()
let rec callback (code : int) (wparam : nativeint) (lparam : KBDLLHOOKSTRUCT) : nativeint =
match handler code wparam lparam with
| Some keys -> SendKeys.Send keys; nativeint 1
| None -> CallNextHookEx(hook, code, wparam, lparam)
and proc = new LowLevelKeyboardProc(callback)
and hook = SetHook proc
override x.ExitThreadCore() =
UnhookWindowsHookEx(hook) |> ignore
base.ExitThreadCore()
printfn "Welcome to Colemak!"
Application.Run(new App(fun code wparam lparam ->
let key = int >> enum
if lparam.flags &&& 0b10010000u = 0u then // key down and not injected
match lparam.vkCode |> key with
| Keys.D -> Some "s"
| Keys.E -> Some "f"
| Keys.F -> Some "t"
| Keys.G -> Some "d"
| Keys.I -> Some "u"
| Keys.J -> Some "n"
| Keys.K -> Some "e"
| Keys.L -> Some "i"
| Keys.N -> Some "k"
| Keys.O -> Some "y"
| Keys.P -> Some ";"
| Keys.R -> Some "p"
| Keys.S -> Some "r"
| Keys.T -> Some "g"
| Keys.U -> Some "l"
| Keys.Y -> Some "j"
| Keys.OemSemicolon -> Some "o"
| _ -> None
else None))
Comments
- Anonymous
March 31, 2013
The comment has been removed - Anonymous
April 01, 2013
@Max, absolutely! I wish I knew right person to talk to and make that happen... - Anonymous
April 02, 2013
@Ashley, Maybe Michael Kaplan? He'd at least know who to get a hold of. blogs.msdn.com/.../michkap - Anonymous
April 09, 2013
@kettch I had a little email thread with Michael today, he says it’s not being considered for the upcoming version, but it is on the radar. - Anonymous
April 27, 2014
I have a mechanical keyboard that has hardware switches to change the layout, no worrying about having the layout set correctly/available!But right now I have a choice between Dvorak and Colemak. Looks like Colemak is the better choice based on your usage. But I'm curious, how did you come up with those heatmaps? - Anonymous
April 28, 2014
www.patrick-wied.at/.../heatmap-keyboard :)