2013-08-15 1 views
4

저는 인터넷에서 많은 리소스를 읽으면서 X 디스플레이에서 UTF-8 키보드 입력을 얻을 수있는 방법을 찾으려고 노력했습니다. 그러나 나는 그것을 작동하게 만들 수 없었다.X11 디스플레이로 UTF-8 입력 받기

나는이 link (exaple 11-4)에서 예제 코드를 시도했지만 성공하지 못했습니다.

또한 아래의 간단한 예제를 작성하여 작동 시키려고했습니다. 나의 간단한 테스트 케이스는 "é"를 인쇄하는 것이다. acute와 e를 입력하면된다.

무엇이 잘못 되었나요? 당신은이 작업을 수행해야

#include <X11/Xlib.h> 
#include <X11/Xutil.h> 
#include <X11/Xresource.h> 
#include <X11/Xlocale.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

int main(int argc, char ** argv) 
{ 
    int screen_num, width, height; 
    unsigned long background, border; 
    Window win; 
    XEvent ev; 
    Display *dpy; 
    XIM im; 
    XIC ic; 
    char *failed_arg; 
    XIMStyles *styles; 
    XIMStyle xim_requested_style; 

    /* First connect to the display server, as specified in the DISPLAY 
    environment variable. */ 
    if (setlocale(LC_ALL, "") == NULL) { 
     return 9; 
    } 

    if (!XSupportsLocale()) { 
     return 10; 
    } 
    if (XSetLocaleModifiers("") == NULL) { 
     return 11; 
    } 

    dpy = XOpenDisplay(NULL); 
    if (!dpy) { 
     fprintf(stderr, "unable to connect to display"); 
     return 7; 
    } 
    /* these are macros that pull useful data out of the display object */ 
    /* we use these bits of info enough to want them in their own variables */ 
    screen_num = DefaultScreen(dpy); 
    background = BlackPixel(dpy, screen_num); 
    border = WhitePixel(dpy, screen_num); 

    width = 400; /* start with a small window */ 
    height = 200; 

    win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), /* display, parent */ 
     0,0, /* x, y: the window manager will place the window elsewhere */ 
     width, height, /* width, height */ 
     2, border, /* border width & colour, unless you have a window manager */ 
     background); /* background colour */ 

    /* tell the display server what kind of events we would like to see */ 
    XSelectInput(dpy, win, ButtonPressMask|StructureNotifyMask|KeyPressMask|KeyReleaseMask|KeymapStateMask); 

    /* okay, put the window on the screen, please */ 
    XMapWindow(dpy, win); 

    im = XOpenIM(dpy, NULL, NULL, NULL); 
    if (im == NULL) { 
     fputs("Could not open input method\n", stdout); 
     return 2; 
    } 

    failed_arg = XGetIMValues(im, XNQueryInputStyle, &styles, NULL); 

    if (failed_arg != NULL) { 
     fputs("XIM Can't get styles\n", stdout); 
     return 3; 
    } 

    int i; 
    for (i = 0; i < styles->count_styles; i++) { 
     printf("style %d\n", styles->supported_styles[i]); 
    } 
    ic = XCreateIC(im, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, win, NULL); 
    if (ic == NULL) { 
     printf("Could not open IC\n"); 
     return 4; 
    } 

    XSetICFocus(ic); 

    /* as each event that we asked about occurs, we respond. In this 
    * case we note if the window's shape changed, and exit if a button 
    * is pressed inside the window */ 
    while(1) { 
     XNextEvent(dpy, &ev); 
     switch(ev.type){ 
     case KeymapNotify: 
      XRefreshKeyboardMapping(&ev.xmapping); 
      break; 
     case KeyPress: 
      { 
       int count = 0; 
       KeySym keysym = 0; 
       char buf[20]; 
       Status status = 0; 
       count = Xutf8LookupString(ic, (XKeyPressedEvent*)&ev, buf, 20, &keysym, &status); 

       printf("count: %d\n", count); 
       if (status==XBufferOverflow) 
        printf("BufferOverflow\n"); 

       if (count) 
        printf("buffer: %s\n", buf); 

       if (status == XLookupKeySym || status == XLookupBoth) { 
        printf("status: %d\n", status); 
       } 
       printf("pressed KEY: %d\n", keysym); 
      } 
      break; 
     case KeyRelease: 
      { 
       int count = 0; 
       KeySym keysym = 0; 
       char buf[20]; 
       Status status = 0; 
       count = XLookupString((XKeyEvent*)&ev, buf, 20, &keysym, NULL); 

       if (count) 
        printf("in release buffer: %s\n", buf); 

       printf("released KEY: %d\n", keysym); 
      } 
      break; 
     case ConfigureNotify: 
      if (width != ev.xconfigure.width 
        || height != ev.xconfigure.height) { 
       width = ev.xconfigure.width; 
       height = ev.xconfigure.height; 
       printf("Size changed to: %d by %d", width, height); 
      } 
      break; 
     case ButtonPress: 
      XCloseDisplay(dpy); 
      return 0; 
     } 
     fflush(stdout); 
    } 
} 

