Wednesday, February 10, 2010

Using Microsoft Natural Ergonomic Keyboard 4000 without Microsoft IntelliType

I love my Natural Ergonomic Keyboard 4000, but frankly, I can't say the same for the bundled software and driver, Microsoft IntelliType. For one, Microsoft IntelliType is cumbersome to use and offer far less customization than my imagination would run. The hacks out there to exhort more freedom out of IntelliType (yes, google'em) are just plainly ugly and I'm not even sure about how much more they can acomplish beyond what IntelliType offers. Furthermore, I prefer installing less stuff on my computer, and however powerful my computer is, I also would always appreciate one less service running in the background.

AutoHotKey comes to rescue! For those of you not in the know, AutoHotKey is an amazing macro / hotkey scripting tool on Windows. It's lightweight, portable, and very powerful - albeit with a slightly awkward syntax. The following trick is due to some helpful forum poster at the AutoHotKey forum, adapted by me. The Natural Ergonomic Keyboard 4000 registers itself to the OS as both a keyboard and a Human Interface Device (HID). The former looks to your OS just like your everyman's keyboard, but the latter accounts for the specials keys like favourites, etc., which, you probably know, will not work without the installing Microsoft IntelliType.

But a little AutoHotKey script can teach your OS how to react to the special keys on your keyboard. To use it, download AutoHotKey from its website; grab the script at the end of this post and save it to something like intellitype.ahk, and drag the script (in Windows Explorer) to the AutoHotKey.exe icon to run it.

Of course, the script now just pops up not-so-useful message boxes when you press the favorite keys, but it's the time now to head to the AutoHotKey website and read their tutorial (hint: look for the Run command). You can make those keys do almost anything you want!

And there you go, a solution to unveil all the potential of your Microsoft Natural Ergonomic Keyboard 4000 without even installing Microsoft Intellitype:


OnMessage(0x00FF, "InputMessage")


RegisterHIDDevice(12, 1) ; Register Microsoft Keyboard

Return

; Zoom down
012E020000010000:
Send, {Ctrl}-
return

; Zoom up
012D020000010000:
Send, {Ctrl}+
return

; All up
0100000000010000:
return

; My Favorites
MsgBox Favourite
return

; Favorites 1
0100000000050000:
MsgBox Favorites 1
return
; Favorites 2
0100000000090000:
MsgBox Favorites 2
return
; Favorites 3
0100000000110000:
MsgBox Favorites 3
return
; Favorites 4
0100000000210000:
MsgBox Favorites 4
return
; Favorites 5
0100000000410000:
MsgBox Favorites 5
return


;numpad(
010000B600010000:
Send (
return

;numpad)
010000B700010000:
Send )
return

;numpad=
0100006700010000:
Send `=
return

Mem2Hex( pointer, len )
{
A_FI := A_FormatInteger
SetFormat, Integer, Hex
Loop, %len% {
Hex := *Pointer+0
StringReplace, Hex, Hex, 0x, 0x0
StringRight Hex, Hex, 2
hexDump := hexDump . hex
Pointer ++
}
SetFormat, Integer, %A_FI%
StringUpper, hexDump, hexDump
Return hexDump
}

; Keyboards are always Usage 6, Usage Page 1, Mice are Usage 2, Usage Page 1,
; HID devices specify their top level collection in the info block
RegisterHIDDevice(UsagePage,Usage)
{
; local RawDevice,HWND
RIDEV_INPUTSINK := 0x00000100
DetectHiddenWindows, on
HWND := WinExist("ahk_class AutoHotkey ahk_pid " DllCall("GetCurrentProcessId"))
DetectHiddenWindows, off

VarSetCapacity(RawDevice, 12)
NumPut(UsagePage, RawDevice, 0, "UShort")
NumPut(Usage, RawDevice, 2, "UShort")
NumPut(RIDEV_INPUTSINK, RawDevice, 4)
NumPut(HWND, RawDevice, 8)

Res := DllCall("RegisterRawInputDevices", "UInt", &RawDevice, UInt, 1, UInt, 12)
if (Res = 0)
MsgBox, Failed to register for HID Device
}
InputMessage(wParam, lParam, msg, hwnd)
{
RID_INPUT := 0x10000003
RIM_TYPEHID := 2
SizeofRidDeviceInfo := 32
RIDI_DEVICEINFO := 0x2000000b


DllCall("GetRawInputData", UInt, lParam, UInt, RID_INPUT, UInt, 0, "UInt *", Size, UInt, 16)
VarSetCapacity(Buffer, Size)
DllCall("GetRawInputData", UInt, lParam, UInt, RID_INPUT, UInt, &Buffer, "UInt *", Size, UInt, 16)

Type := NumGet(Buffer, 0 * 4)
Size := NumGet(Buffer, 1 * 4)
Handle := NumGet(Buffer, 2 * 4)

VarSetCapacity(Info, SizeofRidDeviceInfo)
NumPut(SizeofRidDeviceInfo, Info, 0)
Length := SizeofRidDeviceInfo

DllCall("GetRawInputDeviceInfo", UInt, Handle, UInt, RIDI_DEVICEINFO, UInt, &Info, "UInt *", SizeofRidDeviceInfo)

VenderID := NumGet(Info, 4 * 2)
Product := NumGet(Info, 4 * 3)

; tooltip %VenderID% %Product%


if (Type = RIM_TYPEHID)
{
SizeHid := NumGet(Buffer, (16 + 0))
InputCount := NumGet(Buffer, (16 + 4))
Loop %InputCount% {
Addr := &Buffer + 24 + ((A_Index - 1) * SizeHid)
BAddr := &Buffer
Input := Mem2Hex(Addr, SizeHid)
If (IsLabel(Input))
{
Gosub, %Input%
}

}
}
}

No comments: