fix(xim): honor reset and X11 keyboard state
This commit is contained in:
@@ -31,6 +31,9 @@ static void wirestart(xcb_im_t*, xcb_im_input_context_t*);
|
||||
static void wiredraw(xcb_im_t*, xcb_im_input_context_t*,
|
||||
xcb_im_preedit_draw_fr_t*);
|
||||
static void wiredone(xcb_im_t*, xcb_im_input_context_t*);
|
||||
static void wireforward(xcb_im_t*, xcb_im_input_context_t*,
|
||||
xcb_key_press_event_t*);
|
||||
static void wiresetdata(xcb_im_input_context_t*, void*, xcb_im_free_function);
|
||||
static xcb_get_geometry_cookie_t wiregeometry(xcb_connection_t*, xcb_drawable_t);
|
||||
static xcb_get_geometry_reply_t* wiregeometryreply(xcb_connection_t*,
|
||||
xcb_get_geometry_cookie_t, xcb_generic_error_t**);
|
||||
@@ -44,6 +47,8 @@ static int wireflush(xcb_connection_t*);
|
||||
#define xcb_im_preedit_start_callback wirestart
|
||||
#define xcb_im_preedit_draw_callback wiredraw
|
||||
#define xcb_im_preedit_done_callback wiredone
|
||||
#define xcb_im_forward_event wireforward
|
||||
#define xcb_im_input_context_set_data wiresetdata
|
||||
#define xcb_im_input_context_get_data(ic) \
|
||||
(wirebinding(ic) == nil ? nil : wirebinding(ic)->data)
|
||||
#define xcb_im_input_context_get_client_window(ic) \
|
||||
@@ -64,6 +69,8 @@ static int wireflush(xcb_connection_t*);
|
||||
#undef xcb_im_preedit_start_callback
|
||||
#undef xcb_im_preedit_draw_callback
|
||||
#undef xcb_im_preedit_done_callback
|
||||
#undef xcb_im_forward_event
|
||||
#undef xcb_im_input_context_set_data
|
||||
#undef xcb_im_input_context_get_data
|
||||
#undef xcb_im_input_context_get_client_window
|
||||
#undef xcb_im_input_context_get_focus_window
|
||||
@@ -82,6 +89,7 @@ enum
|
||||
Wdraw,
|
||||
Wdone,
|
||||
Wcommit,
|
||||
Wforward,
|
||||
Maxwire = 8,
|
||||
};
|
||||
|
||||
@@ -189,6 +197,29 @@ wiredone(xcb_im_t *im, xcb_im_input_context_t *ic)
|
||||
newwire(Wdone, ic);
|
||||
}
|
||||
|
||||
static void
|
||||
wireforward(xcb_im_t *im, xcb_im_input_context_t *ic,
|
||||
xcb_key_press_event_t *ev)
|
||||
{
|
||||
Wirecall *call;
|
||||
|
||||
USED(im);
|
||||
call = newwire(Wforward, ic);
|
||||
if(call != nil)
|
||||
call->keysym = ev->detail;
|
||||
}
|
||||
|
||||
static void
|
||||
wiresetdata(xcb_im_input_context_t *ic, void *data, xcb_im_free_function freefn)
|
||||
{
|
||||
Icbinding *binding;
|
||||
|
||||
USED(freefn);
|
||||
binding = wirebinding(ic);
|
||||
if(binding != nil)
|
||||
binding->data = data;
|
||||
}
|
||||
|
||||
static Wirewin*
|
||||
wirewindow(xcb_window_t win)
|
||||
{
|
||||
@@ -306,6 +337,29 @@ wirewin(int n, xcb_window_t win, int x, int y, int h)
|
||||
return w;
|
||||
}
|
||||
|
||||
static struct xkb_state*
|
||||
testkeystate(char *layout)
|
||||
{
|
||||
struct xkb_context *context;
|
||||
struct xkb_keymap *keymap;
|
||||
struct xkb_rule_names names;
|
||||
struct xkb_state *state;
|
||||
|
||||
memset(&names, 0, sizeof names);
|
||||
names.layout = layout;
|
||||
context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
||||
if(context == nil)
|
||||
return nil;
|
||||
keymap = xkb_keymap_new_from_names(context, &names,
|
||||
XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
xkb_context_unref(context);
|
||||
if(keymap == nil)
|
||||
return nil;
|
||||
state = xkb_state_new(keymap);
|
||||
xkb_keymap_unref(keymap);
|
||||
return state;
|
||||
}
|
||||
|
||||
void testengineinit(int);
|
||||
void testenginehandle(Keyreq*);
|
||||
void* testengineowner(void);
|
||||
@@ -727,17 +781,16 @@ xim_adapter_placement_updates(struct ct *t)
|
||||
Ximfix f;
|
||||
Keyreq req;
|
||||
Ic state;
|
||||
xcb_keysym_t key, *oldkmap;
|
||||
uint8_t oldmin, oldmax, oldper;
|
||||
struct xkb_state *oldstate;
|
||||
|
||||
ic = (xcb_im_input_context_t*)(uintptr)71;
|
||||
memset(&state, 0, sizeof state);
|
||||
oldkmap = kmap;
|
||||
oldmin = minkc;
|
||||
oldmax = maxkc;
|
||||
oldper = symsper;
|
||||
oldstate = kstate;
|
||||
if(!ximbegin(t, &f, LangJP))
|
||||
goto cleanup;
|
||||
kstate = testkeystate("us");
|
||||
if(!CT_CHECK(t, kstate != nil))
|
||||
goto cleanup;
|
||||
wireclear();
|
||||
state.xic = ic;
|
||||
state.style = XCB_IM_PreeditPosition | XCB_IM_StatusNothing;
|
||||
@@ -749,12 +802,8 @@ xim_adapter_placement_updates(struct ct *t)
|
||||
b->preattr.spot_location.x = 5;
|
||||
b->preattr.spot_location.y = 6;
|
||||
wirewin(0, 11, 100, 200, 30);
|
||||
key = 'n';
|
||||
kmap = &key;
|
||||
minkc = maxkc = 8;
|
||||
symsper = 1;
|
||||
memset(&ev, 0, sizeof ev);
|
||||
ev.detail = 8;
|
||||
ev.detail = 57;
|
||||
kpress(&state, &ev);
|
||||
req = nexttrace(t, &f, Keypress, &state);
|
||||
CT_CHECK(t, req.caret.valid);
|
||||
@@ -785,10 +834,9 @@ xim_adapter_placement_updates(struct ct *t)
|
||||
req = nexttrace(t, &f, Keycaret, &state);
|
||||
CT_CHECK(t, !req.caret.valid);
|
||||
cleanup:
|
||||
kmap = oldkmap;
|
||||
minkc = oldmin;
|
||||
maxkc = oldmax;
|
||||
symsper = oldper;
|
||||
if(kstate != oldstate)
|
||||
xkb_state_unref(kstate);
|
||||
kstate = oldstate;
|
||||
preowner = nil;
|
||||
ximend(&f);
|
||||
}
|
||||
@@ -797,31 +845,27 @@ void
|
||||
xim_adapter_encoding_negotiation(struct ct *t)
|
||||
{
|
||||
xcb_im_packet_header_fr_t hdr;
|
||||
xcb_im_client_t *a, *b;
|
||||
xcb_im_client_t *clients[Maxclients+1];
|
||||
u16int selected;
|
||||
int i;
|
||||
|
||||
a = (xcb_im_client_t*)(uintptr)1;
|
||||
b = (xcb_im_client_t*)(uintptr)2;
|
||||
memset(clientenc, 0, sizeof clientenc);
|
||||
clearencodings();
|
||||
CT_EQ_SIZE(t, 2, nelem(encs));
|
||||
CT_EQ_STR(t, "COMPOUND_TEXT", encs[0]);
|
||||
CT_EQ_STR(t, "UTF8_STRING", encs[1]);
|
||||
memset(&hdr, 0, sizeof hdr);
|
||||
hdr.major_opcode = XCB_XIM_ENCODING_NEGOTIATION;
|
||||
selected = 1;
|
||||
callback(nil, a, nil, &hdr, nil, &selected, nil);
|
||||
selected = 0;
|
||||
callback(nil, b, nil, &hdr, nil, &selected, nil);
|
||||
CT_EQ_INT(t, Eutf8, getencoding(a));
|
||||
CT_EQ_INT(t, Ecompound, getencoding(b));
|
||||
for(i = 0; i < nelem(clients); i++){
|
||||
clients[i] = (xcb_im_client_t*)(uintptr)(i+1);
|
||||
selected = i == 0 ? 0 : 1;
|
||||
callback(nil, clients[i], nil, &hdr, nil, &selected, nil);
|
||||
}
|
||||
CT_EQ_INT(t, Ecompound, getencoding(clients[0]));
|
||||
CT_EQ_INT(t, Eutf8, getencoding(clients[Maxclients]));
|
||||
hdr.major_opcode = XCB_XIM_DISCONNECT;
|
||||
callback(nil, a, nil, &hdr, nil, nil, nil);
|
||||
CT_EQ_INT(t, Ecompound, getencoding(a));
|
||||
CT_EQ_INT(t, Ecompound, getencoding(b));
|
||||
hdr.major_opcode = XCB_XIM_CLOSE;
|
||||
callback(nil, b, nil, &hdr, nil, nil, nil);
|
||||
CT_EQ_PTR(t, nil, clientenc[0].client);
|
||||
CT_EQ_PTR(t, nil, clientenc[1].client);
|
||||
for(i = 0; i < nelem(clients); i++)
|
||||
callback(nil, clients[i], nil, &hdr, nil, nil, nil);
|
||||
CT_EQ_PTR(t, nil, clientenc);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -875,12 +919,7 @@ void
|
||||
xim_adapter_callback_unicode(struct ct *t)
|
||||
{
|
||||
static char *text[] = {
|
||||
"한글",
|
||||
"かなカナ",
|
||||
"漢字",
|
||||
"𠀋",
|
||||
"😀",
|
||||
"❤️",
|
||||
"한𠀋",
|
||||
"👩💻",
|
||||
};
|
||||
Ic state;
|
||||
@@ -942,16 +981,57 @@ void
|
||||
xim_adapter_callback_cleanup(struct ct *t)
|
||||
{
|
||||
static int opcode[] = {
|
||||
XCB_XIM_RESET_IC,
|
||||
XCB_XIM_UNSET_IC_FOCUS,
|
||||
XCB_XIM_DESTROY_IC,
|
||||
};
|
||||
xcb_im_packet_header_fr_t hdr;
|
||||
xcb_im_reset_ic_reply_fr_t reply;
|
||||
xcb_key_press_event_t ev;
|
||||
xcb_im_client_t *client;
|
||||
xcb_im_input_context_t *ic;
|
||||
Ximfix f;
|
||||
Keyres res;
|
||||
Ic state, *dead;
|
||||
int i;
|
||||
|
||||
ic = (xcb_im_input_context_t*)(uintptr)29;
|
||||
memset(&state, 0, sizeof state);
|
||||
if(!ximbegin(t, &f, LangJP))
|
||||
return;
|
||||
wireclear();
|
||||
wirebind(0, ic, &state);
|
||||
state.xic = ic;
|
||||
state.style = XCB_IM_PreeditCallbacks | XCB_IM_StatusNothing;
|
||||
state.cap = Cclientpreedit;
|
||||
state.encoding = Eutf8;
|
||||
keypress(&state, 'k', 0, &res);
|
||||
nexttrace(t, &f, Keypress, &state);
|
||||
keypress(&state, 'a', 0, &res);
|
||||
nexttrace(t, &f, Keypress, &state);
|
||||
updatepreedit(&state, &res.preedit);
|
||||
memset(&hdr, 0, sizeof hdr);
|
||||
memset(&reply, 0, sizeof reply);
|
||||
hdr.major_opcode = XCB_XIM_RESET_IC;
|
||||
callback(nil, nil, ic, &hdr, nil, &reply, nil);
|
||||
nexttrace(t, &f, Keycap, &state);
|
||||
nexttrace(t, &f, Keyreset, &state);
|
||||
notrace(t, &f);
|
||||
CT_EQ_INT(t, strlen("か"), reply.byte_length_of_committed_string);
|
||||
CT_EQ_MEM(t, "か", reply.committed_string,
|
||||
reply.byte_length_of_committed_string);
|
||||
free(reply.committed_string);
|
||||
CT_CHECK(t, state.engaged);
|
||||
CT_EQ_PTR(t, &state, testengineowner());
|
||||
CT_EQ_INT(t, Wdraw, wirecalls[2].op);
|
||||
CT_EQ_INT(t, Wdone, wirecalls[3].op);
|
||||
keypress(&state, 'n', 0, &res);
|
||||
nexttrace(t, &f, Keypress, &state);
|
||||
checkstr(t, "ん", &res.preedit);
|
||||
release(&state);
|
||||
nexttrace(t, &f, Keyrelease, &state);
|
||||
preowner = nil;
|
||||
ximend(&f);
|
||||
|
||||
for(i = 0; i < nelem(opcode); i++){
|
||||
ic = (xcb_im_input_context_t*)(uintptr)(30+i);
|
||||
wireclear();
|
||||
@@ -994,6 +1074,24 @@ xim_adapter_callback_cleanup(struct ct *t)
|
||||
CT_EQ_INT(t, Wdraw, wirecalls[2].op);
|
||||
CT_EQ_INT(t, Wdone, wirecalls[3].op);
|
||||
CT_EQ_PTR(t, nil, preowner);
|
||||
|
||||
ic = (xcb_im_input_context_t*)(uintptr)42;
|
||||
wireclear();
|
||||
wirebind(0, ic, nil);
|
||||
icinstall(nil, ic, nil);
|
||||
CT_EQ_PTR(t, &passthrough, icbindings[0].data);
|
||||
memset(&ev, 0, sizeof ev);
|
||||
ev.response_type = XCB_KEY_PRESS;
|
||||
ev.detail = 38;
|
||||
hdr.major_opcode = XCB_XIM_FORWARD_EVENT;
|
||||
callback(nil, nil, ic, &hdr, nil, &ev, nil);
|
||||
CT_EQ_INT(t, 1, nwirecalls);
|
||||
CT_EQ_INT(t, Wforward, wirecalls[0].op);
|
||||
CT_EQ_UINT(t, ev.detail, wirecalls[0].keysym);
|
||||
ev.response_type = XCB_KEY_RELEASE;
|
||||
callback(nil, nil, ic, &hdr, nil, &ev, nil);
|
||||
CT_EQ_INT(t, 2, nwirecalls);
|
||||
CT_EQ_INT(t, Wforward, wirecalls[1].op);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
Reference in New Issue
Block a user