답변

8

: 이벤트 루프에서

  if (XFilterEvent(&ev, win)) 
       continue; 

감사합니다,

은 여기 내 예입니다. 이렇게하면 입력 메소드 기계가 실행되고 원시 X 이벤트는 얻을 수 없습니다. 예를 들어, 데드 악센트 키 다음에 문자 키를 누르고 XFilterEvent을 호출하지 않으면 평소처럼 두 건의 KeyPress 이벤트가 발생합니다. 그러나 전화를 걸면 세 개의 이벤트가 발생합니다. 두 개의 원시 이벤트가 있으며 XFilterEvent(&ev, win)True을 반환합니다. 그리고 나서 입력 메소드에 의해 합성 된 하나의 이벤트가 있는데, 그 중 XFilterEvent(&ev, win)False을 반환합니다. 악센트 부호가있는 문자가 포함 된 세 번째 이벤트입니다.

원시 이벤트와 입력 방법으로 합성 된 이벤트를 모두 원할 경우 당연히 continue 대신 원시 이벤트 처리를 수행 할 수 있습니다.

buf을 올바로 (또는 명시 적으로 길이를 사용하여) 인쇄하려면 buf[count] = 0;이 필요하고, Xutf8LookupString은 출력을 Null 종료하지 않습니다.

마지막으로 주석에서 언급했듯이 최신 버전의 X11에서는 XSetLocaleModifiers (예 : XSetLocaleModifiers("@im=none"))으로 수정을 지정해야합니다. 그렇지 않으면 추가 이벤트가 생성되지 않습니다.

#include <X11/Xlib.h> 
#include <X11/Xutil.h> 
#include <X11/Xresource.h> 
#include <X11/Xlocale.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

