最近、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メールです。
答え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ステートメントを削除できます。デバッグにのみ役立ちます。