1 (изменено: Gluck, 2012-03-19 22:55:28)

Тема: AHK: Переназначение LED-индикаторов клавиатуры

Господа, заранее прошу прощения за детский вопрос, но я не разработчик и осилить язык глубже азов быстро не могу. Собственно проблема возникла при совмещении нескольких шатко-валко работающих по отдельности скриптов в один. Но лучше по порядку.

В обоих скриптах используется Keyboard LED control авторства Shimanov'а, Peter'а, JGR и evl'а, а точнее — дописанный Lexikos'ом Keyboard LED control for AutoHotkey_L. Он там в конце темы, но давайте я скопирую сюда код, чтоб вы ничего не искали.


/*

    Keyboard LED control for AutoHotkey_L
        http://www.autohotkey.com/forum/viewtopic.php?p=468000#468000

    KeyboardLED(LEDvalue, "Cmd", Kbd)
        LEDvalue  - ScrollLock=1, NumLock=2, CapsLock=4
        Cmd       - on/off/switch
        Kbd       - index of keyboard (probably 0 or 2)

*/

KeyboardLED(LEDvalue, Cmd, Kbd=0)
{
  SetUnicodeStr(fn,"\Device\KeyBoardClass" Kbd)
  h_device:=NtCreateFile(fn,0+0x00000100+0x00000080+0x00100000,1,1,0x00000040+0x00000020,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"))
    }
  
  success := DllCall( "DeviceIoControl"
              ,  "ptr", h_device
              , "uint", CTL_CODE( 0x0000000b     ; FILE_DEVICE_KEYBOARD
                        , 2
                        , 0             ; METHOD_BUFFERED
                        , 0  )          ; FILE_ANY_ACCESS
              , "int*", KeyLED << 16
              , "uint", 4
              ,  "ptr", 0
              , "uint", 0
              ,  "ptr*", output_actual
              ,  "ptr", 0 )
  
  NtCloseFile(h_device)
  return success
}

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(objattrib,6*A_PtrSize,0)
  VarSetCapacity(io,2*A_PtrSize,0)
  VarSetCapacity(pus,2*A_PtrSize)
  DllCall("ntdll\RtlInitUnicodeString","ptr",&pus,"ptr",&wfilename)
  NumPut(6*A_PtrSize,objattrib,0)
  NumPut(&pus,objattrib,2*A_PtrSize)
  status:=DllCall("ntdll\ZwCreateFile","ptr*",fh,"UInt",desiredaccess,"ptr",&objattrib
                  ,"ptr",&io,"ptr",0,"UInt",fattribs,"UInt",sharemode,"UInt",createdist
                  ,"UInt",flags,"ptr",0,"UInt",0, "UInt")
  return % fh
}

NtCloseFile(handle)
{
  return DllCall("ntdll\ZwClose","ptr",handle)
}


SetUnicodeStr(ByRef out, str_)
{
  VarSetCapacity(out,2*StrPut(str_,"utf-16"))
  StrPut(str_,&out,"utf-16")
}

Итак, первый используемый мной скрипт составлен evl'ом и доступен во всё той же теме, во втором её сообщении. Скрипт инвертирует состояние индикатора Num Lock. Т. е. когда дополнительная цифровая клавиатура включена, индикатор не горит. В скрипт помимо приведённого выше блока входит следующий код:


Gosub, ~NumLock
Return

~NumLock:: 
~CapsLock:: 
~ScrollLock::
  Sleep, 10 ; improve reliability of setting LED state sometimes
  If (GetKeyState("Numlock", "T"))
    KeyboardLED(2,"off")
  Else
    KeyboardLED(2,"on")
Return

Второй, используемый мной скрипт должен зажигать индикатор Scroll Lock, когда включена английская раскладка клавиатуры. Он составлен по мотивам реализации Ludens'а. Однако, у Ludens'а индикатор зажигался, поскольку модифицировалось само состояние переключателя Scroll Lock. Я же хочу обойти переключатель и затронуть только индикатор, если есть такая возможность. Итак, в предлагаемом мной варианте помимо приведённого в начале блока используется следующий код:


#Persistent

SetTimer RussianLED

RussianLED:
  WinGet, WID, ID, A
  WT := DllCall("GetWindowThreadProcessId", "UInt", WID, "UInt", 0)
  LID := DllCall("GetKeyboardLayout", "UInt", WT)
  Russian := LID = 68748313 ? 1 : 0
  If Russian
    KeyboardLED(7,"off")
  Else
    KeyboardLED(7,"on")
Return

Как я уже сказал, по отдельности эти скрипты работоспособны. Вопрос в том, чтобы добиться их одновременной слаженной работы, по возможности записав всё одним скриптом. И вершин удовольствия я достигну, если в этот единый скрипт можно будет безболезненно добавить ещё несколько переназначений, автозамен и прочих мелочей.