int main(int argc, char ** argv) 
{ 
    int screen_num, width, height; 
    unsigned long background, border; 
    Window win; 
    XEvent ev; 
    Display *dpy; 
    XIM im; 
    XIC ic; 
    char *failed_arg; 
    XIMStyles *styles; 
    XIMStyle xim_requested_style; 

    /* First connect to the display server, as specified in the DISPLAY 
    environment variable. */ 
    if (setlocale(LC_ALL, "") == NULL) { 
     return 9; 
    } 

    if (!XSupportsLocale()) { 
     return 10; 
    } 
    if (XSetLocaleModifiers("@im=none") == NULL) { 
     return 11; 
    } 

    dpy = XOpenDisplay(NULL); 
    if (!dpy) { 
     fprintf(stderr, "unable to connect to display"); 
     return 7; 
    } 
    /* these are macros that pull useful data out of the display object */ 
    /* we use these bits of info enough to want them in their own variables */ 
    screen_num = DefaultScreen(dpy); 
    background = BlackPixel(dpy, screen_num); 
    border = WhitePixel(dpy, screen_num); 

    width = 400; /* start with a small window */ 
    height = 200; 

    win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), /* display, parent */ 
     0,0, /* x, y: the window manager will place the window elsewhere */ 
     width, height, /* width, height */ 
     2, border, /* border width & colour, unless you have a window manager */ 
     background); /* background colour */ 

    /* tell the display server what kind of events we would like to see */ 
    XSelectInput(dpy, win, ButtonPressMask|StructureNotifyMask|KeyPressMask|KeyReleaseMask); 

    /* okay, put the window on the screen, please */ 
    XMapWindow(dpy, win); 

    im = XOpenIM(dpy, NULL, NULL, NULL); 
    if (im == NULL) { 
     fputs("Could not open input method\n", stdout); 
     return 2; 
    } 

    failed_arg = XGetIMValues(im, XNQueryInputStyle, &styles, NULL); 

    if (failed_arg != NULL) { 
     fputs("XIM Can't get styles\n", stdout); 
     return 3; 
    } 

    int i; 
    for (i = 0; i < styles->count_styles; i++) { 
     printf("style %d\n", (int)styles->supported_styles[i]); 
    } 
    ic = XCreateIC(im, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, win, NULL); 
    if (ic == NULL) { 
     printf("Could not open IC\n"); 
     return 4; 
    } 

    XSetICFocus(ic); 

    /* as each event that we asked about occurs, we respond. In this 
    * case we note if the window's shape changed, and exit if a button 
    * is pressed inside the window */ 
    while(1) { 
     XNextEvent(dpy, &ev); 
     if (XFilterEvent(&ev, win)) 
      continue; 
     switch(ev.type){ 
     case MappingNotify: 
      XRefreshKeyboardMapping(&ev.xmapping); 
      break; 
     case KeyPress: 
      { 
       int count = 0; 
       KeySym keysym = 0; 
       char buf[20]; 
       Status status = 0; 
       count = Xutf8LookupString(ic, (XKeyPressedEvent*)&ev, buf, 20, &keysym, &status); 

       printf("count: %d\n", count); 
       if (status==XBufferOverflow) 
        printf("BufferOverflow\n"); 

       if (count) 
        printf("buffer: %.*s\n", count, buf); 

       if (status == XLookupKeySym || status == XLookupBoth) { 
        printf("status: %d\n", status); 
       } 
       printf("pressed KEY: %d\n", (int)keysym); 
      } 
      break; 
     case KeyRelease: 
      { 
       int count = 0; 
       KeySym keysym = 0; 
       char buf[20]; 
       Status status = 0; 
       count = XLookupString((XKeyEvent*)&ev, buf, 20, &keysym, NULL); 

       if (count) 
        printf("in release buffer: %.*s\n", count, buf); 

       printf("released KEY: %d\n", (int)keysym); 
      } 
      break; 
     case ConfigureNotify: 
      if (width != ev.xconfigure.width 
        || height != ev.xconfigure.height) { 
       width = ev.xconfigure.width; 
       height = ev.xconfigure.height; 
       printf("Size changed to: %d by %d", width, height); 
      } 
      break; 
     case ButtonPress: 
      XCloseDisplay(dpy); 
      return 0; 
     } 
     fflush(stdout); 
    } 
} 
+0

나는 당신이 3 일 전, 말했다,이 문제를 파악하고 내 사용 사례에 중요한 다른 일을 지적 : 여기

코드의 수정 된 버전입니다. 이것은 내가 올바른 생각을하고 있음을 확인합니다 :). 답을 많이 주셔서 고마워요. – thiagobl

+0

'XNextEvent()'또는'case KeyPress' 다음에 이것을 넣으시겠습니까? – exebook

+1

@exbook XNextEvent 후의 올바른 장소라고 생각합니다. 입력 메소드는 모든 종류의 이벤트를 키 누르기로 변환 할 수 있습니다. –