1

Тема: AHK: AHK V2 управление светодиодом caps lock (индикация раскладки)

Очень прошу помощи. Нашёл в интернете скрипт смены раскладки при нажатии capslock, но беда в том, что при работе этого скрипта светодиод кнопки не работает. А хотелось бы, что бы на английской раскладке светодиод капслока горел, а при переключении на русскую - не горел. Есть какая-то возможность управления светодиодном во второй версии программы? Гуглом нашёл только скрипт (библиотеку?) для старой версии autohotkey_L. www.autohotkey.com/board/topic/9587-key … /?p=446105
Сам скрипт смены раскладки по нажатию капслока

#Requires AutoHotkey v2.0

SetCapsLockState("AlwaysOff")
+CapsLock::{
    if (GetKeyState("CapsLock", "T")) {
        SetCapsLockState('Off')
    } else {
        SetCapsLockState('On')
    }
}
CapsLock::Send("{Ctrl down}{Shift down}{Shift up}{Ctrl up}")

2

Re: AHK: AHK V2 управление светодиодом caps lock (индикация раскладки)

Вроде как невозможно отвязать системную индикацию на клавиатуре. Предлагаю вместо этого использовать другой индикатор.

Win11x64, AHK v1.1.37.01 (Unicode 64-bit), AHK v2.0.17| AHK-Wiki | Переменные и выражения | RegEx101

3

Re: AHK: AHK V2 управление светодиодом caps lock (индикация раскладки)

Скрипт по ссылке у меня работает. Там одна проблема: если мы установили состояние индикатора программно, то его уже нельзя получить через GetKeyState. Но для данной задачи это и не нужно.
21nordson, у вас скрипт работает?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

4

Re: AHK: AHK V2 управление светодиодом caps lock (индикация раскладки)

teadrinker пишет:

у вас скрипт работает?

Нет, пишет что скрипт написан для  AHK версии 1.

5

Re: AHK: AHK V2 управление светодиодом caps lock (индикация раскладки)

__Михаил__ пишет:

Вроде как невозможно отвязать системную индикацию на клавиатуре. Предлагаю вместо этого использовать другой индикатор.

К сожалению это единственный индикатор на моей клавиатуре. Да и проблему я решил более странным способом, создав в microsoft keyboard layout creator раскладку, где на капсе английские символы, а без капса - русские. Просто вспомнил, что ещё лет 20 или 25 назад видел программу которая управляет всеми светодиодами на клавиатуре. Да и скрипт в AHK нашёл.

6

Re: AHK: AHK V2 управление светодиодом caps lock (индикация раскладки)

/*

    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)

*/
#Requires AutoHotkey v2

KeyboardLED(4, "switch")

