키보드의 단일 키는 동시에 누른 각 키에 대해 추가 키 누름을 생성합니다.

키보드의 단일 키는 동시에 누른 각 키에 대해 추가 키 누름을 생성합니다.

최근 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)

키보드 레이아웃에 관계없이 이 단일 키에서만 발생합니다. 이것이 나타나는 또 다른 방법은 키를 누르고 있으면 반복되고, 다른 키를 누르고 있으면 반복이 시작된다는 것입니다.

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의 패치가 포함된 이메일입니다.

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

답변2

글쎄, 나는 이 문제를 해결하기 위해 트릭을 만들었습니다. 누군가가 같은 문제에 직면할 경우를 대비해 여기에 글을 쓰겠습니다.

첫째, 커널 소스 코드를 수정하는 데 관심이 없다면 다른 옵션이 있을 수 있습니다:http://kbd-mangler.sourceforge.net/- 테스트하지는 않았지만 설명이 유망해 보입니다. 이를 통해 입력이 시스템에 전달되기 전에 조정할 수 있습니다.

내 해결책은 drivers/hid/hid-input.c 파일을 편집하는 것이었습니다. 파일 시작 부분에 세 가지 새로운 변수 정의를 추가했습니다.

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이고 두 번째 루프에서는 값이 1이며 다시 세 번째와 네 번째 루프에서는 값이 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 문을 제거할 수 있습니다. 디버깅에만 도움이 됩니다.

관련 정보