2016-07-24 1 views
5

키보드 입력 (X11 이벤트 루프 사용)을 듣고 스캔 코드를 가져 오려고합니다. 이러한 스캔 코드는 키가 입력하는 문자가 아닌 키의 실제 위치를 참조해야합니다. 문제는 KeySyms와 KeyCodes가 다른 언어 (QWERTY와 QWERTZ)에서 다르게 매핑된다는 것입니다.X11을 사용하여 Linux에서 키 코드 대신 스캔 코드 가져 오기

현재 해결책은 "/ usr/share/X11/xkb/keycodes/evdev"파일을 읽는 것입니다. 여기에는 키 위치에 대한 키 코드 매핑이 포함되어 있습니다. 이것을 사용하여 어떤 키 코드라도 스캔 코드로 다시 변환 할 수 있습니다. 내 짐작으로는이 일을하는 안정적인 방법은 아니지만. 나는 리눅스에 대해 많이 모른다. 그래서 여기서 묻는 것이 좋은 생각일지도 모릅니다.

이러한 evdev 매핑이 대부분의 사용자의 컴퓨터에서 사용되고 있다고 가정하는 것이 안전합니까? 그렇지 않다면 실제로 사용되는 키 매핑을 어디에서 찾을 수 있습니까? 아니면 이것에 대한 더 나은 해결책이 있습니까?

+1

키에 고정 된 물리적 위치가 있다는 아이디어는 특정 문자 입력 구현에 따라 달라집니다. 사람들은 키 자체를 자유롭게 재 배열 할 수있는 가상 키보드를 사용할 수 있습니다. 또는 필기 입력 또는 음성 인식 또는 ... 이러한 경우에는 키와 관련된 물리적 위치가 없습니다.스캔 코드가있는 물리적 인 키보드가 있더라도, 호환되지 않는 많은 모델이 있습니다.'/ usr/share/X11/xkb/keycodes '에있는 다른 파일을보십시오. –

+0

그건 의미가 있습니다. 전통적인 키보드가 아닌 다른 특별한 입력 방법을 무시한다고 가정 해 봅시다. "/ usr/share/X11/xkb/keycodes"에있는 파일 중 어떤 것이 매핑에 사용될 수 있다면, 디바이스 중 어떤 것이 사용되는지 탐지하는 방법이 있습니까? – ComfyS

+0

키보드 기하학을 검토하여 키의 실제 위치를 얻을 수 있습니다. 'setxkbmap -print -verbose 10'을 실행하면 geometry include 문을 볼 수 있습니다. X11/xkb/geometry (아마도 "pc"라는 이름의 파일)에서 파일을 검사하십시오. 또한 사용중인 맵핑을 볼 수 있습니다. 나는'setxkbmap -print'와 동등한 프로그래밍 방식을 모릅니다. 그러나 분명히 하나입니다. 사용자가 키보드를 xmodmap으로 다시 매핑하면 어떤 일이 발생할지 모르겠지만이를 처리하도록하십시오. –

답변

3

나는 동일한 문제가있어서 방금 해결책을 찾았습니다. 명백한 것으로부터 시작합시다.

어디서나 "W"또는 "4"와 같은 특정 키를 가져 오려면 이벤트에서받은 키 코드를 KeySym으로 변환하면됩니다. 이 경우 "W"는 XK_WXK_w이고 "4"는 XK_4 (및 대부분 키보드의 경우 XK_dollar)입니다.

그러나 때때로 당신은 "n 개의 번째 m 행의 키"등의 키를 싶어. 이를 수행하려면 키 이름이 필요합니다. 이 경우 QWERTY 키보드에서 "W"는 AD02이고 "4"는 AE04입니다.

플레이어가 이동하기 위해 WASD 키를 사용해야하는 게임을 만들고 있다고 가정 해 봅시다. KeySyms를 찾으면 QWERTY 키보드에서 제대로 작동하지만 AZERTY, QWERTZ 및 DVORAK과 같은 다른 키보드 레이아웃을 사용하는 사람들은 문제가 발생할 것입니다. 따라서이 경우 키 이름을 사용하는 것이 좋습니다.

키 이름을 사용하는 것은 실제로는 꽤 쉽지만 documentation은 매우 지저분합니다 (하지만 여전히 추천합니다). 내가 우둔했기 때문에 GLFW의 소스 코드 (특히 src/x11_init.c)를 봐야했다. 이 방법은 Xkb가 필요하지만 이미 사용하고 있으므로 문제는 아닙니다.

먼저 키보드 맵을 가져 와서 기호 이름을 얻어야합니다. 우리는 키 이름 만 원하기 때문에 XkbKeyNamesMask을 사용합니다.

XEvent Event; 
XNextEvent(XDisplay, &Event); 

switch (Event.type) 
{ 
case KeyPress: 
    /* I'm not sure this 'if' is necessary, but better safe than sorry */ 
    if ((Event.xkey.keycode >= KbDesc->min_key_code) && (Event.xkey.keycode <= KbDesc->max_key_code)) 
    { 
     /* Copy key name into Name */ 
     char Name[XkbKeyNameLength + 1]; 
     memcmp(Name, KbDesc->names->keys[Event.xkey.keycode].name, XkbKeyNameLength); 
     Name[XkbKeyNameLength] = '\0'; /* Null terminator */ 

     if (strcmp(Name, "AD02") == 0) /* Is it W (for QWERTY and QWERTZ)/Z (for AZERTY)/comma (for DVORAK)/ц (for Russian) etc... ? */ 
     { 
      /* Do something... */ 
     } 
     else if (strcmp(Name, "AE04") == 0) /* Is it 4 (for most keyboards)/whatever's in its place? */ 
     { 
      /* Do something... */ 
     } 
     /* ... */ 
    } 

    /* ... */ 
} 

을 그리고 그것 뿐이다 :

#include <X11/XKBlib.h> 

XkbDescPtr KbDesc = XkbGetMap(XDisplay, 0, XkbUseCoreKbd); 
XkbGetNames(XDisplay, XkbKeyNamesMask, KbDesc); 

그런 다음, 이벤트 루프에서 특정 키 코드의 키 이름을 얻기 위해 KbDesc-> names-> 키 배열을 사용할 수 있습니다. 지금까지 꽤 잘 작동하는 것 같습니다. 특수 키에는 매우 다른 키 이름이 있다는 것을 말씀 드리고 싶습니다. 예를 들어, 왼쪽 시프트는 LFSH이고, 왼쪽 컨트롤은 LCTL이고, 공간은 SPCE이고 탈출은 ESC입니다.

도움이되기를 바랍니다.