Como faço para criar uma tecla de atalho para uma sequência de entradas enquanto segura Ctrl, por exemplo, {Ctrl Down}ec{Ctrl Up}?

Como faço para criar uma tecla de atalho para uma sequência de entradas enquanto segura Ctrl, por exemplo, {Ctrl Down}ec{Ctrl Up}?

Por exemplo, no Visual Studio Express 2013, muitos dos atalhos de formatação foram "dobrados" em Ctrl+ E. Para comentar uma seleção, basta segurar Ctrl, bater E, bater C,entãoliberar Ctrl.

    insira a descrição da imagem aqui

Se eu fosseenviandotal entrada, eu escreveria

SendInput {Ctrl Down}ec{Ctrl Up}

Mas como faço para transformar essa sequência em uma tecla de atalho? tentei

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

mas é claro que isso causa um erro de sintaxe:

    insira a descrição da imagem aqui

Responder1

Finalmente descobri.

dr.

Substitua ^epela primeira tecla desejada. Substitua 3pelo índice ASCII do segundo pressionamento de tecla desejado. Isso impõe que Ctrlseja mantido pressionado por ambas as teclas, caso contrário, cancela.

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

Para adaptar isso Shiftem vez de Ctrl, você teria que substituir o Ctrls, remover o Me fazer uma comparação mais simples, como OutputVar = Cem vez do Asc(OutputVar) = 3. Não tenho certeza de como estender isso Alt, mas Wintalvez você precise tentar L2algo do tipo.

Explicação

Inputparecia um lugar óbvio para começar. Inputpede ao AHK para aguardar a entrada do usuário,por exemplo

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

A caixa de mensagem acima é acionada CtrlEentão C. Mas estamos procurando CtrlC, então vamos consertar isso:

^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

Agora temos uma caixa de mensagem ao pressionar CtrlEthen CtrlC. Mas há um problema com isso: a caixa de mensagem é acionada mesmo quando euliberar Ctrlentre as duas teclas. Então, como detectamos essencialmente uma {Ctrl Up}entrada intermediária? Você não pode simplesmente verificar a entrada—

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

—nem você pode simplesmente verificar após inserir—

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

- nem você consegue fazer as duas coisas, porque não importa o que aconteça, você perderá o {Ctrl Up}bloqueio para entrada.

Então eu olhei paradocumentação sobreHotkeypara inspiração. O operador de combinação personalizado, &parecia promissor. Mas infelizmente,

^e & ^c::
    ; ...

causou um erro de compilação; aparentemente &é para combinarnão modificadoapenas teclas digitadas.

Finalmente, chegou a hora UP, e foi aí que finalmente fiz a descoberta. Eu redefini Ctrlpara UPdefinir umalternarisso impediria o acionamento da caixa de mensagem!

$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

Agora, quando pressiono CtrlE, depois solto Ctrle pressiono CtrlC, nada acontece, como esperado!

Havia uma última coisa a consertar. No “cancelamento” (um “acorde quebrado”), eu queria que todas as teclas digitadas voltassem ao normal. Mas no código acima, Inputseria necessário "comer" uma tecla antes de retornar, independentemente de um acorde quebrado ou uma tecla secundária irrelevante. Adicionar um Elsecaso resolve isso muito bem:

    Else
    {
        SendInput %OutputVar%
    }

Então, aí está - "acordes" no AutoHotkey. (Embora eu não chamaria isso exatamente de "acorde". Mais como ummelodia, com uma linha de baixo ;-)


@hippibruder ressalta generosamente que posso evitar a definição $Ctrl::usando ~para tornar $Ctrl UP::o não bloqueio. Isso permite alguma simplificação! (Veja a seção tl;dr na parte superior para ver o resultado final.)


Mais uma coisa. Se, por acaso, após o "cancelamento" (um "acorde quebrado"), você quiser pressionar a primeira tecla,ou seja CtrlEpor si só, basta adicionar isso no Elsebloco,

    Else
    {
        SendInput ^e
        SendInput %OutputVar%
    }

e não se esqueça de mudar a tecla de atalho para

$^e::

para evitar um loop infinito.

Responder2

Não acho que haja suporte integrado para acordes principais no AHK. Uma maneira de detectá-los seria registrar uma tecla de atalho para a primeira tonalidade do acorde (^e) e então usar o Input-Command para detectar as próximas tonalidades.

; 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

informação relacionada