KeyboardLED(ledValue, cmd, kbdIndex := 0) {

    ; KEYBOARD_INDICATOR_PARAMETERS LED bit flags (kbdmou.h)
    static SCROLL_LOCK_LED := 0x0001
         , NUM_LOCK_LED    := 0x0002
         , CAPS_LOCK_LED   := 0x0004
         , LED_MASK        := 0x0007  ; SCROLL_LOCK_LED | NUM_LOCK_LED | CAPS_LOCK_LED

    ; NtCreateFile: DesiredAccess flags (ntioapi.h)
         , FILE_READ_ATTRIBUTES  := 0x00000080
         , FILE_WRITE_ATTRIBUTES := 0x00000100
         , SYNCHRONIZE           := 0x00100000

    ; NtCreateFile: ShareAccess
         , FILE_SHARE_READ := 0x00000001

    ; NtCreateFile: CreateDisposition
         , FILE_OPEN := 0x00000001

    ; NtCreateFile: CreateOptions
         , FILE_NON_DIRECTORY_FILE      := 0x00000020
         , FILE_SYNCHRONOUS_IO_NONALERT := 0x00000040

    ; sizeof(KEYBOARD_INDICATOR_PARAMETERS): USHORT UnitId + USHORT LedFlags
         , KEYBOARD_INDICATOR_PARAMETERS_SIZE := 4

    ; CTL_CODE arguments for IOCTL_KEYBOARD_QUERY_INDICATORS (ntddkbd.h)
         , KBD_DEVICE_TYPE    := 0x0b  ; FILE_DEVICE_KEYBOARD
         , KBD_QUERY_FUNCTION := 0x10  ; query indicators
         , KBD_SET_FUNCTION   := 0x02  ; set indicators
         , KBD_METHOD         := 0x00  ; METHOD_BUFFERED
         , KBD_ACCESS         := 0x00  ; FILE_ANY_ACCESS

    hDevice := NtCreateFile(
        "\Device\KeyBoardClass" kbdIndex,
        FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
        FILE_SHARE_READ,
        FILE_OPEN,
        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
        0   ; FileAttributes: ignored when opening an existing file
    )

    ; Read actual LED state directly from the device
    ioctlQuery := CTL_CODE(KBD_DEVICE_TYPE, KBD_QUERY_FUNCTION, KBD_METHOD, KBD_ACCESS)
    inBuf  := Buffer(KEYBOARD_INDICATOR_PARAMETERS_SIZE, 0)
    outBuf := Buffer(KEYBOARD_INDICATOR_PARAMETERS_SIZE, 0)
    DllCall("DeviceIoControl",
        "ptr",   hDevice,
        "uint",  ioctlQuery,
        "ptr",   inBuf,
        "uint",  KEYBOARD_INDICATOR_PARAMETERS_SIZE,
        "ptr",   outBuf,
        "uint",  KEYBOARD_INDICATOR_PARAMETERS_SIZE,
        "uint*", &bytesReturned := 0,
        "ptr",   0)
    currentLeds := NumGet(outBuf, 2, "ushort")

    if (cmd = "switch")
        keyLed := currentLeds ^ ledValue
    else if (cmd = "on")
        keyLed := currentLeds | ledValue
    else if (cmd = "off")
        keyLed := currentLeds & (ledValue ^ LED_MASK)
    
    indicatorParams := keyLed << 16

    ioctlSet := CTL_CODE(KBD_DEVICE_TYPE, KBD_SET_FUNCTION, KBD_METHOD, KBD_ACCESS)
    success := DllCall("DeviceIoControl",
        "ptr",   hDevice,
        "uint",  ioctlSet,
        "int*",  indicatorParams,
        "uint",  KEYBOARD_INDICATOR_PARAMETERS_SIZE,
        "ptr",   0,
        "uint",  0,
        "uint*", &bytesReturned,
        "ptr",   0)

    NtCloseFile(hDevice)
    return success
}

CTL_CODE(deviceType, function, method, access) {
    return (deviceType << 16) | (access << 14) | (function << 2) | method
}

NtCreateFile(filename, desiredAccess, shareMode, createDisposition, createOptions, fileAttributes) {

    pathBuf := Buffer(2 * StrPut(filename, "UTF-16"))
    StrPut(filename, pathBuf, "UTF-16")

    uniStr    := Buffer(2 * A_PtrSize, 0)
    objAttrib := Buffer(6 * A_PtrSize, 0)
    ioStatus  := Buffer(2 * A_PtrSize, 0)

    DllCall("ntdll\RtlInitUnicodeString", "ptr", uniStr, "ptr", pathBuf)

    NumPut("uint", 6 * A_PtrSize, objAttrib, 0)             ; Length
    NumPut("ptr",  uniStr.Ptr,    objAttrib, 2 * A_PtrSize) ; ObjectName

    DllCall("ntdll\ZwCreateFile",
        "ptr*", &hFile := 0,
        "uint", desiredAccess,
        "ptr",  objAttrib,
        "ptr",  ioStatus,
        "ptr",  0,
        "uint", fileAttributes,
        "uint", shareMode,
        "uint", createDisposition,
        "uint", createOptions,
        "ptr",  0,
        "uint", 0,
        "uint")

    return hFile
}

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

