キーボードの単一のキーは、同時に押された各キーに対して追加のキー押下を生成します。

キーボードの単一のキーは、同時に押された各キーに対して追加のキー押下を生成します。

最近、QPADからMK-85メカニカルUSBキーボードを購入しました。キーボードはWindowsで完全に動作します。 Syslinuxでは完璧に動作します。 Linuxではほぼ完全に動作します。 Linuxの唯一の問題は、単一のキーが奇妙に機能することです(Gentoo(3.6.11)、Arch Linux、およびLinux Mint(2.6.38)がすべて影響を受けます)。

キーボードは105キーのドイツ語レイアウトキーボードですが、問題のキーはäとenterの間にあります。アメリカのレイアウトではキーに対応し、\ドイツ語のレイアウトではに対応#し、スカンジナビアのレイアウトではに対応します'

このキーを他のキーと一緒に押すと、同時に押す各キーに対して追加のキー押下が生成されます。たとえば、スカンジナビアのレイアウトでは、いいえ「私はすぐに結論に達しました。いいえ」

この動作はshowkeysプログラムを使用して観察できます。

kb mode was UNICODE
[ if you are trying this under X, it might not work
since the X server is also reading /dev/console ]

press any key (program terminates 10s after last keypress)...
keycode  28 release
keycode  32 press    // d pressed
keycode  24 press    // o pressed
keycode  49 press    // n pressed
keycode  32 release  // d released
keycode  43 press    // ' pressed
keycode  24 release  // o released
keycode  43 release  // ' released
keycode  43 press    // ' pressed, extra ' produced
keycode  49 release  // n released
keycode  43 release  // ' released
keycode  43 press    // ' pressed, extra ' produced
keycode  20 press    // t pressed
keycode  43 release  // ' released
keycode  43 press    // ' pressed, extra ' produced
keycode  20 release  // t released
keycode  43 release  // ' released
keycode  43 press    // ' pressed, extra ' produced
keycode  43 release  // ' released (REAL)

キーボードのレイアウトに関係なく、この単一のキーでのみ発生します。これが現れるもう1つの方法は、キーを押し続けると繰り返され、別のキーを押し続けると繰り返しが開始されることです。

