fix(engine): a reset or a lost focus commits the pending text
Clicking elsewhere, changing focus, or any client reset dropped the composition in the GTK module and IBus (only XIM ResetIC handed it back), so typing 안녕 and clicking Send lost 녕. The engine now returns the pending text — a moved-to candidate first, as Enter would — on Keyreset and Keyrelease; the GTK module asks for it before closing on focus-out and commits it, IBus commits it on FocusOut, Reset and a switch to a password field, and XIM commits it on focus loss and hands it back on ResetIC without a separate capability probe.
This commit is contained in:
@@ -219,6 +219,7 @@ simplefilter(GtkIMContext *ctx, GdkEventKey *ev, int release)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The daemon hands the pending text back; it becomes committed text. */
|
||||||
static void
|
static void
|
||||||
sendreset(Im *im)
|
sendreset(Im *im)
|
||||||
{
|
{
|
||||||
@@ -238,6 +239,8 @@ sendreset(Im *im)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setpreedit(im, "", 0);
|
setpreedit(im, "", 0);
|
||||||
|
if(commit[0] != '\0')
|
||||||
|
g_signal_emit_by_name(im, "commit", commit);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@@ -331,7 +334,8 @@ focusout(GtkIMContext *ctx)
|
|||||||
if(parentim->focus_out != NULL)
|
if(parentim->focus_out != NULL)
|
||||||
parentim->focus_out(ctx);
|
parentim->focus_out(ctx);
|
||||||
im->simpleactive = 0;
|
im->simpleactive = 0;
|
||||||
/* Closing the connection releases the engine, which resets it. */
|
/* Closing the connection releases the engine. */
|
||||||
|
sendreset(im);
|
||||||
srvclose(im);
|
srvclose(im);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
97
ibus.c
97
ibus.c
@@ -288,36 +288,6 @@ sendrequest(Ictx *ctx, int op, u32int ks, u32int mod, Keyres *res)
|
|||||||
chanrecv(replyc, res);
|
chanrecv(replyc, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
releasecontext(Ictx *ctx)
|
|
||||||
{
|
|
||||||
Keyres res;
|
|
||||||
|
|
||||||
if(ctx->focused)
|
|
||||||
sendrequest(ctx, Keyrelease, 0, 0, &res);
|
|
||||||
ctx->focused = 0;
|
|
||||||
memset(&ctx->caret, 0, sizeof ctx->caret);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
dropcontext(Ictx *ctx)
|
|
||||||
{
|
|
||||||
releasecontext(ctx);
|
|
||||||
if(preowner == ctx)
|
|
||||||
preowner = nil;
|
|
||||||
memset(ctx, 0, sizeof *ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
dropconncontexts(DBusConnection *conn)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for(i = 0; i < nelem(contexts); i++)
|
|
||||||
if(contexts[i].conn == conn)
|
|
||||||
dropcontext(&contexts[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
hidden(Ictx *ctx)
|
hidden(Ictx *ctx)
|
||||||
{
|
{
|
||||||
@@ -465,6 +435,52 @@ checkpreowner(void)
|
|||||||
emitpreedit(ctx, "");
|
emitpreedit(ctx, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* A reset or a lost focus hands the pending text back as committed text. */
|
||||||
|
static void
|
||||||
|
flushcontext(Ictx *ctx, int op)
|
||||||
|
{
|
||||||
|
Keyres res;
|
||||||
|
char commit[Maxutf];
|
||||||
|
|
||||||
|
sendrequest(ctx, op, 0, 0, &res);
|
||||||
|
if(clientpreedit(ctx))
|
||||||
|
emitpreedit(ctx, "");
|
||||||
|
stoutf(&res.commit, commit, sizeof commit);
|
||||||
|
if(commit[0] != '\0')
|
||||||
|
emitcommit(ctx->conn, ctx->path, commit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Nobody is left to hand text to: the context or its connection is gone. */
|
||||||
|
static void
|
||||||
|
releasecontext(Ictx *ctx)
|
||||||
|
{
|
||||||
|
Keyres res;
|
||||||
|
|
||||||
|
if(ctx->focused)
|
||||||
|
sendrequest(ctx, Keyrelease, 0, 0, &res);
|
||||||
|
ctx->focused = 0;
|
||||||
|
memset(&ctx->caret, 0, sizeof ctx->caret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dropcontext(Ictx *ctx)
|
||||||
|
{
|
||||||
|
releasecontext(ctx);
|
||||||
|
if(preowner == ctx)
|
||||||
|
preowner = nil;
|
||||||
|
memset(ctx, 0, sizeof *ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dropconncontexts(DBusConnection *conn)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < nelem(contexts); i++)
|
||||||
|
if(contexts[i].conn == conn)
|
||||||
|
dropcontext(&contexts[i]);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
processkey(Ictx *ctx, u32int sym, u32int state, Keyres *res)
|
processkey(Ictx *ctx, u32int sym, u32int state, Keyres *res)
|
||||||
{
|
{
|
||||||
@@ -603,11 +619,7 @@ handlekey(DBusConnection *c, DBusMessage *m, Ictx *ctx)
|
|||||||
static DBusHandlerResult
|
static DBusHandlerResult
|
||||||
handlereset(DBusConnection *c, DBusMessage *m, Ictx *ctx)
|
handlereset(DBusConnection *c, DBusMessage *m, Ictx *ctx)
|
||||||
{
|
{
|
||||||
Keyres res;
|
flushcontext(ctx, Keyreset);
|
||||||
|
|
||||||
sendrequest(ctx, Keyreset, 0, 0, &res);
|
|
||||||
if(clientpreedit(ctx))
|
|
||||||
emitpreedit(ctx, "");
|
|
||||||
return reply(c, m, DBUS_TYPE_INVALID, nil);
|
return reply(c, m, DBUS_TYPE_INVALID, nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -621,9 +633,10 @@ handlefocusin(DBusConnection *c, DBusMessage *m, Ictx *ctx)
|
|||||||
static DBusHandlerResult
|
static DBusHandlerResult
|
||||||
handlefocusout(DBusConnection *c, DBusMessage *m, Ictx *ctx)
|
handlefocusout(DBusConnection *c, DBusMessage *m, Ictx *ctx)
|
||||||
{
|
{
|
||||||
releasecontext(ctx);
|
if(ctx->focused)
|
||||||
if(clientpreedit(ctx))
|
flushcontext(ctx, Keyrelease);
|
||||||
emitpreedit(ctx, "");
|
ctx->focused = 0;
|
||||||
|
memset(&ctx->caret, 0, sizeof ctx->caret);
|
||||||
return reply(c, m, DBUS_TYPE_INVALID, nil);
|
return reply(c, m, DBUS_TYPE_INVALID, nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -701,7 +714,6 @@ handlepropertyset(DBusConnection *c, DBusMessage *m, Ictx *ctx)
|
|||||||
DBusMessageIter value, st;
|
DBusMessageIter value, st;
|
||||||
dbus_bool_t b;
|
dbus_bool_t b;
|
||||||
u32int purpose;
|
u32int purpose;
|
||||||
Keyres res;
|
|
||||||
int washidden;
|
int washidden;
|
||||||
|
|
||||||
if(!getproperty(m, &iface, &name, &value))
|
if(!getproperty(m, &iface, &name, &value))
|
||||||
@@ -716,11 +728,8 @@ handlepropertyset(DBusConnection *c, DBusMessage *m, Ictx *ctx)
|
|||||||
"ContentType expects (uu)");
|
"ContentType expects (uu)");
|
||||||
washidden = hidden(ctx);
|
washidden = hidden(ctx);
|
||||||
ctx->purpose = purpose;
|
ctx->purpose = purpose;
|
||||||
if(ctx->focused && !washidden && hidden(ctx)){
|
if(ctx->focused && !washidden && hidden(ctx))
|
||||||
sendrequest(ctx, Keyreset, 0, 0, &res);
|
flushcontext(ctx, Keyreset);
|
||||||
if(clientpreedit(ctx))
|
|
||||||
emitpreedit(ctx, "");
|
|
||||||
}
|
|
||||||
return reply(c, m, DBUS_TYPE_INVALID, nil);
|
return reply(c, m, DBUS_TYPE_INVALID, nil);
|
||||||
}
|
}
|
||||||
if(strcmp(name, "ClientCommitPreedit") == 0){
|
if(strcmp(name, "ClientCommitPreedit") == 0){
|
||||||
|
|||||||
41
strans.c
41
strans.c
@@ -572,6 +572,22 @@ startsearch(int lang, Str *com)
|
|||||||
search.lang = lang;
|
search.lang = lang;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Whatever is pending becomes committed text, a moved-to candidate
|
||||||
|
* first: Enter does this, and so do a reset and a lost focus.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
flush(Str *com)
|
||||||
|
{
|
||||||
|
if(search.lang)
|
||||||
|
commitsearch(com);
|
||||||
|
else if(candidatechosen && im.sel >= 0 && im.sel < im.nkouho)
|
||||||
|
sappend(com, &im.kouho[im.sel]);
|
||||||
|
else
|
||||||
|
commit(com);
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
picksearch(int n, Str *com)
|
picksearch(int n, Str *com)
|
||||||
{
|
{
|
||||||
@@ -679,17 +695,10 @@ transition(u32int ks, u32int mod, Str *com)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if(ks == Ktab || ks == Kret){
|
if(ks == Ktab || ks == Kret){
|
||||||
if(candidatechosen && im.sel >= 0 && im.sel < im.nkouho){
|
if(!haspre(&im))
|
||||||
sappend(com, &im.kouho[im.sel]);
|
return 0;
|
||||||
reset();
|
flush(com);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
|
||||||
if(haspre(&im)){
|
|
||||||
commit(com);
|
|
||||||
reset();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
if(ks == Kback){
|
if(ks == Kback){
|
||||||
if(!haspre(&im))
|
if(!haspre(&im))
|
||||||
@@ -773,8 +782,10 @@ init(void)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* The engine belongs to whichever context last typed a real key; only
|
* The engine belongs to whichever context last typed a real key; only
|
||||||
* the owner's requests change state. Every request ends in redraw(),
|
* the owner's requests change state. A reset or release hands the
|
||||||
* which sends the popup a picture only if something visible changed.
|
* owner its pending text back as commit. Every request ends in
|
||||||
|
* redraw(), which sends the popup a picture only if something visible
|
||||||
|
* changed.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
imhandlekey(Keyreq *kr)
|
imhandlekey(Keyreq *kr)
|
||||||
@@ -787,14 +798,14 @@ imhandlekey(Keyreq *kr)
|
|||||||
switch(kr->op){
|
switch(kr->op){
|
||||||
case Keyrelease:
|
case Keyrelease:
|
||||||
if(kr->owner == activeowner){
|
if(kr->owner == activeowner){
|
||||||
reset();
|
flush(&res.commit);
|
||||||
activeowner = nil;
|
activeowner = nil;
|
||||||
activecap = 0;
|
activecap = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Keyreset:
|
case Keyreset:
|
||||||
if(kr->owner == activeowner)
|
if(kr->owner == activeowner)
|
||||||
reset();
|
flush(&res.commit);
|
||||||
break;
|
break;
|
||||||
case Keycaret:
|
case Keycaret:
|
||||||
if(kr->owner == activeowner)
|
if(kr->owner == activeowner)
|
||||||
|
|||||||
@@ -244,7 +244,8 @@ engine_active_owner_lifecycle(struct ct *t)
|
|||||||
checkstr(t, "stale release preserves owner", "にゃ", &shown);
|
checkstr(t, "stale release preserves owner", "にゃ", &shown);
|
||||||
CT_EQ_PTR(t, &b, activeowner);
|
CT_EQ_PTR(t, &b, activeowner);
|
||||||
|
|
||||||
ownerrequest(&b, Keyrelease, 0, 0);
|
res = ownerrequest(&b, Keyrelease, 0, 0);
|
||||||
|
checkstr(t, "release hands the reading back", "にゃ", &res.commit);
|
||||||
CT_EQ_PTR(t, nil, activeowner);
|
CT_EQ_PTR(t, nil, activeowner);
|
||||||
CT_EQ_INT(t, 0, im.pre.n);
|
CT_EQ_INT(t, 0, im.pre.n);
|
||||||
CT_EQ_INT(t, 0, im.raw.n);
|
CT_EQ_INT(t, 0, im.raw.n);
|
||||||
@@ -274,6 +275,7 @@ engine_active_owner_reset(struct ct *t)
|
|||||||
checkstr(t, "preedit before reset", "か", &res.preedit);
|
checkstr(t, "preedit before reset", "か", &res.preedit);
|
||||||
res = ownerrequest(&owner, Keyreset, 0, 0);
|
res = ownerrequest(&owner, Keyreset, 0, 0);
|
||||||
CT_EQ_PTR(t, &owner, activeowner);
|
CT_EQ_PTR(t, &owner, activeowner);
|
||||||
|
checkstr(t, "reset hands the reading back", "か", &res.commit);
|
||||||
CT_EQ_INT(t, 0, res.preedit.n);
|
CT_EQ_INT(t, 0, res.preedit.n);
|
||||||
CT_CHECK(t, !caret.valid);
|
CT_CHECK(t, !caret.valid);
|
||||||
res = ownerrequest(&owner, Keypress, 'n', 0);
|
res = ownerrequest(&owner, Keypress, 'n', 0);
|
||||||
|
|||||||
@@ -820,7 +820,9 @@ main(int argc, char **argv)
|
|||||||
closes = closecount(&srv);
|
closes = closecount(&srv);
|
||||||
gtk_im_context_focus_out(ctx);
|
gtk_im_context_focus_out(ctx);
|
||||||
Check(waitclose(&srv, closes + 1), "focus-out did not close connection");
|
Check(waitclose(&srv, closes + 1), "focus-out did not close connection");
|
||||||
Check(eventcount(&srv) == first, "focus-out sent a request before closing");
|
Check(eventcount(&srv) == first + 1 &&
|
||||||
|
getevent(&srv, first).type == Ereset,
|
||||||
|
"focus-out did not hand the pending text back before closing");
|
||||||
Check(strcmp(log.event, "CE") == 0, "focus-out clear order was %s", log.event);
|
Check(strcmp(log.event, "CE") == 0, "focus-out clear order was %s", log.event);
|
||||||
|
|
||||||
/* Dispose is repeatable, closes the connection, and emits no preedit. */
|
/* Dispose is repeatable, closes the connection, and emits no preedit. */
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ struct Log
|
|||||||
int rfirst;
|
int rfirst;
|
||||||
int rcommit;
|
int rcommit;
|
||||||
int rdone;
|
int rdone;
|
||||||
|
int flushed;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -51,6 +52,11 @@ legacy(IBusInputContext *ctx, IBusText *text, guint cursor,
|
|||||||
log = arg;
|
log = arg;
|
||||||
log->legacy++;
|
log->legacy++;
|
||||||
s = ibus_text_get_text(text);
|
s = ibus_text_get_text(text);
|
||||||
|
if(log->repeat == 3){
|
||||||
|
if(s[0] != '\0' || cursor != 0 || visible)
|
||||||
|
log->invalid = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(log->repeat != 0){
|
if(log->repeat != 0){
|
||||||
revent(log, 'P');
|
revent(log, 'P');
|
||||||
if(log->repeat == 1){
|
if(log->repeat == 1){
|
||||||
@@ -134,6 +140,16 @@ commit(IBusInputContext *ctx, IBusText *text, void *arg)
|
|||||||
log->commit++;
|
log->commit++;
|
||||||
s = ibus_text_get_text(text);
|
s = ibus_text_get_text(text);
|
||||||
attrs = ibus_text_get_attributes(text);
|
attrs = ibus_text_get_attributes(text);
|
||||||
|
if(log->repeat == 3){
|
||||||
|
/* Focus loss hands the pending syllable back as a commit. */
|
||||||
|
if(strcmp(s, "ㅋ") == 0)
|
||||||
|
log->flushed = 1;
|
||||||
|
else
|
||||||
|
log->invalid = 1;
|
||||||
|
if(log->loop != NULL && log->waiting != NULL && *log->waiting)
|
||||||
|
g_main_loop_quit(log->loop);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(log->repeat != 0){
|
if(log->repeat != 0){
|
||||||
revent(log, 'K');
|
revent(log, 'K');
|
||||||
if(log->repeat != 2 || strcmp(s, "ㅋ") != 0 || attrs == NULL ||
|
if(log->repeat != 2 || strcmp(s, "ㅋ") != 0 || attrs == NULL ||
|
||||||
@@ -253,9 +269,10 @@ main(int argc, char **argv)
|
|||||||
log.rn = 0;
|
log.rn = 0;
|
||||||
ok = ok && ibus_input_context_process_key_event(a, 'z', 0, 0) &&
|
ok = ok && ibus_input_context_process_key_event(a, 'z', 0, 0) &&
|
||||||
waitflag(&log, &log.rdone) && strcmp(log.revent, "PKP") == 0;
|
waitflag(&log, &log.rdone) && strcmp(log.revent, "PKP") == 0;
|
||||||
log.repeat = 0;
|
log.repeat = 3;
|
||||||
ibus_input_context_focus_out(a);
|
ibus_input_context_focus_out(a);
|
||||||
if(log.legacy == 0 || log.modern != 0 || log.commit != 2 ||
|
ok = ok && waitflag(&log, &log.flushed);
|
||||||
|
if(log.legacy == 0 || log.modern != 0 || log.commit != 3 ||
|
||||||
log.invalid || !log.done || !log.atext || !log.aclear ||
|
log.invalid || !log.done || !log.atext || !log.aclear ||
|
||||||
log.clearctx != a || !log.rdone)
|
log.clearctx != a || !log.rdone)
|
||||||
ok = 0;
|
ok = 0;
|
||||||
@@ -265,12 +282,12 @@ main(int argc, char **argv)
|
|||||||
g_object_unref(bus);
|
g_object_unref(bus);
|
||||||
if(!ok){
|
if(!ok){
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"ibus_client_smoke: legacy=%d modern=%d commit=%d invalid=%d preedit=%d committed=%d transfer-text=%d a-clear=%d repeat=%s\n",
|
"ibus_client_smoke: legacy=%d modern=%d commit=%d invalid=%d preedit=%d committed=%d transfer-text=%d a-clear=%d repeat=%s flushed=%d\n",
|
||||||
log.legacy, log.modern, log.commit, log.invalid,
|
log.legacy, log.modern, log.commit, log.invalid,
|
||||||
log.sawpreedit, log.sawcommit, log.atext, log.aclear,
|
log.sawpreedit, log.sawcommit, log.atext, log.aclear,
|
||||||
log.revent);
|
log.revent, log.flushed);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
printf("official libibus client preedit, commit, and owner clear: ok\n");
|
printf("official libibus client preedit, commit, owner clear, and focus-out hand-back: ok\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,11 +135,12 @@ expectresponse(int fd, int want, int eaten, char *commit, char *preedit,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
requestreset(int fd, int want, int eaten, char *preedit, char *where)
|
requestreset(int fd, int want, int eaten, char *commit, char *preedit,
|
||||||
|
char *where)
|
||||||
{
|
{
|
||||||
if(!sendreset(fd, want))
|
if(!sendreset(fd, want))
|
||||||
return fail("send %s: %s", where, strerror(errno));
|
return fail("send %s: %s", where, strerror(errno));
|
||||||
return expectresponse(fd, want, eaten, "", preedit, where);
|
return expectresponse(fd, want, eaten, commit, preedit, where);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -257,7 +258,7 @@ runsmoke(char *path)
|
|||||||
requestkey(client, 1, Mctrl, 'n', 1, "", "",
|
requestkey(client, 1, Mctrl, 'n', 1, "", "",
|
||||||
"select Japanese") &&
|
"select Japanese") &&
|
||||||
requestkey(client, 1, 0, 'k', 1, "", "k", "preedit") &&
|
requestkey(client, 1, 0, 'k', 1, "", "k", "preedit") &&
|
||||||
requestreset(client, 1, 1, "", "reset");
|
requestreset(client, 1, 1, "k", "", "reset");
|
||||||
close(client);
|
close(client);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,14 +163,15 @@ allowrequest(Pump *p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
readreply(struct ct *t, Testclient *client, int want, char *preedit)
|
readreply(struct ct *t, Testclient *client, int want, char *wantcommit,
|
||||||
|
char *preedit)
|
||||||
{
|
{
|
||||||
char commit[Ipcfieldmax+1];
|
char commit[Ipcfieldmax+1];
|
||||||
Ipcresp resp;
|
Ipcresp resp;
|
||||||
|
|
||||||
if(ipcreadresp(client->peer, want, commit, preedit, &resp) < 0)
|
if(ipcreadresp(client->peer, want, commit, preedit, &resp) < 0)
|
||||||
return CT_ERRORF(t, "response read failed: %s", strerror(errno));
|
return CT_ERRORF(t, "response read failed: %s", strerror(errno));
|
||||||
CT_EQ_STR(t, "", commit);
|
CT_EQ_STR(t, wantcommit, commit);
|
||||||
return resp.eaten;
|
return resp.eaten;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,14 +258,14 @@ server_connection_ownership(struct ct *t)
|
|||||||
req = nextrequest(t, &f.pump, Keypress);
|
req = nextrequest(t, &f.pump, Keypress);
|
||||||
aowner = req.owner;
|
aowner = req.owner;
|
||||||
allowrequest(&f.pump);
|
allowrequest(&f.pump);
|
||||||
CT_CHECK(t, readreply(t, &a, 1, preedit));
|
CT_CHECK(t, readreply(t, &a, 1, "", preedit));
|
||||||
CT_EQ_STR(t, "k", preedit);
|
CT_EQ_STR(t, "k", preedit);
|
||||||
if(!sendkey(t, &a, 1, 0, 'a'))
|
if(!sendkey(t, &a, 1, 0, 'a'))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
req = nextrequest(t, &f.pump, Keypress);
|
req = nextrequest(t, &f.pump, Keypress);
|
||||||
CT_EQ_PTR(t, aowner, req.owner);
|
CT_EQ_PTR(t, aowner, req.owner);
|
||||||
allowrequest(&f.pump);
|
allowrequest(&f.pump);
|
||||||
CT_CHECK(t, readreply(t, &a, 1, preedit));
|
CT_CHECK(t, readreply(t, &a, 1, "", preedit));
|
||||||
CT_EQ_STR(t, "か", preedit);
|
CT_EQ_STR(t, "か", preedit);
|
||||||
CT_EQ_PTR(t, aowner, testengineowner());
|
CT_EQ_PTR(t, aowner, testengineowner());
|
||||||
|
|
||||||
@@ -274,7 +275,7 @@ server_connection_ownership(struct ct *t)
|
|||||||
bowner = req.owner;
|
bowner = req.owner;
|
||||||
CT_CHECK(t, bowner != aowner);
|
CT_CHECK(t, bowner != aowner);
|
||||||
allowrequest(&f.pump);
|
allowrequest(&f.pump);
|
||||||
CT_CHECK(t, readreply(t, &b, 1, preedit));
|
CT_CHECK(t, readreply(t, &b, 1, "", preedit));
|
||||||
CT_EQ_STR(t, "ん", preedit);
|
CT_EQ_STR(t, "ん", preedit);
|
||||||
CT_EQ_PTR(t, bowner, testengineowner());
|
CT_EQ_PTR(t, bowner, testengineowner());
|
||||||
|
|
||||||
@@ -283,14 +284,14 @@ server_connection_ownership(struct ct *t)
|
|||||||
req = nextrequest(t, &f.pump, Keyreset);
|
req = nextrequest(t, &f.pump, Keyreset);
|
||||||
CT_EQ_PTR(t, aowner, req.owner);
|
CT_EQ_PTR(t, aowner, req.owner);
|
||||||
allowrequest(&f.pump);
|
allowrequest(&f.pump);
|
||||||
CT_CHECK(t, readreply(t, &a, 1, preedit));
|
CT_CHECK(t, readreply(t, &a, 1, "", preedit));
|
||||||
CT_EQ_STR(t, "", preedit);
|
CT_EQ_STR(t, "", preedit);
|
||||||
CT_EQ_PTR(t, bowner, testengineowner());
|
CT_EQ_PTR(t, bowner, testengineowner());
|
||||||
if(!sendkey(t, &b, 1, 0, Kmodfirst))
|
if(!sendkey(t, &b, 1, 0, Kmodfirst))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
req = nextrequest(t, &f.pump, Keypress);
|
req = nextrequest(t, &f.pump, Keypress);
|
||||||
allowrequest(&f.pump);
|
allowrequest(&f.pump);
|
||||||
CT_CHECK(t, !readreply(t, &b, 1, preedit));
|
CT_CHECK(t, !readreply(t, &b, 1, "", preedit));
|
||||||
CT_EQ_STR(t, "ん", preedit);
|
CT_EQ_STR(t, "ん", preedit);
|
||||||
|
|
||||||
disconnectclient(t, &f.pump, &a, aowner);
|
disconnectclient(t, &f.pump, &a, aowner);
|
||||||
@@ -299,12 +300,12 @@ server_connection_ownership(struct ct *t)
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
req = nextrequest(t, &f.pump, Keypress);
|
req = nextrequest(t, &f.pump, Keypress);
|
||||||
allowrequest(&f.pump);
|
allowrequest(&f.pump);
|
||||||
CT_CHECK(t, readreply(t, &b, 1, preedit));
|
CT_CHECK(t, readreply(t, &b, 1, "", preedit));
|
||||||
if(!sendkey(t, &b, 1, 0, 'a'))
|
if(!sendkey(t, &b, 1, 0, 'a'))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
req = nextrequest(t, &f.pump, Keypress);
|
req = nextrequest(t, &f.pump, Keypress);
|
||||||
allowrequest(&f.pump);
|
allowrequest(&f.pump);
|
||||||
CT_CHECK(t, readreply(t, &b, 1, preedit));
|
CT_CHECK(t, readreply(t, &b, 1, "", preedit));
|
||||||
CT_EQ_STR(t, "にゃ", preedit);
|
CT_EQ_STR(t, "にゃ", preedit);
|
||||||
|
|
||||||
if(!sendreset(t, &b, 1))
|
if(!sendreset(t, &b, 1))
|
||||||
@@ -312,7 +313,7 @@ server_connection_ownership(struct ct *t)
|
|||||||
req = nextrequest(t, &f.pump, Keyreset);
|
req = nextrequest(t, &f.pump, Keyreset);
|
||||||
CT_EQ_PTR(t, bowner, req.owner);
|
CT_EQ_PTR(t, bowner, req.owner);
|
||||||
allowrequest(&f.pump);
|
allowrequest(&f.pump);
|
||||||
CT_CHECK(t, readreply(t, &b, 1, preedit));
|
CT_CHECK(t, readreply(t, &b, 1, "にゃ", preedit));
|
||||||
CT_EQ_STR(t, "", preedit);
|
CT_EQ_STR(t, "", preedit);
|
||||||
CT_EQ_PTR(t, bowner, testengineowner());
|
CT_EQ_PTR(t, bowner, testengineowner());
|
||||||
|
|
||||||
@@ -321,7 +322,7 @@ server_connection_ownership(struct ct *t)
|
|||||||
req = nextrequestcap(t, &f.pump, Keypress, 0);
|
req = nextrequestcap(t, &f.pump, Keypress, 0);
|
||||||
CT_EQ_PTR(t, bowner, req.owner);
|
CT_EQ_PTR(t, bowner, req.owner);
|
||||||
allowrequest(&f.pump);
|
allowrequest(&f.pump);
|
||||||
CT_CHECK(t, readreply(t, &b, 0, preedit));
|
CT_CHECK(t, readreply(t, &b, 0, "", preedit));
|
||||||
errno = 0;
|
errno = 0;
|
||||||
n = recv(b.peer, &byte, 1, MSG_PEEK|MSG_DONTWAIT);
|
n = recv(b.peer, &byte, 1, MSG_PEEK|MSG_DONTWAIT);
|
||||||
CT_EQ_INT(t, -1, n);
|
CT_EQ_INT(t, -1, n);
|
||||||
@@ -331,7 +332,7 @@ server_connection_ownership(struct ct *t)
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
req = nextrequest(t, &f.pump, Keypress);
|
req = nextrequest(t, &f.pump, Keypress);
|
||||||
allowrequest(&f.pump);
|
allowrequest(&f.pump);
|
||||||
CT_CHECK(t, readreply(t, &b, 1, preedit));
|
CT_CHECK(t, readreply(t, &b, 1, "", preedit));
|
||||||
CT_EQ_STR(t, "か", preedit);
|
CT_EQ_STR(t, "か", preedit);
|
||||||
|
|
||||||
disconnectclient(t, &f.pump, &b, bowner);
|
disconnectclient(t, &f.pump, &b, bowner);
|
||||||
@@ -393,7 +394,7 @@ server_extension_stream(struct ct *t)
|
|||||||
aowner = req.owner;
|
aowner = req.owner;
|
||||||
CT_EQ_PTR(t, nil, testengineowner());
|
CT_EQ_PTR(t, nil, testengineowner());
|
||||||
allowrequest(&f.pump);
|
allowrequest(&f.pump);
|
||||||
CT_EQ_INT(t, 1, readreply(t, &a, 1, preedit));
|
CT_EQ_INT(t, 1, readreply(t, &a, 1, "", preedit));
|
||||||
CT_EQ_STR(t, "", preedit);
|
CT_EQ_STR(t, "", preedit);
|
||||||
|
|
||||||
ipcpackcaret(frame, 1, -101, -7, 23);
|
ipcpackcaret(frame, 1, -101, -7, 23);
|
||||||
@@ -419,7 +420,7 @@ server_extension_stream(struct ct *t)
|
|||||||
CT_EQ_INT(t, -7, req.caret.y);
|
CT_EQ_INT(t, -7, req.caret.y);
|
||||||
CT_EQ_INT(t, 23, req.caret.h);
|
CT_EQ_INT(t, 23, req.caret.h);
|
||||||
allowrequest(&f.pump);
|
allowrequest(&f.pump);
|
||||||
CT_EQ_INT(t, 1, readreply(t, &a, 1, preedit));
|
CT_EQ_INT(t, 1, readreply(t, &a, 1, "", preedit));
|
||||||
CT_EQ_STR(t, "k", preedit);
|
CT_EQ_STR(t, "k", preedit);
|
||||||
CT_EQ_PTR(t, aowner, testengineowner());
|
CT_EQ_PTR(t, aowner, testengineowner());
|
||||||
|
|
||||||
@@ -430,7 +431,7 @@ server_extension_stream(struct ct *t)
|
|||||||
CT_EQ_PTR(t, aowner, req.owner);
|
CT_EQ_PTR(t, aowner, req.owner);
|
||||||
CT_EQ_INT(t, 1, req.caret.valid);
|
CT_EQ_INT(t, 1, req.caret.valid);
|
||||||
allowrequest(&f.pump);
|
allowrequest(&f.pump);
|
||||||
CT_EQ_INT(t, 1, readreply(t, &a, 0, preedit));
|
CT_EQ_INT(t, 1, readreply(t, &a, 0, "", preedit));
|
||||||
|
|
||||||
/* Reset is still the old six-byte frame and does not discard caret. */
|
/* Reset is still the old six-byte frame and does not discard caret. */
|
||||||
ipcpackreset(frame, 0);
|
ipcpackreset(frame, 0);
|
||||||
@@ -443,14 +444,14 @@ server_extension_stream(struct ct *t)
|
|||||||
CT_EQ_INT(t, -7, req.caret.y);
|
CT_EQ_INT(t, -7, req.caret.y);
|
||||||
CT_EQ_INT(t, 23, req.caret.h);
|
CT_EQ_INT(t, 23, req.caret.h);
|
||||||
allowrequest(&f.pump);
|
allowrequest(&f.pump);
|
||||||
CT_EQ_INT(t, 1, readreply(t, &a, 0, preedit));
|
CT_EQ_INT(t, 1, readreply(t, &a, 0, "k", preedit));
|
||||||
|
|
||||||
ipcpackcap(frame, Cclientpreedit);
|
ipcpackcap(frame, Cclientpreedit);
|
||||||
if(!sendframe(t, &a, frame, Ipcreqsz, 0))
|
if(!sendframe(t, &a, frame, Ipcreqsz, 0))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
req = nextrequest(t, &f.pump, Keycap);
|
req = nextrequest(t, &f.pump, Keycap);
|
||||||
allowrequest(&f.pump);
|
allowrequest(&f.pump);
|
||||||
CT_EQ_INT(t, 1, readreply(t, &a, 1, preedit));
|
CT_EQ_INT(t, 1, readreply(t, &a, 1, "", preedit));
|
||||||
CT_EQ_STR(t, "", preedit);
|
CT_EQ_STR(t, "", preedit);
|
||||||
ipcpackreq(frame, 1, 0, 'n');
|
ipcpackreq(frame, 1, 0, 'n');
|
||||||
if(!sendframe(t, &a, frame, Ipcreqsz, 0))
|
if(!sendframe(t, &a, frame, Ipcreqsz, 0))
|
||||||
@@ -459,7 +460,7 @@ server_extension_stream(struct ct *t)
|
|||||||
CT_EQ_INT(t, 1, req.caret.valid);
|
CT_EQ_INT(t, 1, req.caret.valid);
|
||||||
CT_EQ_INT(t, -101, req.caret.x);
|
CT_EQ_INT(t, -101, req.caret.x);
|
||||||
allowrequest(&f.pump);
|
allowrequest(&f.pump);
|
||||||
CT_EQ_INT(t, 1, readreply(t, &a, 1, preedit));
|
CT_EQ_INT(t, 1, readreply(t, &a, 1, "", preedit));
|
||||||
CT_EQ_STR(t, "ん", preedit);
|
CT_EQ_STR(t, "ん", preedit);
|
||||||
|
|
||||||
disconnectclient(t, &f.pump, &a, aowner);
|
disconnectclient(t, &f.pump, &a, aowner);
|
||||||
@@ -471,7 +472,7 @@ server_extension_stream(struct ct *t)
|
|||||||
bowner = req.owner;
|
bowner = req.owner;
|
||||||
CT_EQ_INT(t, 0, req.caret.valid);
|
CT_EQ_INT(t, 0, req.caret.valid);
|
||||||
allowrequest(&f.pump);
|
allowrequest(&f.pump);
|
||||||
CT_EQ_INT(t, 1, readreply(t, &b, 1, preedit));
|
CT_EQ_INT(t, 1, readreply(t, &b, 1, "", preedit));
|
||||||
CT_EQ_STR(t, "k", preedit);
|
CT_EQ_STR(t, "k", preedit);
|
||||||
|
|
||||||
disconnectclient(t, &f.pump, &b, bowner);
|
disconnectclient(t, &f.pump, &b, bowner);
|
||||||
@@ -532,7 +533,7 @@ server_rejects_unknown_extension(struct ct *t)
|
|||||||
req = nextrequest(t, &f.pump, Keypress);
|
req = nextrequest(t, &f.pump, Keypress);
|
||||||
owner = req.owner;
|
owner = req.owner;
|
||||||
allowrequest(&f.pump);
|
allowrequest(&f.pump);
|
||||||
CT_EQ_INT(t, 1, readreply(t, &good, 1, preedit));
|
CT_EQ_INT(t, 1, readreply(t, &good, 1, "", preedit));
|
||||||
CT_EQ_STR(t, "k", preedit);
|
CT_EQ_STR(t, "k", preedit);
|
||||||
disconnectclient(t, &f.pump, &good, owner);
|
disconnectclient(t, &f.pump, &good, owner);
|
||||||
|
|
||||||
|
|||||||
@@ -901,7 +901,6 @@ xim_adapter_callback_cleanup(struct ct *t)
|
|||||||
memset(&reply, 0, sizeof reply);
|
memset(&reply, 0, sizeof reply);
|
||||||
hdr.major_opcode = XCB_XIM_RESET_IC;
|
hdr.major_opcode = XCB_XIM_RESET_IC;
|
||||||
callback(nil, nil, ic, &hdr, nil, &reply, nil);
|
callback(nil, nil, ic, &hdr, nil, &reply, nil);
|
||||||
nexttrace(t, &f, Keycap, &state);
|
|
||||||
nexttrace(t, &f, Keyreset, &state);
|
nexttrace(t, &f, Keyreset, &state);
|
||||||
notrace(t, &f);
|
notrace(t, &f);
|
||||||
checkct(t, "reset reply", reply.committed_string,
|
checkct(t, "reset reply", reply.committed_string,
|
||||||
|
|||||||
21
xim/xim.c
21
xim/xim.c
@@ -311,23 +311,31 @@ keypress(Ic *state, u32int key, u32int mod, Keyres *res)
|
|||||||
sendrequest(state, Keypress, key, mod, res);
|
sendrequest(state, Keypress, key, mod, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Losing the engine commits the pending text; the release hands it back. */
|
||||||
static void
|
static void
|
||||||
release(Ic *state)
|
release(Ic *state)
|
||||||
{
|
{
|
||||||
Keyres res;
|
Keyres res;
|
||||||
|
char buf[Maxutf];
|
||||||
|
int n;
|
||||||
|
|
||||||
clearpreedit(state);
|
if(!state->engaged){
|
||||||
if(!state->engaged)
|
clearpreedit(state);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
sendrequest(state, Keyrelease, 0, 0, &res);
|
sendrequest(state, Keyrelease, 0, 0, &res);
|
||||||
state->engaged = 0;
|
state->engaged = 0;
|
||||||
|
n = stoutf(&res.commit, buf, sizeof buf);
|
||||||
|
commit(state, buf, n);
|
||||||
|
clearpreedit(state);
|
||||||
|
xcb_flush(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XIM reset hands the pending preedit back to the client as committed text. */
|
/* XIM reset hands the pending text back to the client as committed text. */
|
||||||
static void
|
static void
|
||||||
resetic(Ic *state, xcb_im_reset_ic_reply_fr_t *reply)
|
resetic(Ic *state, xcb_im_reset_ic_reply_fr_t *reply)
|
||||||
{
|
{
|
||||||
Keyres pending, res;
|
Keyres res;
|
||||||
char utf[Maxutf], *wire;
|
char utf[Maxutf], *wire;
|
||||||
size_t nwire;
|
size_t nwire;
|
||||||
int nbyte;
|
int nbyte;
|
||||||
@@ -336,12 +344,11 @@ resetic(Ic *state, xcb_im_reset_ic_reply_fr_t *reply)
|
|||||||
clearpreedit(state);
|
clearpreedit(state);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sendrequest(state, Keycap, 0, 0, &pending);
|
|
||||||
sendrequest(state, Keyreset, 0, 0, &res);
|
sendrequest(state, Keyreset, 0, 0, &res);
|
||||||
clearpreedit(state);
|
clearpreedit(state);
|
||||||
if(reply == nil || !pending.eaten || pending.preedit.n == 0)
|
if(reply == nil || res.commit.n == 0)
|
||||||
return;
|
return;
|
||||||
nbyte = stoutf(&pending.preedit, utf, sizeof utf);
|
nbyte = stoutf(&res.commit, utf, sizeof utf);
|
||||||
wire = xcb_utf8_to_compound_text(utf, nbyte, &nwire);
|
wire = xcb_utf8_to_compound_text(utf, nbyte, &nwire);
|
||||||
if(wire == nil)
|
if(wire == nil)
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user