 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
evl
Joined: 24 Aug 2005 Posts: 1239
|
Posted: Mon Mar 27, 2006 8:56 pm Post subject: |
|
|
I've been playing with this script a bit and have merged Shimanov's code for getting info on the available keyboards with the Peter's code so that the script looks up the device instance id itself (again, only tested on windows xp sp2). You can change the line "Use_USB_Keyboard =0 ; 0= normal keyboard, 1 =usb keyboard" if you have a USB keyboard, but the wireless usb keyboard I have hooked up on my laptop doesn't have LED indicators on it so I've not been able to check that works.
| Code: |
KeyboardLED("5","switch") ;switches the LED's ScrollLock and CapsLock on, and NumLock off
Sleep, 2000
KeyboardLED("0","on") ;All LED('s) according to keystate (Cmd= on or off)
Sleep, 2000
KeyboardLED("1","switch") ;switches the ScrollLock LED on, and others off
Sleep, 2000
KeyboardLED("0","off") ;All LED('s) according to keystate (Cmd= on or off)
Loop, 25
{
KeyboardLED("4","on") ;only CapsLock LED on
Sleep, 100
KeyboardLED("4","off") ;only CapsLock LED off
Sleep, 100
}
KeyboardLED("0","off") ;All LED('s) according to keystate (Cmd= on or off)
Return
KeyboardLED(LEDvalue, Cmd)
{
;Original code for keyboard LED control is from Shimanov http://www.autohotkey.com/forum/viewtopic.php?t=8372
;LEDvalue: ScrollLock= 1, NumLock= 2, CapsLock= 4
Use_USB_Keyboard =0 ; 0= normal keyboard, 1 =usb keyboard
Static device, initialised
If initialised !=1
{
initialised =1
Loop, HKEY_LOCAL_MACHINE, SYSTEM\CurrentControlSet\Services\Kbdclass\Enum
{
RegRead, device_instance_id, HKLM, SYSTEM\CurrentControlSet\Services\Kbdclass\Enum, %A_LoopRegName%
If Use_USB_Keyboard=0
{
If device_instance_id contains ACPI\
Break
}
If Use_USB_Keyboard=1
{
If device_instance_id contains HID\
Break
}
}
Loop, HKEY_LOCAL_MACHINE, SYSTEM\CurrentControlSet\Control\DeviceClasses, 1, 1
{
If ( A_LoopRegName = "DeviceInstance" )
{
RegRead, value
If ( InStr( value, device_instance_id, false ) )
{
StringGetPos, ix, A_LoopRegSubKey, \##?#, R
StringTrimLeft, device, A_LoopRegSubKey, ix+5
device = \\.\%device%
Break
}
}
}
}
h_device := DllCall( "CreateFile"
, "str", device
, "uint", 0
, "uint", 1 ; FILE_SHARE_READ
, "uint", 0
, "uint", 3 ; OPEN_EXISTING
, "uint", 0
, "uint", 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
}
|
|
|
| Back to top |
|
 |
evl
Joined: 24 Aug 2005 Posts: 1239
|
Posted: Thu Mar 30, 2006 12:00 am Post subject: |
|
|
| Updated my last post with a quicker way of finding the first part of the device id of the keyboard ( Loop, HKEY_LOCAL_MACHINE, SYSTEM\CurrentControlSet\Services\Kbdclass\Enum ). |
|
| Back to top |
|
 |
JGR Guest
|
Posted: Wed Jun 14, 2006 7:58 pm Post subject: Getting the Handle without messing so much |
|
|
Use this code to get the handle of the keyboard device using the Native API via ZwCreateFile
No need to look stuff up in the control panel
| Code: | 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")
}
SetUnicodeStr(fn,device)
h_device:=NtCreateFile(fn,0+0x00000100+0x00000080+0x00100000,1,1,0x00000040+0x00000020,0)
|
|
|
| Back to top |
|
 |
JGR Guest
|
Posted: Wed Jun 14, 2006 8:00 pm Post subject: |
|
|
Whoops: left this out from top
device=\Device\KeyBoardClass0 |
|
| Back to top |
|
 |
evl
Joined: 24 Aug 2005 Posts: 1239
|
Posted: Wed Jun 14, 2006 9:53 pm Post subject: |
|
|
@ JGR:
Do you have a complete version of this script with your code that you could post? I'm also getting a "call to nonexistent function" error with InsertInteger for some reason.
Any idea how the code handles more than one keyboard? e.g. a laptop with usb keyboard? |
|
| Back to top |
|
 |
JGR
Joined: 15 Jun 2006 Posts: 53 Location: Flaky internet connection :/
|
Posted: Thu Jun 15, 2006 5:35 am Post subject: |
|
|
InsertInteger and ExtractInteger are examples in the AHK manual. I'll post them here.
| Code: | 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)
} |
The script from which I extracted the code extract is full of commented out bits, debugging statements, etc. So I don't think that you want the full script, (spread over two files totalling 17kb)
I'm not sure how the script deals with multiple keyboards, but I know on my machine there is a \Device\KeyBoardClass1 as well.
I only have one keyboard. However I'm sure that you could use SysInternals WinObj to poke around the Device directory and try other devices.
(www.sysinternals.com) |
|
| Back to top |
|
 |
evl
Joined: 24 Aug 2005 Posts: 1239
|
Posted: Thu Jun 15, 2006 10:07 am Post subject: |
|
|
h_device always seems to be "88", when for me in control panel it says:
ACPI\PNP0303\4&6DAEA46&0
Am I missing something? |
|
| Back to top |
|
 |
JGR
Joined: 15 Jun 2006 Posts: 53 Location: Flaky internet connection :/
|
Posted: Thu Jun 15, 2006 10:23 am Post subject: |
|
|
That's the handle which you pass to DeviceIoControl.
It is named the same as the variable containing the handle returned by CreateFile in the code you posted so that it can be swapped in for the CreateFile statement and the above registry searching.
The ACPI\PNP0303\4&6DAEA46&0 is just a symlink to a device number. (which is probably either another link or linked from the \Device\KeyBoardClass0 device.
The whole point is that you don't need to know ACPI\PNP0303\4&6DAEA46&0, or whatever, at all. |
|
| Back to top |
|
 |
evl
Joined: 24 Aug 2005 Posts: 1239
|
Posted: Thu Jun 15, 2006 6:09 pm Post subject: |
|
|
Ah! Thanks for the explanation, I follow what you mean now. The code was originally shimanov's, I just made some tweaks. I'll post an update of the script using your code  |
|
| Back to top |
|
 |
evl
Joined: 24 Aug 2005 Posts: 1239
|
|
| Back to top |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|