;
; AutoHotkey Version: 1.x
; Language.........: English
; Platform.........: NT/XP/Vista
; Author...........: mrBTK
;
; Script Function..: Make Apple Wireless Keyboard useful in MS Windows:
; - EJECT = Delete with repeat deleting on long pressing. Shift-DEL and other combinations works too.
; - Swap FN & left Control
; - FN-functions оn F3-F12 keys and arrow keys (use new-FN)
; - FN+EJECT = drive eject
; - F12 = INSERT (on your need, it simple to delete this feature: find in script "switch F12 to Insert" and delete the command)
; - AWK POWER button toggle script suspending. Place in script directory two any sound files "on.wav" & "off.wav" for notification
;
; Based on.........: DLLCall: Support for Human Interface devices: some keymapping code
; By...............: Micha
; URL..............: http://www.autohotkey.com/forum/viewtopic.php?t=6367
; Based on.........: HID/Extended input devices (MS Natural Keyboard 4000 etc.): HID operations code
; By...............: Shaun
; URL..............: http://www.autohotkey.com/board/topic/36304-hidextended-input-devices-ms-natural-keyboard-4000-etc/
;
; Use..............: Spread the word! Just be sure to credit the writer of the original config
; and the authors of this file.
;
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
#MaxHotkeysPerInterval 1000
#SingleInstance force ; Replace any previous instance
DetectHiddenWindows, on
OnMessage(0x00FF, "InputMessage")
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
;#NoTrayIcon
; Set screen title, to set the HWND
Gui, Show, x0 y0 h0 w0, AppleWKHelper
HWND := WinExist("AppleWKHelper")
hidMessage := 0
isSuspend := 0
; Variable for the modifier key
fnPressed := 0
fnPrevState := 0
ejPressed := 0
ejPrevState := 0
pwrPressed := 0
pwrPrevState := 0
; Variable for Fn <> Lctrl
lctrlPressed := 0
lctrlPrevState := 0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; handle HID input, set global vars, call modKeysProcessing
; List all of the "Raw Input" devices available for use and allow
; capture of output
;
; There may be more than one 'raw' device per device actually attached
; to the system. This is because these devices generally represent
; "HID Collections", and there may be more than one HID collection per
; USB device. For example, the Natural Keyboard 4000 supports a normal
; keyboard HID collection, plus an additional HID collection that can
; be used for the zoom slider and other important buttons
SizeofRawInputDeviceList := 8
SizeofRidDeviceInfo := 32
SizeofRawInputDevice := 12
RIM_TYPEMOUSE := 0
RIM_TYPEKEYBOARD := 1
RIM_TYPEHID := 2
RIDI_DEVICENAME := 0x20000007
RIDI_DEVICEINFO := 0x2000000b
RIDEV_INPUTSINK := 0x00000100
RID_INPUT := 0x10000003
;;get count of HID devices
Res := DllCall("GetRawInputDeviceList", UInt, 0, "UInt *", Count, UInt, SizeofRawInputDeviceList)
VarSetCapacity(RawInputList, SizeofRawInputDeviceList * Count)
;;get list of HID devices
Res := DllCall("GetRawInputDeviceList", UInt, &RawInputList, "UInt *", Count, UInt, SizeofRawInputDeviceList)
rimHIDregistered := 0
Loop %Count% { ;for all HID devices
Handle := NumGet(RawInputList, (A_Index - 1) * SizeofRawInputDeviceList)
Type := NumGet(RawInputList, (A_Index - 1) * SizeofRawInputDeviceList + 4)
if (Type = RIM_TYPEMOUSE)
TypeName := "RIM_TYPEMOUSE"
else if (Type = RIM_TYPEKEYBOARD)
TypeName := "RIM_TYPEKEYBOARD"
else if (Type = RIM_TYPEHID)
TypeName := "RIM_TYPEHID"
else
TypeName := "RIM_OTHER"
;; get HID device name length
; Res := DllCall("GetRawInputDeviceInfo", UInt, Handle, UInt, RIDI_DEVICENAME, UInt, 0, "UInt *", Length)
; VarSetCapacity(Name, Length + 2)
;; get HID device name
; Res := DllCall("GetRawInputDeviceInfo", UInt, Handle, UInt, RIDI_DEVICENAME, "Str", Name, "UInt *", Length)
; get HID device info
VarSetCapacity(Info, SizeofRidDeviceInfo)
NumPut(SizeofRidDeviceInfo, Info, 0)
Length := SizeofRidDeviceInfo
Res := DllCall("GetRawInputDeviceInfo", UInt, Handle, UInt, RIDI_DEVICEINFO, UInt, &Info, "UInt *", SizeofRidDeviceInfo)
; 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
; if (Type = RIM_TYPEMOUSE) {
; Buttons := NumGet(Info, 4 * 3, "UShort")
; SampleRate := NumGet(Info, 4 * 4, "UShort")
; UsagePage := 1
; Usage := 2
; } else if (Type = RIM_TYPEKEYBOARD) {
; Mode := NumGet(Info, 4 * 4, "UShort")
; FunctionKeys := NumGet(Info, 4 * 5, "UShort")
; UsagePage := 1
; Usage := 6
; }
; AWK modifier buttons is separate TYPEHID (rather keyboard standard buttons)
if (Type = RIM_TYPEHID)
{
Vendor := NumGet(Info, 4 * 2, "UShort")
Product := NumGet(Info, 4 * 3, "UShort")
Version := NumGet(Info, 4 * 4, "UShort")
UsagePage := NumGet(Info, (4 * 5), "UShort")
Usage := NumGet(Info, (4 * 5) + 2, "UShort")
}
VarSetCapacity(RawDevice, SizeofRawInputDevice)
NumPut(RIDEV_INPUTSINK, RawDevice, 4)
NumPut(HWND, RawDevice, 8)
if (Type = RIM_TYPEHID && Vendor = 1452 && rimHIDregistered = 0) ; AWK Vendor number
{
rimHIDregistered := 1
NumPut(UsagePage, RawDevice, 0, "UShort")
NumPut(Usage, RawDevice, 2, "UShort")
;; Register AWK modifier buttons HID
Res := DllCall("RegisterRawInputDevices", "UInt", &RawDevice, UInt, 1, UInt, SizeofRawInputDevice)
if (Res = 0) {
MsgBox, Failed to register for AWK device!
ExitApp
}
}
}
Count := 1
InputMessage(wParam, lParam, msg, hwnd)
{
global hidMessage
global isSuspend
global RIM_TYPEMOUSE, RIM_TYPEKEYBOARD, RIM_TYPEHID
global RID_INPUT
; get HID input
Res := DllCall("GetRawInputData", UInt, lParam, UInt, RID_INPUT, UInt, 0, "UInt *", Size, UInt, 16)
VarSetCapacity(Buffer, Size)
Res := DllCall("GetRawInputData", UInt, lParam, UInt, RID_INPUT, UInt, &Buffer, "UInt *", Size, UInt, 16)
Type := NumGet(Buffer, 0 * 4)
; if (Type = RIM_TYPEMOUSE)
; {
; LastX := NumGet(Buffer, (16 + (4 * 3)), "Int")
; LastY := NumGet(Buffer, (16 + (4 * 4)), "Int")
; hidMessage := 0
; }
; else if (Type = RIM_TYPEKEYBOARD)
; {
; ScanCode := NumGet(Buffer, (16 + 0), "UShort")
; VKey :=
; hidMessage := NumGet(Buffer, (16 + 8))
; }
; else
if (Type = RIM_TYPEHID)
{
SizeHid := NumGet(Buffer, (16 + 0))
InputCount := NumGet(Buffer, (16 + 4))
Loop %InputCount% {
Addr := &Buffer + 24 + ((A_Index - 1) * SizeHid)
hidMessage := Mem2Hex(Addr, SizeHid)
ProcessHIDData(wParam, lParam)
}
}
return
} ; END: InputMessage
Mem2Hex( pointer, len )
{
multiply := 0x100
Hex := 0
Loop, %len% {
Hex := Hex * multiply
Hex := Hex + *Pointer+0
Pointer ++
}
Return Hex
} ; END: Mem2Hex
ProcessHIDData(wParam, lParam) ; set global vars for further handling
{
global hidMessage
global isSuspend
global fnPressed
global fnPrevState
global ejPressed
global ejPrevState
global pwrPressed
global pwrPrevState
SetTimer, SendDelete, Off
; Filter bit 5 (Fn key)
Transform, FnValue, BitAnd, 0xFF10, hidMessage
if (FnValue = 0x1110) {
; Fn is pressed
fnPrevState := fnPressed
fnPressed := 1
} else {
; Fn is released
fnPrevState := fnPressed
fnPressed := 0
}
; Filter bit 4 (Eject key)
Transform, FnValue, BitAnd, 0xFF08, hidMessage
if (FnValue = 0x1108) {
; Eject is pressed
ejPrevState := ejPressed
ejPressed := 1
} else {
; Eject is Released
ejPrevState := ejPressed
ejPressed := 0
}
; Filter bit 1 fnd 2 (Power key)
Transform, FnValue, BitAnd, 0xFF03, hidMessage
if (FnValue = 0x1303) { ; Power is pressed
pwrPrevState := 0
pwrPressed := 1
; Toggle Suspend of this script.
chkSuspend()
}
if (fnValue = 0x1302) {
; Power is released
pwrPrevState := 1
pwrPressed := 0
; no anything doing оn power button release
}
if (isSuspend = 0)
modKeysProcessing()
} ; END: ProcessHIDData
modKeysProcessing() { ; handle keypressing for modifier keys
global fnPressed
global ejPressed
global ejPrevState
global fnPrevState
global lctrlPressed
global lctrlPrevState
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Eject = delete with delay and repeat
if (lctrlPressed = 0) { ; eject only pressed
if (ejPressed = 1 and ejPrevState = 0) { ; eject down
if (GetKeyState("Shift") or GetKeyState("Alt") or GetKeyState("Control")) {
SendInput {Blind}{Delete} ; Edit::Cut and other w|o repeating
} else if (fnPressed = 1) {
SendInput {Ctrl}{Delete} ; ctrl - del
} else { ; No modifiers = Del with repeating
SendInput {Delete}
SetTimer, SendDelete, -800 ; Delay for start repeating
}
}
}
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; fn = rCtrl
if (ejPressed = 0) { ; fn only pressed
if (fnPressed = 1 and fnPrevState = 0) ; fn down
SendInput {rCtrl Down}
if (fnPressed = 0 and fnPrevState = 1) ; fn up
SendInput {rCtrl Up}
}
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; lctrl + Eject Up = optical drive eject
if (lctrlPressed = 1 and ejPressed = 0 and ejPrevState = 1 and fnPressed = 0)
Drive, Eject
} ; END: modKeysProcessing
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Send Delete keystroke repeatedly while Eject still pressed
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SendDelete:
; repeating del while Eject still down
if (ejPressed = 1) {
SendInput {delete}
SetTimer, SendDelete, -40
}
Return
chkSuspend() {
global fnPressed
global fnPrevState
global ejPressed
global ejPrevState
global lctrlPressed
global lctrlPrevState
global pwrPressed
global pwrPrevState
global isSuspend
if (isSuspend = 0) {
isSuspend := 1
fnPressed := 0
fnPrevState := 0
ejPressed := 0
ejPrevState := 0
pwrPressed := 0
pwrPrevState := 0
lctrlPressed := 0
lctrlPrevState := 0
Suspend , On
SetTimer, SendDelete, Off
SendInput {rCtrl Up}
TrayTip, AWK Helper, Suspended, 1, 1
Soundplay , off.wav
} else {
isSuspend := 0
Suspend , Off
TrayTip, AWK Helper, Restored, 1, 1
Soundplay , on.wav
}
} ; END: chkSuspend
; switch F12 to Insert
*F12::sendInput {Blind}{Insert}
;
; lctrl = fn
; get up and down Lcontrol, sets global variables
;
$*lControl up::LCtrlUp()
LCtrlUp() {
global lctrlPressed
global lctrlPrevState
lctrlPrevState := 1
lctrlPressed := 0
SendInput {F24 up}
}
Return
$*lControl::LCtrlDn()
LCtrlDn() {
global lctrlPressed
global lctrlPrevState
lctrlPrevState := 0
lctrlPressed := 1
SetTimer, SendDelete, Off
SendInput {F24 down}
}
Return
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Fn modifier: PrintScreen, Task Manager
; lctrl uses as fn
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; fn+alt F3 = PrtScr for Active Window
;
$!F3::hotkeyAltF3()
hotkeyAltF3() {
global ejPressed
global lctrlPressed
if(lctrlPressed = 1 and ejPressed = 0)
SendInput !{PrintScreen}
else
SendInput !{F3}
}
Return
;
; fn+F3 = PrtScr
;
$F3::hotkeyF3()
hotkeyF3() {
global ejPressed
global lctrlPressed
if(lctrlPressed = 1 and ejPressed = 0)
SendInput {PrintScreen}
else
SendInput {F3}
}
Return
;
; fn+F4 = Run TM
;
$F4::hotkeyF4()
hotkeyF4() {
global ejPressed
global lctrlPressed
if(lctrlPressed = 1 and ejPressed = 0)
SendInput +^{Esc}
else
SendInput {F4}
}
Return
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Fn modifier: Audio hotkeys, specified for WMP
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; WinMPlayer: Previous
;
$F7::hotkeyF7()
hotkeyF7() {
global ejPressed
global lctrlPressed
if(lctrlPressed = 1 and ejPressed = 0)
SendInput {Media_Prev} ; Previous
else
SendInput {F7}
}
Return
;
; WinMPlayer: Pause/Unpause
;
$F8::hotkeyF8()
hotkeyF8() {
global ejPressed
global lctrlPressed
if(lctrlPressed = 1 and ejPressed = 0)
SendInput {Media_Play_Pause} ; Pause/Unpause
else
SendInput {F8}
}
Return
;
; WinMPlayer: Next
;
$F9::hotkeyF9()
hotkeyF9()
{
global ejPressed
global lctrlPressed
if(lctrlPressed = 1 and and ejPressed = 0)
SendInput {Media_Next} ; Next
else
SendInput {F9}
}
Return
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Fn modifier: Audio hotkeys, system volume
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; System volume: Mute/Unmute
;
$F10::hotkeyF10()
hotkeyF10() {
global ejPressed
global lctrlPressed
if(lctrlPressed = 1 and ejPressed = 0)
SendInput {Volume_Mute} ; Mute/unmute the master volume.
else
SendInput {F10}
}
Return
;
; System volume: Volume Down
;
$F11::hotkeyF11()
hotkeyF11() {
global ejPressed
global lctrlPressed
if(lctrlPressed = 1 and ejPressed = 0)
SendInput {Volume_Down} ; Lower the master volume by 1 interval (typically 5%)
else
SendInput {F11}
}
Return
;
; System volume: Volume Down
;
$F12::hotkeyF12()
hotkeyF12() {
global fnPressed
global ejPressed
global lctrlPressed
if(lctrlPressed = 1 and ejPressed = 0 and fnPressed = 0)
SendInput {Volume_Up} ; Raise the master volume by 1 interval (typically 5%).
else
SendInput {Insert}
}
Return
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Fn modifier: Arrow keys
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Page Up
;
$UP::hotkeyPgUp()
hotkeyPgUp() {
global ejPressed
global lctrlPressed
if(lctrlPressed = 1 and ejPressed = 0) {
if (GetKeyState("Shift"))
SendInput {rCtrl Up}+{PgUp}
else
SendInput {rCtrl Up}{PgUp}
} else
SendInput {UP}
}
Return
;
; Page Down
;
$Down::hotkeyPgDn()
hotkeyPgDn() {
global fnPressed
global ejPressed
global ejPrevState
global fnPrevState
global lctrlPressed
if(lctrlPressed = 1 and ejPressed = 0)
SendInput {rCtrl Up}{PgDn}
else
SendInput {Down}
}
Return
;
; Home
;
$Left::hotkeyHome()
hotkeyHome() {
global ejPressed
global lctrlPressed
if(lctrlPressed = 1 and ejPressed = 0)
SendInput {rCtrl Up}{Home}
else
SendInput {Left}
}
Return
;
; End
;
$Right::hotkeyEnd()
hotkeyEnd() {
global ejPressed
global lctrlPressed
if(lctrlPressed = 1 and ejPressed = 0)
SendInput {rCtrl Up}{End}
else
SendInput {Right}
}
Return