aaaaaaaaaakkkkkkkkkkkkk (works as intended)
¨¨¨¨¨¨¨¨¨¨fffffffffffff (works as intended)
''''''''''a'''''''''''' (a is not repeated, instead ' continues)

Windowsではこの問題は発生しません。

OnKeyDown, Key code=68, Control keys=, Key name d
OnKeyPress d
OnKeyDown, Key code=79, Control keys=, Key name o
OnKeyPress o
OnKeyDown, Key code=78, Control keys=, Key name n
OnKeyPress n
OnKeyup, Key code=68, Control keys=, Key name d
OnKeyDown, Key code=191, Control keys=, Key name ........OEM specific
OnKeyPress '
OnKeyup, Key code=79, Control keys=, Key name o
OnKeyup, Key code=78, Control keys=, Key name n
OnKeyDown, Key code=84, Control keys=, Key name t
OnKeyPress t
OnKeyup, Key code=191, Control keys=, Key name ........OEM specific
OnKeyup, Key code=84, Control keys=, Key name t

SEについてどう思いますか?ハードウェアの問題? Syslinuxではうまく動作するので、Linux側に問題があると思います。これをデバッグするためのアドバイス、アイデア、またはより良い方法はありますか?動作させるためにカーネルをパッチする必要がある場合は、それを喜んで行います。

答え1

私はこのバグの適切なパッチを作成しようとしました。これはキーボードの問題ではなくカーネルの問題です。しかし、キーボードが奇妙な方法で動作すると言うこともできます。それにもかかわらず、パッチはレビューのためにLinux入力リストに提出されましたが、まだコメントはありません。

これにより、ここで言及されているQPAD MK-85の問題が解決されますが、Corsair K70、Gigabyte Osmium、およびその他の同様のキーボードにも同じ問題があります。キーボードにバグがある場合は、パッチをテストできれば良いでしょう。テストするときに動作するか、どのキーボードを持っているか教えてください。使用している言語のバージョンも重要です。アメリカのキーボードと米国以外のキーボードは異なる動作をします。アメリカのキーボードのバックスラッシュキーは、異なるバージョンのキーボードで異なるラベルを持っています。

以下は、linux-inputのパッチを含むEメールです。

http://article.gmane.org/gmane.linux.kernel.input/37583

答え2

まあ、私はこの問題を解決するためのトリックを作成しました。誰かが同じ問題に直面する場合に備えて、ここに文を書きます。

まず、カーネルソースコードの修正に興味がない場合は、他のオプションがあります。http://kbd-mangler.sourceforge.net/- テストしていませんが、説明が有望に見えます。これにより、入力がシステムに渡される前に調整できます。

私の解決策は、drivers/hid/hid-input.cファイルを編集することでした。ファイルの先頭に3つの新しい変数定義を追加しました。

static bool CODE43TRUE = 0; // If true, code43 has been pressed
static bool CODEXXTRUE = 0; // If true, any other key has been pressed
static int  CODESKIP = 0;   // Counter for skipping extra code43 events

機能を探す

void hidinput_hid_event

この機能の下部は

input_event(input, usage->type, usage->code, value);

入力はコントローラ、タイプはイベントタイプ(1はキーを押し、2はマウスを移動しますか?)を表し、コードはキーコード、値は押す場合は0、押す場合は1です。

任意のキーを押すたびに、HIDシステムはすべてのキーボードキーを4回循環します。なぜ4番をするのかはわかりませんが、4番は問題のキーで得られる追加のキーストロークに対応します。最初のループで押されたキーの値は 0 で、2 番目のループでは値が 1 で、3 番目と 4 番目のループでは値は 0 です。

回避策は、別のキーを押すか、元のキーを押してから4サイクル以内に問題のあるキーをもう一度押すことを許可しないように、この機能を変更することです。これは、次のコードを使用して達成されます。 (少なくとも10年間Cコードを書いていないと言いましたか?申し訳ありません。)

/* report the usage code as scancode if the key status has changed */
if (usage->type == EV_KEY && !!test_bit(usage->code, input->key) != value)
    input_event(input, EV_MSC, MSC_SCAN, usage->hid);

// NEW CODE STARTS HERE
if (usage->type == 1 && value == 1) // Keypress ahead
{
    if (usage->code == 43) { // Keypress is code 43
        if (CODE43TRUE == 0) {  // Key not yet pressed 
            CODE43TRUE = 1;
            printk(KERN_INFO "CODE43 SET TRUE\n");
        }
    else { // Key already pressed, so force value 1
        printk(KERN_INFO "CODE43 ALREADY TRUE SET VALUE 1\n");
        value = 0;
    }
}
else { // Some other key pressed, set XX true
    CODEXXTRUE = 1;
    printk(KERN_INFO "CODEXX SET TRUE\n");  
}
printk(KERN_INFO "Keypress type:%u code:%u value%d\n", (unsigned int) usage->type, (unsigned int) usage->code, (int) value);
}

if (usage->type == 1 && value == 0) { // Non-pressed key ahead
    if (usage->code == 43) { // If its a 43
        printk(KERN_INFO "43 call..\n");
        if (CODE43TRUE == 1) { // And 43 is fake pressed still
            if (CODEXXTRUE == 1 || CODESKIP < 4) { // If other buttons are pressed OR we are less than 5 ticks into the press..
                printk(KERN_INFO "FAKE PRESS 43. CODESKIP %d\n",CODESKIP);
                value = 0;
                CODESKIP ++;
            }
            else { // No other buttons pressed and over five ticks have passed
                printk(KERN_INFO "43 RELEASED\n");
                CODE43TRUE = 0;
                CODESKIP = 0;   
            }
        }
        // Reset the CODEXXTRUE (next time we get info about 43, we have looped through all the other keys so we know if something is pressed)
        CODEXXTRUE = 0;
    }   
}

// NEW CODE ENDS HERE
input_event(input, usage->type, usage->code, value);

この機能を実装している場合は、期待どおりに機能していることを確認してからprintkステートメントを削除できます。デバッグにのみ役立ちます。

関連情報