-
-
Save garasubo/8ebb893f2af1950254df715fcf1de58e to your computer and use it in GitHub Desktop.
#include <X11/Xlib.h> | |
#include <X11/Xutil.h> | |
#include <X11/Xos.h> | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <locale.h> | |
#include <assert.h> | |
Display *dpy; | |
Window win; | |
int scr; | |
void send_spot(XIC ic, XPoint nspot) | |
{ | |
XVaNestedList preedit_attr; | |
preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &nspot, NULL); | |
XSetICValues(ic, XNPreeditAttributes, preedit_attr, NULL); | |
XFree(preedit_attr); | |
} | |
static int preedit_start_callback( | |
XIM xim, | |
XPointer client_data, | |
XPointer call_data) | |
{ | |
printf("preedit start\n"); | |
// no length limit | |
return -1; | |
} | |
static void preedit_done_callback( | |
XIM xim, | |
XPointer client_data, | |
XPointer call_data) | |
{ | |
printf("preedit done\n"); | |
} | |
static void preedit_draw_callback( | |
XIM xim, | |
XPointer client_data, | |
XIMPreeditDrawCallbackStruct *call_data) | |
{ | |
printf("callback\n"); | |
XIMText *xim_text = call_data->text; | |
if (xim_text != NULL) | |
{ | |
printf("Draw callback string: %s, length: %d, first: %d, caret: %d\n", xim_text->string.multi_byte, call_data->chg_length, call_data->chg_first, call_data->caret); | |
} | |
else | |
{ | |
printf("Draw callback string: (DELETED), length: %d, first: %d, caret: %d\n", call_data->chg_length, call_data->chg_first, call_data->caret); | |
} | |
} | |
static void preedit_caret_callback( | |
XIM xim, | |
XPointer client_data, | |
XIMPreeditCaretCallbackStruct *call_data) | |
{ | |
printf("preedit caret\n"); | |
if (call_data != NULL) | |
{ | |
printf("direction: %d position: %d\n", call_data->direction, call_data->position); | |
} | |
} | |
int main() | |
{ | |
setlocale(LC_CTYPE, ""); | |
XSetLocaleModifiers(""); | |
dpy = XOpenDisplay(NULL); | |
scr = DefaultScreen(dpy); | |
win = XCreateSimpleWindow(dpy, | |
XDefaultRootWindow(dpy), | |
0, 0, 100, 100, 5, | |
BlackPixel(dpy, scr), | |
BlackPixel(dpy, scr)); | |
XMapWindow(dpy, win); | |
XIMCallback draw_callback; | |
draw_callback.client_data = NULL; | |
draw_callback.callback = (XIMProc)preedit_draw_callback; | |
XIMCallback start_callback; | |
start_callback.client_data = NULL; | |
start_callback.callback = (XIMProc)preedit_start_callback; | |
XIMCallback done_callback; | |
done_callback.client_data = NULL; | |
done_callback.callback = (XIMProc)preedit_done_callback; | |
XIMCallback caret_callback; | |
caret_callback.client_data = NULL; | |
caret_callback.callback = (XIMProc)preedit_caret_callback; | |
XVaNestedList preedit_attributes = XVaCreateNestedList( | |
0, | |
XNPreeditStartCallback, &start_callback, | |
XNPreeditDoneCallback, &done_callback, | |
XNPreeditDrawCallback, &draw_callback, | |
XNPreeditCaretCallback, &caret_callback, | |
NULL); | |
XIM xim = XOpenIM(dpy, NULL, NULL, NULL); | |
XIC ic = XCreateIC(xim, | |
XNInputStyle, XIMPreeditCallbacks | XIMStatusNothing, | |
XNClientWindow, win, | |
XNPreeditAttributes, preedit_attributes, | |
NULL); | |
XSetICFocus(ic); | |
XSelectInput(dpy, win, KeyPressMask); | |
XPoint spot; | |
spot.x = 0; | |
spot.y = 0; | |
send_spot(ic, spot); | |
static char *buff; | |
size_t buff_size = 16; | |
buff = (char *)malloc(buff_size); | |
for (;;) { | |
KeySym ksym; | |
Status status; | |
XEvent ev; | |
XNextEvent(dpy, &ev); | |
if (XFilterEvent(&ev, None)) { | |
continue; | |
} | |
if (ev.type == KeyPress) { | |
size_t c = Xutf8LookupString(ic, &ev.xkey, | |
buff, buff_size - 1, | |
&ksym, &status); | |
if (status == XBufferOverflow) { | |
printf("reallocate to the size of: %lu\n", c + 1); | |
buff = realloc(buff, c + 1); | |
c = XmbLookupString(ic, &ev.xkey, | |
buff, c, | |
&ksym, &status); | |
} | |
if (c) { | |
spot.x += 20; | |
spot.y += 20; | |
send_spot(ic, spot); | |
buff[c] = 0; | |
printf("delievered string: %s\n", buff); | |
} | |
} | |
} | |
} |
@tuxzz What do you mean by "spot location"? You mean caret
in call_data?
This snippet is an example code for my blog post, so please check it as well.
https://garasubo.github.io/hexo/2020/01/25/xim.html
@garasubo No. I mean the XNSpotLocation
value set in send_spot()
. It should move the position of ime candidate box. But it doesn't work with XIMPreeditCallbacks
. When using XIMPreeditCallbacks
, the candidate box always stuck under the bottom of window.
Oh, I see. Well, I didn't care about XNSpotLocation value so much, so I don't have much insight about it. Sorry.
@garasubo I discussed with the author of fcitx. Seems there is no easy way to get XNSpotLocation
to work with XNPreeditCallbacks
. Perhaps I should dismiss this problem since the preedit in IME itself also works...
The spot location doesn't work in XIMPreeditCallbacks style. Any solution?