This script allows you to control which capslock/numlock/scrolllock LED indicators are lit up, to produce effects such as flashing and cycling without altering the actual state of those keys (i.e. doesn't interfere with typing).
The script consists of 2 sections: 1) Some examples near the top. 2) The necessary functions.
The code originated here: Using Keyboard LEDs for spectrum.
Credit goes to Shimanov for the original code, Peter for syntax improvements and JGR for the code to get the handle of the keyboard device directly.
; Keyboard LED control (capslock/numlock/scrolllock lights)
; http://www.autohotkey.com/forum/viewtopic.php?t=10532
; USAGE: KeyboardLED(LEDvalue,"Cmd") ; LEDvalue: ScrollLock=1, NumLock=2, CapsLock=4 ; Cmd = on/off/switch
Loop, 3 ; flash all LEDs
{
KeyboardLED(7,"on")
Sleep, 500
KeyboardLED(7,"off")
Sleep, 500
}
Loop, 3 ; flash ScrollLock LED
{
KeyboardLED(7,"off")
KeyboardLED(4,"switch")
Sleep, 500
KeyboardLED(7,"off")
Sleep, 500
}
Loop, 3 ; cycle all LEDs left to right
{
KeyboardLED(7,"off")
Sleep, 250
KeyboardLED(2,"switch")
Sleep, 250
KeyboardLED(4,"switch")
Sleep, 250
KeyboardLED(1,"switch")
Sleep, 250
}
Loop, 3 ; progress bar in LEDs
{
KeyboardLED(7,"off")
Sleep, 500
KeyboardLED(2,"switch")
Sleep, 500
KeyboardLED(6,"switch")
Sleep, 500
KeyboardLED(7,"switch")
Sleep, 500
}
Loop, 3 ; Knight Rider KITT cycling all LEDs ;-)
{
KeyboardLED(2,"switch")
Sleep, 500
KeyboardLED(4,"switch")
Sleep, 500
KeyboardLED(1,"switch")
Sleep, 500
KeyboardLED(4,"switch")
Sleep, 500
}
KeyboardLED(0,"off") ; all LED('s) according to keystate (Command = on or off)
Return
KeyboardLED(LEDvalue, Cmd) ; LEDvalue: ScrollLock=1, NumLock=2, CapsLock=4 ; Cmd = on/off/switch
{
Static h_device
If ! h_device ; initialise
{
device =\Device\KeyBoardClass0
SetUnicodeStr(fn,device)
h_device:=NtCreateFile(fn,0+0x00000100+0x00000080+0x00100000,1,1,0x00000040+0x00000020,0)
}
VarSetCapacity( output_actual, 4, 0 )
input_size = 4
VarSetCapacity( input, input_size, 0 )
If Cmd= switch ;switches every LED according to LEDvalue
KeyLED:= LEDvalue
If Cmd= on ;forces all choosen LED's to ON (LEDvalue= 0 ->LED's according to keystate)
KeyLED:= LEDvalue | (GetKeyState("ScrollLock", "T") + 2*GetKeyState("NumLock", "T") + 4*GetKeyState("CapsLock", "T"))
If Cmd= off ;forces all choosen LED's to OFF (LEDvalue= 0 ->LED's according to keystate)
{
LEDvalue:= LEDvalue ^ 7
KeyLED:= LEDvalue & (GetKeyState("ScrollLock", "T") + 2*GetKeyState("NumLock", "T") + 4*GetKeyState("CapsLock", "T"))
}
; EncodeInteger( KeyLED, 1, &input, 2 ) ;input bit pattern (KeyLED): bit 0 = scrolllock ;bit 1 = numlock ;bit 2 = capslock
input := Chr(1) Chr(1) Chr(KeyLED)
input := Chr(1)
input=
success := DllCall( "DeviceIoControl"
, "uint", h_device
, "uint", CTL_CODE( 0x0000000b ; FILE_DEVICE_KEYBOARD
, 2
, 0 ; METHOD_BUFFERED
, 0 ) ; FILE_ANY_ACCESS
, "uint", &input
, "uint", input_size
, "uint", 0
, "uint", 0
, "uint", &output_actual
, "uint", 0 )
}
CTL_CODE( p_device_type, p_function, p_method, p_access )
{
Return, ( p_device_type << 16 ) | ( p_access << 14 ) | ( p_function << 2 ) | p_method
}
NtCreateFile(ByRef wfilename,desiredaccess,sharemode,createdist,flags,fattribs)
{
VarSetCapacity(fh,4,0)
VarSetCapacity(objattrib,24,0)
VarSetCapacity(io,8,0)
VarSetCapacity(pus,8)
uslen:=DllCall("lstrlenW","str",wfilename)*2
InsertInteger(uslen,pus,0,2)
InsertInteger(uslen,pus,2,2)
InsertInteger(&wfilename,pus,4)
InsertInteger(24,objattrib,0)
InsertInteger(&pus,objattrib,8)
status:=DllCall("ntdll\ZwCreateFile","str",fh,"UInt",desiredaccess,"str",objattrib,"str",io,"UInt",0,"UInt",fattribs
,"UInt",sharemode,"UInt",createdist,"UInt",flags,"UInt",0,"UInt",0, "UInt")
return % ExtractInteger(fh)
}
SetUnicodeStr(ByRef out, str_)
{
VarSetCapacity(st1, 8, 0)
InsertInteger(0x530025, st1)
VarSetCapacity(out, (StrLen(str_)+1)*2, 0)
DllCall("wsprintfW", "str", out, "str", st1, "str", str_, "Cdecl UInt")
}
ExtractInteger(ByRef pSource, pOffset = 0, pIsSigned = false, pSize = 4)
; pSource is a string (buffer) whose memory area contains a raw/binary integer at pOffset.
; The caller should pass true for pSigned to interpret the result as signed vs. unsigned.
; pSize is the size of PSource's integer in bytes (e.g. 4 bytes for a DWORD or Int).
; pSource must be ByRef to avoid corruption during the formal-to-actual copying process
; (since pSource might contain valid data beyond its first binary zero).
{
Loop %pSize% ; Build the integer by adding up its bytes.
result += *(&pSource + pOffset + A_Index-1) << 8*(A_Index-1)
if (!pIsSigned OR pSize > 4 OR result < 0x80000000)
return result ; Signed vs. unsigned doesn't matter in these cases.
; Otherwise, convert the value (now known to be 32-bit) to its signed counterpart:
return -(0xFFFFFFFF - result + 1)
}
InsertInteger(pInteger, ByRef pDest, pOffset = 0, pSize = 4)
; The caller must ensure that pDest has sufficient capacity. To preserve any existing contents in pDest,
; only pSize number of bytes starting at pOffset are altered in it.
{
Loop %pSize% ; Copy each byte in the integer into the structure as raw binary data.
DllCall("RtlFillMemory", "UInt", &pDest + pOffset + A_Index-1, "UInt", 1, "UChar", pInteger >> 8*(A_Index-1) & 0xFF)
}
I Used the available scripts to make a script that uses caps lock and scroll lock keys as read and write for removable media such as pendrives as my flash drive doesnt have the light
#SingleInstance, Force
#Persistent
Process, Priority,, High
CoordMode, Tooltip
KeyboardLED(5, "off")
DriveGet, HDD_List, List, Removable
Drives := StrLen(HDD_List)
Loop, parse, HDD_List
{
HDD%A_Index% := A_LoopField
hDrv%A_Index% := DllCall( "CreateFile", Str,"\\.\" . A_LoopField . ":", Uint,0 ,Uint,3, Uint,0, Uint,3, Uint,0, Uint,0), oRC%A_Index% := 0, oWC%A_Index% := 0
}
SetTimer, HDD_Monitor, ;500
HDD_Monitor:
loop, % Drives
{
VarSetCapacity(dp%A_Index%, 88)
DllCall("DeviceIoControl", Uint,hDrv%A_Index%, Uint,0x00070020, Uint,0, Uint,0, Uint, &dp%A_Index%, Uint,88, UintP,nReturn, Uint,0 )
nRC%A_Index% := *(&dp%A_Index%+40) | *(&dp%A_Index%+41) << 8 | *(&dp%A_Index%+42) << 16 | *(&dp%A_Index%+43) << 24
nWC%A_Index% := *(&dp%A_Index%+44) | *(&dp%A_Index%+45) << 8 | *(&dp%A_Index%+46) << 16 | *(&dp%A_Index%+47) << 24
RC%A_Index% := Round(100-(100*(1/(1+(nRC%A_Index%-oRC%A_Index%))))) , WC%A_Index% := Round(100-(100*(1/(1+(nWC%A_Index%-oWC%A_Index%)))))
If(RC%A_Index% > 0)
KeyboardLED(4,"on")
If(WC%A_Index% > 0)
KeyboardLED(1,"on")
If(RC%A_Index% = 0)
KeyboardLED(4,"off")
If(WC%A_Index% = 0)
KeyboardLED(1,"off")
oRC%A_Index% := nRC%A_Index% , oWC%A_Index% := nWC%A_Index%
}
Return
KeyboardLED(LEDvalue, Cmd) ; LEDvalue: ScrollLock=1, NumLock=2, CapsLock=4 ; Cmd = on/off/switch
{
Static h_device
If ! h_device ; initialise
{
device =\Device\KeyBoardClass0
SetUnicodeStr(fn,device)
h_device:=NtCreateFile(fn,0+0x00000100+0x00000080+0x00100000,1,1,0x00000040+0x00000020,0)
}
VarSetCapacity( output_actual, 4, 0 )
input_size = 4
VarSetCapacity( input, input_size, 0 )
If Cmd= switch ;switches every LED according to LEDvalue
KeyLED:= LEDvalue
If Cmd= on ;forces all choosen LED's to ON (LEDvalue= 0 ->LED's according to keystate)
KeyLED:= LEDvalue | (GetKeyState("ScrollLock", "T") + 2*GetKeyState("NumLock", "T") + 4*GetKeyState("CapsLock", "T"))
If Cmd= off ;forces all choosen LED's to OFF (LEDvalue= 0 ->LED's according to keystate)
{
LEDvalue:= LEDvalue ^ 7
KeyLED:= LEDvalue & (GetKeyState("ScrollLock", "T") + 2*GetKeyState("NumLock", "T") + 4*GetKeyState("CapsLock", "T"))
}
; EncodeInteger( KeyLED, 1, &input, 2 ) ;input bit pattern (KeyLED): bit 0 = scrolllock ;bit 1 = numlock ;bit 2 = capslock
input := Chr(1) Chr(1) Chr(KeyLED)
input := Chr(1)
input=
success := DllCall( "DeviceIoControl"
, "uint", h_device
, "uint", CTL_CODE( 0x0000000b ; FILE_DEVICE_KEYBOARD
, 2
, 0 ; METHOD_BUFFERED
, 0 ) ; FILE_ANY_ACCESS
, "uint", &input
, "uint", input_size
, "uint", 0
, "uint", 0
, "uint", &output_actual
, "uint", 0 )
}
CTL_CODE( p_device_type, p_function, p_method, p_access )
{
Return, ( p_device_type << 16 ) | ( p_access << 14 ) | ( p_function << 2 ) | p_method
}
NtCreateFile(ByRef wfilename,desiredaccess,sharemode,createdist,flags,fattribs)
{
VarSetCapacity(fh,4,0)
VarSetCapacity(objattrib,24,0)
VarSetCapacity(io,8,0)
VarSetCapacity(pus,8)
uslen:=DllCall("lstrlenW","str",wfilename)*2
InsertInteger(uslen,pus,0,2)
InsertInteger(uslen,pus,2,2)
InsertInteger(&wfilename,pus,4)
InsertInteger(24,objattrib,0)
InsertInteger(&pus,objattrib,8)
status:=DllCall("ntdll\ZwCreateFile","str",fh,"UInt",desiredaccess,"str",objattrib,"str",io,"UInt",0,"UInt",fattribs
,"UInt",sharemode,"UInt",createdist,"UInt",flags,"UInt",0,"UInt",0, "UInt")
return % ExtractInteger(fh)
}
SetUnicodeStr(ByRef out, str_)
{
VarSetCapacity(st1, 8, 0)
InsertInteger(0x530025, st1)
VarSetCapacity(out, (StrLen(str_)+1)*2, 0)
DllCall("wsprintfW", "str", out, "str", st1, "str", str_, "Cdecl UInt")
}
ExtractInteger(ByRef pSource, pOffset = 0, pIsSigned = false, pSize = 4)
{
Loop %pSize% ; Build the integer by adding up its bytes.
result += *(&pSource + pOffset + A_Index-1) << 8*(A_Index-1)
if (!pIsSigned OR pSize > 4 OR result < 0x80000000)
return result ; Signed vs. unsigned doesn't matter in these cases.
; Otherwise, convert the value (now known to be 32-bit) to its signed counterpart:
return -(0xFFFFFFFF - result + 1)
}
InsertInteger(pInteger, ByRef pDest, pOffset = 0, pSize = 4)
; The caller must ensure that pDest has sufficient capacity. To preserve any existing contents in pDest,
; only pSize number of bytes starting at pOffset are altered in it.
{
Loop %pSize% ; Copy each byte in the integer into the structure as raw binary data.
DllCall("RtlFillMemory", "UInt", &pDest + pOffset + A_Index-1, "UInt", 1, "UChar", pInteger >> 8*(A_Index-1) & 0xFF)
}
OnExit:
KeyboardLED(0, "off")
ExitApp