У меня есть таинственная проблема с Tcl/Tk (версия 8.6, Ubuntu 14.04). Когда я удерживаю кнопку (например, Return) нажатой в течение некоторого времени и отпускаю ее, программа не реагирует должным образом на дальнейшие нажатия клавиш: она игнорирует некоторые нажатия клавиш и выдает неправильный код ключа (обычно тот, который удерживается нажатой клавишей дольше, даже если был нажат какой-то другой ключ). Проблема возникает, если обработчик события занимает некоторое время (здесь моделируется с использованием after
).tcl/tk: ошибка переполнения очереди событий ключевого события?
Вот мой сценарий testKey.tcl
:
proc keyHandler {keySym keyCode keySymNum} {
puts "keyHandler (t=[clock clicks]): ($keySym) ($keyCode) ($keySymNum)"
flush stdout
if {$keySym == "Return"} { after 500 }
}
bind . <KeyPress> "keyHandler %K %k %N"
Если я запустить сценарий с wish testKey.tcl
, переместите курсор к окну и нажмите и удерживайте клавишу возврата в течение нескольких секунд, я получаю выходные линии, как это
keyHandler (t=1474120548284090): (Return) (36) (65293)
также в течение некоторого времени после отпускания ключа, который я думаю, это ожидаемое поведение. Но когда эти выходы заканчиваются, нажатие дополнительных клавиш (отличное от Return) приводит к ошибочному поведению (игнорируются нажатия клавиш, неправильные коды клавиш).
Для меня это выглядит так, как если бы какая-то очередь ключевых событий переполнялась.
Я очень благодарен за любую помощь, спасибо!
Edit: Я пытался воспроизвести ошибку с простой программой X11, который я предполагаю, делает подобную вещь в основной цикл Тк, но здесь эффект не виден:
// modified from https://gist.github.com/javiercantero/7753445
// g++ -o xreadkeys xreadkeys.C -lX11
#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
Display *display;
Window window;
XEvent event;
int s;
/* open connection with the server */
display = XOpenDisplay(NULL);
if (display == NULL) {
fprintf(stderr, "Cannot open display\n");
exit(1);
}
s = DefaultScreen(display);
/* create window */
window = XCreateSimpleWindow(display, RootWindow(display, s),
10, 10, 200, 200, 1,
BlackPixel(display, s),
WhitePixel(display, s));
/* select kind of events we are interested in */
XSelectInput(display, window, KeyPressMask | KeyReleaseMask);
/* map (show) the window */
XMapWindow(display, window);
/* event loop */
long cnt = 0;
while (1) {
XNextEvent(display, &event);
/* keyboard events */
if (event.type == KeyPress) {
printf("KeyPress (%ld): %x\n", cnt, event.xkey.keycode);
/* exit on ESC key press */
if (event.xkey.keycode == 0x09)
break;
/* Return */
if (event.xkey.keycode == 0x24) {
printf("Enter\n");
for (int i = 0; i < 10000; i++)
for (int j = 0; j < 40000; j++) {}
}
}
else if (event.type == KeyRelease){
printf("KeyRelease (%ld): %x\n", cnt, event.xkey.keycode);
}
cnt++;
}
/* close connection to server */
XCloseDisplay(display);
return 0;
}
(Вы, возможно, придется отрегулируйте количество итераций цикла для вашего компьютера.) Не означает ли это, что проблема связана с Tcl/Tk?
Я только что обнаружил, что проблема возникает только на моем Lenovo ThinkPad T530.С той же версией Tk и той же версией Ubuntu на моем настольном ПК (доступ с удаленного компьютера) этого не происходит. Любая идея, где проблема может быть найдена? – Ralf
Что-то с клавиатурным драйвером на Thinkpad становится несчастным? Если это специфично для какого-то оборудования, довольно сложно охотиться за людьми (такими как я!) С разными конфигурациями системы ... –
Я смог дублировать проблему при запуске IME. Выключил IME, и проблема исчезла. Очень вероятно какое-то взаимодействие системы. –