Скрипт должен переключать состояние CapsLock. У меня работает.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

7

Re: AHK: AHK V2 управление светодиодом caps lock (индикация раскладки)

teadrinker пишет:

Скрипт должен переключать состояние CapsLock. У меня работает.

Большое спасибо за помощь. Перебирая kbdIndex на цифре 7 заработало включение. Но не выключение. Если светодиод выключен то включается, но если включён, то скриптом не выключается.

8

Re: AHK: AHK V2 управление светодиодом caps lock (индикация раскладки)

Попробуйте такой:

#Requires AutoHotkey v2

led := KeyboardLED(7) ; ваш индекс клавиатуры

^1:: led.CapsLock := 1 ; включение
^2:: led.CapsLock := 0 ; отключение

class KeyboardLED
{
    static SCROLL_LOCK := 0x0001
    static NUM_LOCK    := 0x0002
    static CAPS_LOCK   := 0x0004

    static LED_MASK := 0x0007
    static kip_size := 4 ; KEYBOARD_INDICATOR_PARAMETERS_SIZE

    ; kbdIndex — index of keyboard (probably 0 or 2)
    __New(kbdIndex := 0) {
        this.hDevice := KeyboardLED.CreateFile('\\.\GLOBALROOT\Device\KeyboardClass' . kbdIndex)
    }

    __Delete() => DllCall('CloseHandle', 'Ptr', this.hDevice)

    ; setters accept 'on', 'off', 'switch' or 1, 0, -1
    NumLock {
        get => KeyboardLED.GetKey(this.hDevice, KeyboardLED.NUM_LOCK)
        set => KeyboardLED.SetKey(this.hDevice, KeyboardLED.NUM_LOCK, value)
    }

    CapsLock {
        get => KeyboardLED.GetKey(this.hDevice, KeyboardLED.CAPS_LOCK)
        set => KeyboardLED.SetKey(this.hDevice, KeyboardLED.CAPS_LOCK, value)
    }

    ScrollLock {
        get => KeyboardLED.GetKey(this.hDevice, KeyboardLED.SCROLL_LOCK)
        set => KeyboardLED.SetKey(this.hDevice, KeyboardLED.SCROLL_LOCK, value)
    }

    GetAll() => KeyboardLED.QueryIndicators(this.hDevice)

    SetAll(ledFlags) => KeyboardLED.SetIndicators(this.hDevice, ledFlags)

    Set(ledMask) {
        currentLeds := KeyboardLED.QueryIndicators(this.hDevice)
        return KeyboardLED.SetIndicators(this.hDevice, currentLeds | ledMask)
    }

    Clear(ledMask) {
        currentLeds := KeyboardLED.QueryIndicators(this.hDevice)
        return KeyboardLED.SetIndicators(this.hDevice, currentLeds & (ledMask ^ KeyboardLED.LED_MASK))
    }

    Toggle(ledMask) {
        currentLeds := KeyboardLED.QueryIndicators(this.hDevice)
        return KeyboardLED.SetIndicators(this.hDevice, currentLeds ^ ledMask)
    }

    static GetKey(hDevice, key) => !!(this.QueryIndicators(hDevice) & key)

    static SetKey(hDevice, key, cmd) {
        currentLeds := this.QueryIndicators(hDevice)
        switch cmd, false {
            case 'switch', -1 : keyLed := currentLeds ^ key
            case 'on'    ,  1 : keyLed := currentLeds | key
            case 'off'   ,  0 : keyLed := currentLeds & (key ^ this.LED_MASK)
            default           : throw Error('Incorrect cmd')
        }
        return this.SetIndicators(hDevice, keyLed)
    }

