7

Например, в Visual Studio Express 2013 многие ярлыки форматирования были "свернуты" в Ctrl+E. Чтобы прокомментировать выбор, нужно было удерживать нажатой клавишу Ctrl, нажимать E, нажимать C, а затем отпускать Ctrl.

    

Если бы я отправлял такой вклад, я бы написал

SendInput {Ctrl Down}ec{Ctrl Up}

Но как мне сделать эту последовательность горячей клавишей? Я старался

{Ctrl Down}EC{Ctrl Up}::
    MsgBox, "Hello, world!"
    Return

но, конечно, это вызывает синтаксическую ошибку:

    

2 ответа2

7

Наконец-то разобрался.

ТЛ; др

Замените ^e первым желаемым нажатием клавиши. Замените 3 индексом ASCII второго желаемого нажатия клавиши. Это гарантирует, что Ctrl удерживается нажатием обеих клавиш, иначе отменяется.

~$Ctrl UP::
    ChordIsBroken := True
    Return
^e::
    ChordIsBroken := False
    Input, OutputVar, L1 M
    If (!ChordIsBroken && Asc(OutputVar) = 3)
    {
        MsgBox "Hello, World!"
    }
    Else
    {
        SendInput %OutputVar%
    }
    Return

Чтобы адаптировать это к Shift вместо Ctrl, вам нужно заменить Ctrl s, удалить M и сделать более простое сравнение, например OutputVar = C вместо Asc(OutputVar) = 3 . Не уверен, как распространить это на Alt и Win но вам, возможно, придется попробовать L2 или что-то в этом роде.

объяснение

Input казался очевидным местом для начала. Input просит AHK ждать ввода пользователя, например

^e::
    Input, OutputVar, L1        ; "L1" means wait for 1 keystroke then continue.
    If (OutputVar = "c")
    {
        MsgBox, "Hello, World!"
    }
    Return

Окно сообщения выше вызывает по Ctrl E затем C. Но мы ищем Ctrl C, так что давайте исправим это:

^e::
    Input, OutputVar, L1 M      ; "M" allows storage of modified keystrokes (^c).
    If (Asc(OutputVar) = 3)     ; ASCII character 3 is ^c.
    {
        MsgBox "Hello, World!"
    }
    Return

Теперь у нас есть окно сообщения о нажатии Ctrl E, а затем Ctrl C. Но есть проблема с этим: окно сообщения срабатывает, даже когда я нажимаю Ctrl между двумя нажатиями клавиш. Итак, как мы можем определить, по существу, {Ctrl Up} средний ввод? Вы не можете просто проверить на входе

^e::
    if (!GetKeyState("Ctrl"))
    {
        Return
    }
    Input, OutputVar, L1 M 
    ; ...

Не можете просто проверить после ввода

^e::
    Input, OutputVar, L1 M 
    if (!GetKeyState("Ctrl"))
    {
        Return
    }
    ; ...

- ни один из них не сработает, потому что, несмотря ни на что, вы пропустите {Ctrl Up} при блокировке ввода.

Затем я заглянул в документацию по Hotkey для вдохновения. Оператор пользовательской комбинации & , казалось многообещающим. Но, к сожалению,

^e & ^c::
    ; ...

вызвала ошибку компиляции; по-видимому, & предназначен только для комбинации неизмененных нажатий клавиш.

Наконец-то дело дошло до UP , и вот, наконец, я совершил прорыв. Я переопределил Ctrl 's UP чтобы установить переключатель, который бы препятствовал срабатыванию окна сообщения!

$Ctrl::Send {Ctrl Down}     ; The $ prevents an infinite loop. Although this
$Ctrl UP::                  ; line seems redundant, it is in fact necessary.
    ChordIsBroken := True   ; Without it, Ctrl becomes effectively disabled.
    Send {Ctrl Up}
    Return
^e::
    ChordIsBroken := False
    Input, OutputVar, L1 M
    If (!ChordIsBroken && Asc(OutputVar) = 3)
    {
        MsgBox "Hello, World!"
    }
    Return

Теперь, когда я нажимаю Ctrl E, затем отпускаю Ctrl и нажимаю Ctrl C, ничего не происходит, как ожидалось!

Была одна последняя вещь, которую нужно исправить. При "отмене" ("сломанный аккорд") я хотел, чтобы все нажатия клавиш вернулись в нормальное состояние. Но в приведенном выше коде Input должен был бы "съесть" нажатие клавиши перед возвратом, независимо от разрыва аккорда или неуместного вторичного нажатия клавиши. Добавление случая Else хорошо решает это:

    Else
    {
        SendInput %OutputVar%
    }

Итак, вот оно - "аккорды" в AutoHotkey. (Хотя я бы точно не назвал это "аккордом". Больше похоже на мелодию с басовой линией ;-)


@hippibruder щедро указывает на то, что я могу избежать определения $Ctrl:: с помощью ~ чтобы сделать $Ctrl UP:: неблокирующим. Это позволяет немного упростить! (См. Раздел tl; dr в верхней части для окончательного результата.)


Еще кое-что. Если, случайно, после "отмены" ("разбитый аккорд"), вы хотите выполнить первое нажатие клавиши, то есть Ctrl E , просто добавьте это в блок Else ,

    Else
    {
        SendInput ^e
        SendInput %OutputVar%
    }

и не забудьте изменить горячую клавишу на

$^e::

чтобы избежать бесконечного цикла.

2

Я не думаю, что есть встроенная поддержка ключевых аккордов в AHK. Один из способов их обнаружения - зарегистрировать горячую клавишу для первой клавиши в аккорде (^ e), а затем использовать команду ввода для определения следующих клавиш.

; Tested with AHK_L U64 v1.1.14.03 (and Visual Studio 2010)
; This doesn't block the input. To block it remove '~' from the hotkey and 'V' from Input-Cmd
~^e::
  ; Input-Cmd will capture the next keyinput as its printable representation. 
  ; (i.e. 'Shift-a' produces 'A'. 'a' produces 'a'. 'Ctrl-k' produces nothing printable. This can be changed with 'M' option. Maybe better approch; See help) 
  ; Only the next, because of 'L1'. (Quick-Fail; Not necessary)
  ; To detect 'c' and 'u' with control pressed I used them as EndKeys.
  ; If a EndKey is pressed the Input-Cmd will end and save the EndKey in 'ErrorLevel'.
  Input, _notInUse, V L1 T3, cu

  ; Return if Input-Cmd was not terminated by an EndKey
  ; or 'Control' is no longer pressed. (It would be better if Input-Cmd would be also terminated by a {Ctrl Up}. I don't know if that is possible)
  if ( InStr(ErrorLevel, "Endkey:") != 1
    || !GetKeyState("Control") )
    {
    return
    }

  ; Extract the EndKey-Name from 'ErrorLevel' (ErrorLevel == "Endkey:c")
  key := SubStr(ErrorLevel, 8)    
  if ( InStr(key, "c") == 1 )
    {
    TrayTip,, ^ec
    }
  else if ( InStr(key, "u") == 1 )
    {
    TrayTip,, ^eu
    }
  else
    {
    MsgBox, wut? key="%key%"
    }
return

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .