Por que alguns aplicativos deixam os eventos KeyRelease serem consumidos pelo próximo aplicativo / janela focado?

1

Estou tentando incluir dmenu em algum script para alimentá-lo e agir sobre ele, no entanto, ao pressionar o botão Voltar tecla para selecionar alguma entrada dmenu, um evento KeyRelease é enviado para qualquer janela que esteja focada quando o dmenu é fechado. Se esse aplicativo reagir a ele (no meu caso aconteceu com o javascript no Firefox), coisas indesejadas podem acontecer.

Mas isso não é específico para o meu script ou mesmo para o dmenu. Isso também acontece com outros aplicativos X de estilo de diálogo que testei, em particular o ssh-askpass, o ksshaskpass, o diálogo da frase-senha do gpg, etc.

Um teste simples é o seguinte:

  1. Vincule ssh-askpass a uma chave (combinação). Eu uso minha configuração do i3-wm para isso.
  2. Execute o seguinte em um terminal:

    xev | grep -EA2 --line-buffered '^Key(Press|Release)' | sed -n 's/^.*\(Press\|Release\|keysym[^)]*\).*$//p'
    
  3. Pressione a combinação de teclas associadas.
  4. Pressione Return, observe a seguinte saída no terminal:

    Release
    keysym 0xff0d, Return
    
  5. Não observe um Press anterior de Return

Por que esses aplicativos não consomem Release da fila de eventos X? Eu diria um bug - mas no X ou no aplicativo?

Ao envolver esse aplicativo com um script (python?), como posso corrigir isso?

    
por Klaas 23.02.2015 / 19:33

1 resposta

1

Geralmente, não se espera que um aplicativo que manipulou um evento KeyPress manipule o evento KeyRelease subsequente. Se o usuário pressionar uma tecla, alternar para outro aplicativo e, em seguida, liberar a chave, a mudança de foco deverá ocorrer quando solicitada, não deverá ser adiada até que o usuário tenha liberado a chave.

A arquitetura do X11 para manipular eventos de entrada é bem simples: ou o evento foi capturado por um cliente, caso em que o cliente recebe o evento ou o evento não foi capturado; nesse caso, o cliente que atualmente possui o evento foco recebe o evento. Não há nenhuma disposição para despachar eventos KeyRelease separadamente com base em qual cliente recebeu o evento KeyPress .

Um exemplo em que seria claramente errado redirecionar KeyRelease eventos para o cliente que recebeu o KeyPress com modificadores. Em uma mudança de foco, se um modificador for pressionado, ele permanecerá pressionado. O evento KeyRelease é enviado quando o modificador não está mais pressionado. Embora possa fazer sentido enviar KeyRelease eventos para todos os modificadores deprimidos em uma perda de foco e enviar os eventos KeyPress correspondentes para a janela recém-focalizada, isso não seria um relatório preciso da entrada real do usuário, que seria especialmente disruptivo para mudanças de foco entre widgets do mesmo aplicativo.

Outro exemplo em que o comportamento do X11 está claramente correto e sua proposta de reencaminhar eventos de pressionamento de tecla seria errada é com alterações de foco entre os widgets do mesmo aplicativo. Seria errado enviar eventos espúrios se o aplicativo se importar com essa chave específica sem se importar com qual widget estava focado. Mas, se o aplicativo se importar com qual widget recebe o evento KeyRelease , esse evento definitivamente deve ser enviado para o widget que tem o foco no momento.

A maioria dos aplicativos tem ações acionadas por eventos de pressionamento de tecla, não por eventos de lançamento de chave. Quando um evento faz com que um botão seja pressionado, espera-se que o efeito do botão seja acionado no momento da impressão, não no momento da liberação. Seria uma experiência estranha do usuário se os eventos que causassem o fechamento de uma janela tivessem um comportamento diferente.

Um exemplo em que é claramente a coisa certa deixar o foco ser transferido para outra janela quando uma tecla pressionada causou o fechamento de uma janela é manter a tecla Esc pressionada para sair de vários diálogos caixas. Seria perturbador se um aplicativo exigisse liberar a tecla Esc a ser liberada para fechar uma janela.

No cenário que você descreve, é claramente o aplicativo Firefox / JavaScript que está fazendo algo errado. A maioria das interfaces de teclado é baseada em pressionamentos de teclas, não em liberações de chave. Em particular, é pressionando Enter que supostamente faz com que algo aconteça, não liberando ele. Se um aplicativo reage a um evento de lançamento de chave, o ônus está nele para lidar com situações em que ele recebe um evento KeyRelease sem ter recebido um KeyPress correspondente de uma maneira sensata.

Os cliques do mouse são um pouco diferentes porque há muitas situações em que se espera que uma interface reaja a eventos de lançamento, como arrastar e soltar ou eventos que dependem da duração de um clique. Mesmo assim, um aplicativo geralmente não deve reagir a um evento ButtonRelease se não obtiver o ButtonPress correspondente.

    
por 25.02.2015 / 01:13