ipc, srv, gtk: the client's text goes over and a take-back comes back
The engine can reach a Hanja reading back into the text the client already holds, but only if the frontend hands that text over and can take some of it away again. GTK 3 has both: retrieve-surrounding brings the text around the cursor and delete-surrounding removes runes before it, and a widget that answers neither leaves the text empty, so nothing is ever reached into or taken from it. The wire grows a control frame for the text, sent like the caret only when it changes, and one byte in every response for the runes to take back. That byte moves the length fields along, so the version goes to 2: an old daemon and a new module, either way round, fail the handshake and the module falls through to GtkIMContextSimple rather than misread a frame. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -23,6 +23,7 @@ typedef struct Response Response;
|
||||
struct Response
|
||||
{
|
||||
int eaten;
|
||||
int del;
|
||||
char commit[Ipcfieldmax+1];
|
||||
char preedit[Ipcfieldmax+1];
|
||||
};
|
||||
@@ -50,7 +51,8 @@ readresponseuntil(int fd, int want, Response *res, int64_t deadline,
|
||||
return rv;
|
||||
}
|
||||
res->eaten = hdr[0] != 0;
|
||||
n = getlen(hdr + 1);
|
||||
res->del = hdr[1];
|
||||
n = getlen(hdr + 2);
|
||||
if(n > Ipcfieldmax){
|
||||
fail("invalid commit length %zu", n);
|
||||
return -1;
|
||||
@@ -119,6 +121,18 @@ sendcap(int fd, int cap)
|
||||
return ipcsend(fd, req, sizeof req) == 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sendsurround(int fd, char *text)
|
||||
{
|
||||
unsigned char req[Ipcreqsz];
|
||||
size_t n;
|
||||
|
||||
n = strlen(text);
|
||||
ipcpacksurround(req, n);
|
||||
return ipcsend(fd, req, sizeof req) == 0 &&
|
||||
(n == 0 || ipcsend(fd, text, n) == 0);
|
||||
}
|
||||
|
||||
static int
|
||||
expectresponse(int fd, int want, int eaten, char *commit, char *preedit,
|
||||
char *where)
|
||||
@@ -152,6 +166,33 @@ requestkey(int fd, int want, uint32_t mod, uint32_t key, int eaten,
|
||||
return expectresponse(fd, want, eaten, commit, preedit, where);
|
||||
}
|
||||
|
||||
/*
|
||||
* The Korean habit: 한자 typed, then the Hanja key. The 한 is the
|
||||
* client's by then, so the daemon must ask for it back and answer with
|
||||
* the whole word.
|
||||
*/
|
||||
static int
|
||||
requesthanja(int fd)
|
||||
{
|
||||
Response res;
|
||||
|
||||
if(!sendsurround(fd, "저는 한"))
|
||||
return fail("send surrounding text: %s", strerror(errno));
|
||||
if(!requestkey(fd, 1, Mctrl, 's', 1, "", "", "select Korean") ||
|
||||
!requestkey(fd, 1, 0, 'w', 1, "", "ㅈ", "jamo") ||
|
||||
!requestkey(fd, 1, 0, 'k', 1, "", "자", "syllable") ||
|
||||
!requestkey(fd, 1, Mctrl, 'h', 1, "", "자", "Hanja search"))
|
||||
return 0;
|
||||
if(!sendkey(fd, 1, 0, Kret))
|
||||
return fail("send Hanja pick: %s", strerror(errno));
|
||||
if(readresponseuntil(fd, 1, &res, nowms() + Calltimeout, 0) != 1)
|
||||
return 0;
|
||||
if(strcmp(res.commit, "漢字") != 0 || res.del != 1)
|
||||
return fail("Hanja pick committed %s and took back %d",
|
||||
res.commit, res.del);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
tryclient(char *path, int64_t deadline, int *client)
|
||||
{
|
||||
@@ -258,7 +299,8 @@ runsmoke(char *path)
|
||||
requestkey(client, 1, Mctrl, 'n', 1, "", "",
|
||||
"select Japanese") &&
|
||||
requestkey(client, 1, 0, 'k', 1, "", "k", "preedit") &&
|
||||
requestreset(client, 1, 1, "k", "", "reset");
|
||||
requestreset(client, 1, 1, "k", "", "reset") &&
|
||||
requesthanja(client);
|
||||
close(client);
|
||||
return ok;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user