2016-09-17 1 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でスクリプトを実行し、ウィンドウを押しにフォーカスを移動し、数秒間Returnキーを押したままにすると、私はこのような出力ラインを取得しておきます私が期待される振る舞いだと思うキーを、解除した後しばらくの間も

keyHandler (t=1474120548284090): (Return) (36) (65293)

。しかし、これらの出力が終了すると、Returnキーとは別のキーを押すと、誤った動作になります(キーの押下は無視され、間違ったキーコードが渡されます)。

私にとって、キーイベントキューがオーバーフローしたように見えます。

ご協力いただきありがとうございます。

編集:私はTkのメインループに同じようなことをすると仮定し、プレーン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バージョンとデスクトップPCの同じUbuntuバージョン(リモートからアクセス)では、それは起こらない。問題がどこに置かれたのか? – Ralf

+0

ThinkPadのキーボード・ドライバーで何かが不幸になってしまった?それがハードウェアに特有のものであれば、私のような人たちをさまざまなシステム構成で探し出すのはかなり難しいです... –

+1

IMEを実行して問題を再現することができました。 IMEを無効にして、問題が解決します。システムのやりとりのようなものでしょう。 –

答えて

2

Tkは少なくとも2つのケースで同じコードを使用しています。少なくとも、あるケースでは入力メソッドとの間に奇妙なやり取りがない限り、イベントを処理します。私が知る限り、キーボードイベントは、Ubuntuを実行する異なるシステム間で同じようにキューに入れられます。 GUIシステムのイベントキューにKeyEventが渡されているだけで、通常のX11キーボードの処理になります。理論的には、Thinkpadのケースではサーバ側のバッファを埋めるかもしれませんが、デスクトップとのシステムの速度が異なると追いつくことができます。多分…?

はい、私はあなたのコードを書いて、イベントキューをより迅速に処理することを提案しています。(これはまったく問題ではないかもしれませんが)Tcl/Tkがないシステムの部分には、の責任を負う。

+0

純粋なX11プログラムでは効果がありません。私はコードで私の質問を拡張します。 – Ralf

0

同僚がim-config -aを実行して、「アクティブなコンフィギュレーション」の代わりに、(ラインrun_im noneを含むファイル~/.xinputrcを生成します)以前の「IBUS」として「なし」を選択するために私に助言しました。私がこれを行うと、問題はラップトップ(Xを再起動した後)で消えているように見えますが、これまでのところ私は理由を知りません。私のPC(問題が発生していない場所)で、im-config -aは「欠落」を「アクティブな構成」と記載しています。

ドナルフェローは「入力方法との奇妙なやり取り」に就いているようです。 @Donal Fellows:あなたのコメントを詳述できますか?

@Brad Lanam:「IME」の「インプットメソッドエディタ」の意味もあると思うので、あなたもそうでした。

+1

ibus IMEを再起動すると、Tkはセグメント化エラーでクラッシュします。私は、両方のプログラムでさまざまなキー処理の前提が存在し、それらがうまく一緒に遊ぶことはないと推測します(つまり、推測します)。 –

関連する問題