    static QueryIndicators(hDevice) {
        ioctlQuery := this.CTL_CODE(0x10) ; KBD_QUERY_FUNCTION
        inBuf  := Buffer(this.kip_size, 0)
        outBuf := Buffer(this.kip_size, 0)
        DllCall('DeviceIoControl', 'Ptr', hDevice, 'UInt', ioctlQuery,
                                   'Ptr',  inBuf, 'UInt', this.kip_size,
                                   'Ptr', outBuf, 'UInt', this.kip_size,
                                   'UInt*', &ret := 0, 'Ptr', 0)
        return NumGet(outBuf, 2, 'UShort')
    }

    static SetIndicators(hDevice, ledFlags) {
        ioctlSet := this.CTL_CODE(0x2) ; KBD_SET_FUNCTION
        return DllCall('DeviceIoControl', 'Ptr', hDevice, 'UInt', ioctlSet,
                                          'Int*', ledFlags << 16, 'UInt', this.kip_size,
                                          'Ptr', 0, 'UInt', 0, 'UInt*', &ret := 0, 'Ptr', 0)
    }

    static CTL_CODE(function) {
        static FILE_DEVICE_KEYBOARD := 0x0b, FILE_ANY_ACCESS := 0, METHOD_BUFFERED := 0
             , opt := (FILE_DEVICE_KEYBOARD << 16) | (FILE_ANY_ACCESS << 14) | METHOD_BUFFERED
        return opt | (function << 2)
    }

    static CreateFile(devPath) {
        static shareFlag := (FILE_SHARE_READ  := 0x1)
                          | (FILE_SHARE_WRITE := 0x2)
             , OPEN_EXISTING := 3, INVALID_HANDLE_VALUE := -1

        res := DllCall('CreateFile', 'Str', devPath, 'UInt', 0, 'UInt', shareFlag, 'Ptr', 0
                                   , 'UInt', OPEN_EXISTING, 'UInt', 0, 'UInt', 0, 'Ptr')
        if (res = INVALID_HANDLE_VALUE)
            throw Error('CreateFile failed. Error: INVALID_HANDLE_VALUE')
        return res
    }
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

9

Re: AHK: AHK V2 управление светодиодом caps lock (индикация раскладки)

teadrinker пишет:

Попробуйте такой:

Ещё раз спасибо, но этот совсем не работает, просто висит в фоне.

Script lines most recently executed (oldest first).  Press [F5] to refresh.  The seconds elapsed between a line and the one after it is in parentheses to the right (if not 0).  The bottommost line's elapsed time is the number of seconds since it executed.

---- C:\Users\NS\Documents\AutoHotkey\led3.ahk
003: led := KeyboardLED(7)
010: KeyboardLED.SCROLL_LOCK := 0x0001
011: KeyboardLED.NUM_LOCK := 0x0002
012: KeyboardLED.CAPS_LOCK := 0x0004
014: KeyboardLED.LED_MASK := 0x0007
015: KeyboardLED.kip_size := 4
000: }
019: this.hDevice := KeyboardLED.CreateFile('\\.\GLOBALROOT\Device\KeyboardClass' . kbdIndex)
097: Static shareFlag := (FILE_SHARE_READ  := 0x1) | (FILE_SHARE_WRITE := 0x2)
097: Static OPEN_EXISTING := 3
097: Static INVALID_HANDLE_VALUE := -1
101: res := DllCall('CreateFile', 'Str', devPath, 'UInt', 0, 'UInt', shareFlag, 'Ptr', 0 , 'UInt', OPEN_EXISTING, 'UInt', 0, 'UInt', 0, 'Ptr')
103: If (res = INVALID_HANDLE_VALUE)
105: Return res
020: }
005: {
006: {
008: KeyboardLED
008: {
018: {
022: {
026: {
027: {
031: {
032: {
036: {
037: {
040: {
042: {
044: {
049: {
054: {
059: {
061: {
072: {
083: {
090: {
096: {
108: Exit (27.55)

Press [F5] to refresh.

10

Re: AHK: AHK V2 управление светодиодом caps lock (индикация раскладки)

А если Ctrl + 1 или Ctrl + 2 нажать?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder