我有一个关于Tcl/Tk(8.6版本,Ubuntu 14.04)的神秘问题。当我按下一个按钮(例如返回)一段时间并释放它时,程序不会对进一步的按键做出正确的反应:它忽略了一些按键,并产生错误的按键代码(通常是按键保持较长时间的那个,即使按下了其他一些按键)。如果事件处理程序花费一些时间(这里使用after
模拟),则会出现问题。
这是我的脚本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
运行脚本,将焦点移动到窗口并按下并按住Return键几秒钟,我一直得到这样的输出行
keyHandler (t=1474120548284090): (Return) (36) (65293)
在释放键后也会持续一段时间,我认为这是预期的行为。但是当这些输出结束时,按下更多的键(与Return不同)会导致错误的行为(忽略按键,传递错误的键代码)。
对我来说,似乎有些关键事件队列溢出。
我非常感谢任何帮助,谢谢!
编辑:我试图用一个普通的X11程序重现错误,我认为它与Tk主循环类似,但这里的效果是不可见的:// 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 displayn");
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): %xn", cnt, event.xkey.keycode );
/* exit on ESC key press */
if ( event.xkey.keycode == 0x09 )
break;
/* Return */
if (event.xkey.keycode == 0x24) {
printf("Entern");
for (int i = 0; i < 10000; i++)
for (int j = 0; j < 40000; j++) {}
}
}
else if (event.type == KeyRelease){
printf( "KeyRelease (%ld): %xn", cnt, event.xkey.keycode );
}
cnt++;
}
/* close connection to server */
XCloseDisplay(display);
return 0;
}
(您可能需要为您的机器调整循环迭代的次数。)这难道不表明问题出在Tcl/Tk上吗?
Tk将在两种情况下使用相同的代码来处理事件,至少除非在一种情况下与输入法有奇怪的交互,而在另一种情况下没有。据我所知,键盘事件在运行Ubuntu的不同系统之间排队是相同的;这只是通常的X11键盘处理,KeyEvent
通过GUI系统的事件队列传递。理论上,在Thinkpad的情况下,您可能会在服务器端填充缓冲区,而桌面系统的不同速度更能够跟上。也许…?
是的,我建议您编写代码来更快地为事件队列提供服务(我知道,这可能根本不是一件微不足道的事情),失败的根源最终在于Tcl/Tk没有负责的系统部分。
一位同事建议我运行im-config -a
并选择"none"作为"active configuration",而不是之前的"ibus"(它产生一个包含行run_im none
的文件~/.xinputrc
)。如果我这样做,问题似乎在笔记本电脑上消失(重新启动X后),但到目前为止我不知道为什么。在我的PC上(问题没有发生),im-config -a
将"missing"列为"active configuration"。
所以Donal Fellows关于"与输入法的奇怪交互"的预感似乎是正确的。你能详细解释一下你的评论吗?