AutoHotkey Homepage AutoHotkey Community
Let's help each other out
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Using Keyboard LEDs for spectrum.
Goto page Previous  1, 2, 3
 
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Ask for Help
View previous topic :: View next topic  
Author Message
evl



Joined: 24 Aug 2005
Posts: 1239

PostPosted: Mon Mar 27, 2006 8:56 pm    Post subject: Reply with quote

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 Very Happy (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
View user's profile Send private message
evl



Joined: 24 Aug 2005
Posts: 1239

PostPosted: Thu Mar 30, 2006 12:00 am    Post subject: Reply with quote

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
View user's profile Send private message
JGR
Guest





PostPosted: Wed Jun 14, 2006 7:58 pm    Post subject: Getting the Handle without messing so much Reply with quote

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





PostPosted: Wed Jun 14, 2006 8:00 pm    Post subject: Reply with quote

Whoops: left this out from top

device=\Device\KeyBoardClass0
Back to top
evl



Joined: 24 Aug 2005
Posts: 1239

PostPosted: Wed Jun 14, 2006 9:53 pm    Post subject: Reply with quote

@ 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
View user's profile Send private message
JGR



Joined: 15 Jun 2006
Posts: 53
Location: Flaky internet connection :/

PostPosted: Thu Jun 15, 2006 5:35 am    Post subject: Reply with quote

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
View user's profile Send private message
evl



Joined: 24 Aug 2005
Posts: 1239

PostPosted: Thu Jun 15, 2006 10:07 am    Post subject: Reply with quote

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
View user's profile Send private message
JGR



Joined: 15 Jun 2006
Posts: 53
Location: Flaky internet connection :/

PostPosted: Thu Jun 15, 2006 10:23 am    Post subject: Reply with quote

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
View user's profile Send private message
evl



Joined: 24 Aug 2005
Posts: 1239

PostPosted: Thu Jun 15, 2006 6:09 pm    Post subject: Reply with quote

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 Very Happy
Back to top
View user's profile Send private message
evl



Joined: 24 Aug 2005
Posts: 1239

PostPosted: Fri Jun 16, 2006 6:10 pm    Post subject: Reply with quote

I've posted an updated version of this script in the scripts forum so it's easier to find:
http://www.autohotkey.com/forum/viewtopic.php?t=10532
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Ask for Help All times are GMT
Goto page Previous  1, 2, 3
Page 3 of 3

 
Jump to:  
You can post new topics in this forum
You can reply to topics in this forum


Powered by phpBB © 2001, 2005 phpBB Group