포장하려고 하는데메뉴일부 스크립트에서는 입력이 제공되고 조작되지만 Return 키를 눌러 일부 dmenu 입력을 선택하면 KeyRelease 이벤트가 dmenu가 닫힐 때 초점이 맞춰진 창으로 전송됩니다. 응용 프로그램이 이에 반응하면(제 경우에는 Firefox의 javascript에서 발생했습니다) 원치 않는 일이 발생할 수 있습니다.
그러나 이것은 내 스크립트나 심지어 dmenu에만 국한된 것이 아닙니다. 이는 제가 테스트한 다른 대화 상자 스타일 X 응용 프로그램, 특히 ssh-askpass, ksshaskpass, gpg 암호 대화 상자 등에서도 발생합니다.
간단한 테스트는 다음과 같습니다.
- ssh-askpass를 키(조합)에 바인딩합니다. 이를 달성하기 위해 i3-wm 구성을 사용합니다.
터미널에서 다음 명령을 실행합니다.
xev | grep -EA2 --line-buffered '^Key(Press|Release)' | sed -n 's/^.*\(Press\|Release\|keysym[^)]*\).*$/\1/p'
- 바운드 키 조합을 누르십시오.
Enter를 누르고 터미널에서 다음 출력을 관찰합니다.
Release keysym 0xff0d, Return
Press
과거 를 관찰하지 마세요Return
Release
이러한 애플리케이션이 X 이벤트 큐의 이벤트를 사용하지 않는 이유는 무엇입니까 ? 제 생각에는 이것이 버그인 것 같습니다. 하지만 X에서인가요, 아니면 애플리케이션에서인가요?
이와 같은 애플리케이션을 (파이썬?) 스크립트로 래핑할 때 이 문제를 어떻게 해결할 수 있습니까?
답변1
이미 이벤트를 처리한 애플리케이션은 KeyPress
일반적으로 후속 이벤트를 처리하지 않습니다 KeyRelease
. 사용자가 키를 누른 다음 다른 애플리케이션으로 전환한 다음 키를 놓으면 요청 시 포커스 변경이 발생할 것으로 예상되며 사용자가 키를 놓을 때까지 지연되어서는 안 됩니다.
X11에서 입력 이벤트를 처리하기 위한 아키텍처는 매우 간단합니다. 클라이언트가 이벤트를 포착한 경우 클라이언트가 이벤트를 받거나 이벤트가 아직 포착되지 않은 경우 현재 포커스가 있는 클라이언트가 이벤트를 받습니다. 이벤트. 이벤트를 KeyRelease
수신한 클라이언트에 따라 KeyPress
이벤트를 개별적으로 전달하는 규정은 없습니다 .
KeyRelease
이벤트를 수신하는 클라이언트로 이벤트를 다시 라우팅하기 위해 수정자를 사용하는 예는 분명히 잘못된 것입니다. KeyPress
초점이 변경될 때 수정자를 누르면 누른 상태가 유지됩니다. KeyRelease
이 이벤트는 수정자 키를 더 이상 누르지 않을 때 전송됩니다. KeyRelease
포커스가 손실되었을 때 누른 모든 수정자에 대한 이벤트를 보내고 새로 포커스된 창에 해당 이벤트를 보내는 것이 합리적일 수 있지만 KeyPress
이는 실제 사용자 입력에 대한 정확한 보고가 아니며 특히 파괴적인 창 사이의 포커스 변경에 대한 경우입니다. . 동일한 애플리케이션에 대한 위젯.
X11 동작이 분명히 정확하고 키 이벤트를 다시 라우팅하라는 제안이 잘못된 또 다른 예는 동일한 애플리케이션의 위젯 간에 포커스가 변경되는 경우입니다. 애플리케이션이 이 특정 키에 관심을 갖고 어떤 위젯에 초점이 맞춰져 있는지는 신경 쓰지 않는다면 가짜 이벤트를 보내는 것은 오류가 될 것입니다. 그러나 앱이 어떤 위젯이 KeyRelease
이벤트를 수신하는지에 관심이 있다면 해당 이벤트는 당시 포커스가 있는 위젯으로 확실히 전송되어야 합니다.
대부분의 애플리케이션 작업은 키 놓기 이벤트가 아닌 키 누름 이벤트에 의해 트리거됩니다. 이벤트로 인해 버튼이 눌리면 버튼을 눌렀을 때가 아니라 버튼을 눌렀을 때 버튼의 효과가 실행될 것으로 예상됩니다. 창을 닫는 이벤트가 다르게 동작한다면 이는 이상한 사용자 경험이 될 것입니다.
키를 눌러 창이 닫힐 때 포커스를 다른 창으로 옮기는 것이 분명히 올바른 예는 Esc키를 눌러 여러 대화 상자를 종료하는 것입니다. 응용 프로그램이 창을 닫기 위해 키를 놓아야 하는 경우 Esc이는 파괴적입니다 .
설명하신 시나리오에서는 분명히 문제가 있는 것은 Firefox/JavaScript 애플리케이션입니다. 대부분의 키보드 인터페이스는 키를 놓는 것이 아니라 키를 누르는 것을 기반으로 합니다. 특히,긴급한 Enter이로 인해 대신에 뭔가가 발생해야 합니다.해방됨그것. 애플리케이션이 키 릴리스 이벤트에 반응하는 경우 KeyRelease
일치 항목이 수신되지 않고 이벤트가 수신되는 상황을 합리적인 방식으로 처리하는 것은 애플리케이션의 책임입니다 .KeyPress
마우스 클릭은 약간 다릅니다. 대부분의 경우 인터페이스는 드래그 앤 드롭이나 클릭 지속 시간에 따른 이벤트와 같은 릴리스 이벤트에 반응해야 하기 때문입니다. 그럼에도 불구하고 애플리케이션이 ButtonRelease
해당 ButtonPress
.