2016-09-17 2 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)

также в течение некоторого времени после отпускания ключа, который я думаю, это ожидаемое поведение. Но когда эти выходы заканчиваются, нажатие дополнительных клавиш (отличное от 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?

+0

Я только что обнаружил, что проблема возникает только на моем Lenovo ThinkPad T530.С той же версией Tk и той же версией Ubuntu на моем настольном ПК (доступ с удаленного компьютера) этого не происходит. Любая идея, где проблема может быть найдена? – Ralf

+0

Что-то с клавиатурным драйвером на Thinkpad становится несчастным? Если это специфично для какого-то оборудования, довольно сложно охотиться за людьми (такими как я!) С разными конфигурациями системы ... –

+1

Я смог дублировать проблему при запуске IME. Выключил IME, и проблема исчезла. Очень вероятно какое-то взаимодействие системы. –

ответ

2

Tk будет использовать идентичный код в двух случаях для обработки событий, по крайней мере, если не будет странного взаимодействия с методом ввода в одном случае, а не другом. Насколько я знаю, события клавиатуры помещаются в очередь одинаково между различными системами, работающими под управлением Ubuntu; это обычная обработка клавиатуры X11, причем KeyEvent s передается через очередь событий системы GUI. Теоретически, вы можете заполнить буфер на стороне сервера в корпусе Thinkpad, в то время как разная скорость работы системы с рабочим столом больше в состоянии поддерживать скорость. Может быть…?

В то время как да, я предлагаю написать свой код, чтобы быстрее обслуживать очередь событий (что может быть не совсем тривиально, я знаю), отказ в конечном счете уходит корнями в части системы, которые Tcl/Tk не делает есть ответственность.

+0

Эффект не возникает в чистой программе X11. Я продолжу свой вопрос с помощью кода. – Ralf

0

коллега посоветовал мне бежать im-config -a и выберите «нет» в качестве «активной конфигурации» вместо ранее «IBUs» (который производит файл ~/.xinputrc, содержащий строку run_im none). Если я это сделаю, проблема, похоже, исчезнет на ноутбуке (после перезапуска X), но до сих пор я понятия не имею, почему. На моем ПК (где проблема не возникла), im-config -a перечислены как «активная конфигурация».

Так что кажется, что Donal Fellows предполагают, что «странное взаимодействие с методом ввода» было правильным. @Donal Fellows: можете ли вы подробнее рассказать о своем комментарии?

@Brad Lanam: Я просто вижу, что вы, вероятно, также подразумевали «редактор методов ввода» от «IME», поэтому вы были правы.

+1

Если перезапуск ibus IME перезагружен, Tk выйдет из строя с ошибкой сегментации. Я подозреваю (например, предполагаю), что в обеих программах делаются различные ключевые манипуляции, и они плохо взаимодействуют друг с другом. –

Смежные вопросы