Finalmente descobri.
tl; dr
Substitua ^e
pelo primeiro pressionamento de tecla desejado. Substitua 3
pelo índice ASCII do segundo pressionamento de tecla desejado. Isso impõe que a Ctrl seja mantida através de ambos os pressionamentos de tecla, 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 a Shift ao invés de Ctrl , você teria que substituir o Ctrl
s, remover o M
e fazer um comparação mais simples como OutputVar = C
em vez de Asc(OutputVar) = 3
. Não sei como estender isso para Alt
e Win
, mas você pode ter que tentar L2
ou algo do tipo.
Explicação
Input
parecia um lugar óbvio para começar. Input
pede ao AHK que aguarde 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 dispara em Ctrl E e depois em C . Mas nós estamos procurando Ctrl C , então vamos corrigir 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 Ctrl E e depois Ctrl C . Mas há um problema com isso: a caixa de mensagem é acionada mesmo quando eu libero Ctrl entre os dois pressionamentos de tecla. Então, como detectamos essencialmente uma {Ctrl Up}
mid-input? Você não pode simplesmente verificar a entrada -
^e::
if (!GetKeyState("Ctrl"))
{
Return
}
Input, OutputVar, L1 M
; ...
—não pode simplesmente verificar após a entrada -
^e::
Input, OutputVar, L1 M
if (!GetKeyState("Ctrl"))
{
Return
}
; ...
- você não pode nem mesmo fazer as duas coisas, porque não importa o quê, você perderá o {Ctrl Up}
enquanto bloqueia a entrada.
Depois, procurei na documentação sobre Hotkey
como inspiração. O operador de combinação personalizada, &
, parecia promissor. Mas infelizmente,
^e & ^c::
; ...
causou um erro de compilação; aparentemente, o &
é para combinar apenas as teclas não modificadas .
Finalmente, foi até UP
, e é aí que eu finalmente fiz a descoberta. Redefinei UP
do Ctrl para definir um alternância que 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 pressionar Ctrl E , solte a Ctrl e pressione Ctrl C , nada acontece, como esperado!
Houve uma última coisa para corrigir. Em "cancelamento" (um "acorde quebrado"), eu queria que todos os toques de tecla voltassem ao normal. Mas no código acima, o Input
teria que "comer" um pressionamento de tecla antes de retornar, independentemente de um acorde quebrado ou de um pressionamento de tecla secundário irrelevante. Adicionar um Else
resolve bem isso:
Else
{
SendInput %OutputVar%
}
Então, você tem isso - "acordes" no AutoHotkey. (Apesar de eu não chamar exatamente isso de "acorde". Mais como uma melodia , com uma linha de baixo; -)
@hippibruder generosamente aponta que eu posso evitar definir $Ctrl::
usando ~
para tornar $Ctrl UP::
sem bloqueio. Isso permite alguma simplificação! (Veja a seção dr no topo para o resultado final.)
Mais uma coisa. Se, por acaso, sobre "cancelamento" (um "acorde quebrado"), você gostaria de emitir o primeiro toque de tecla, ie Ctrl E por conta própria, basta adicionar isso no bloco Else
,
Else
{
SendInput ^e
SendInput %OutputVar%
}
e não se esqueça de mudar a tecla de atalho para
$^e::
para evitar um loop infinito.