2016-09-17 38 views
1

我有一个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)

也解除键,我认为这是预期的行为后的一段时间。但是,当这些输出结束时,按下其他键(与返回不同)会导致错误的行为(按键被忽略,错误的键码被输出)。

对我来说,看起来好像某些关键事件队列溢出。

我非常感谢任何帮助,谢谢!

编辑:我试图重现错误与普通的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 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吗?

+0

我刚刚发现问题只出现在我的联想ThinkPad T530。在我的台式电脑上使用相同的Tk版本和相同的Ubuntu版本(从远程访问),它不会发生。任何想法可以找到问题的想法? – Ralf

+0

Thinkpad上的某个键盘驱动程序变得不快乐了?如果这是针对某些硬件的,那么使用不同的系统配置寻找人(如我!)是很难的...... –

+1

我能够在运行IME时复制问题。关闭IME并且问题消失。所以很可能是某种系统交互。 –

回答

2

在两种情况下,Tk将使用相同的代码来处理事件,至少除非在一种情况下与输入法有奇怪的相互作用,而另一种情况则不存在。据我所知,键盘事件在运行Ubuntu的不同系统之间排队相同;这只是通常的X11键盘处理,而KeyEvent则通过GUI系统的事件队列传递。理论上讲,你可能会在Thinkpad的服务器端填充缓冲区,而桌面系统的不同速度更能跟上。也许…?虽然是的,但我建议编写代码以更快速地服务事件队列(根据我所知,这根本不是一件微不足道的事情),故障最终根植于Tcl/Tk系统的某些部分有责任。

+0

该效果在纯X11程序中不会发生。我会用代码扩展我的问题。 – Ralf

0

一个同事劝我跑im-config -a并选择“无”“活性结构”而不是前面的“IBUS”(其产生的文件~/.xinputrc含有线run_im none)。如果我这样做,问题似乎在笔记本电脑上消失(重新启动X后),但到目前为止,我不知道为什么。在我的PC上(问题没有发生的地方),im-config -a列出“缺失”为“主动配置”。

因此,Donal Fellows预测“与输入法的奇怪交互”似乎是正确的。 @Donal Fellows:你能否详细说明你的评论?

@Brad Lanam:我刚才看到你可能也是用“IME”表示“输入法编辑器”,所以你也是对的。

+1

如果ibus IME重新启动,Tk将因分段故障而崩溃。我怀疑(即猜测)在这两个程序中都存在各种关键处理假设,并且它们不能很好地协同工作。 –