wl: the text before the cursor, and the runes to take back
The surrounding_text event was taken and thrown away. It carries the text around the cursor with a byte offset into it, and belongs to the activation like the content type, so it is pending until done and starts empty at every activate. delete_surrounding_text counts bytes where the engine counts runes, and the frontend holds the text those runes are in, so it measures them itself. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -129,4 +129,5 @@ void xim_adapter_callback_owner_loss(struct ct*);
|
|||||||
void xim_adapter_commit_encoding(struct ct*);
|
void xim_adapter_commit_encoding(struct ct*);
|
||||||
void wl_modifier_mask(struct ct*);
|
void wl_modifier_mask(struct ct*);
|
||||||
void wl_forwarded_keys(struct ct*);
|
void wl_forwarded_keys(struct ct*);
|
||||||
|
void wl_surrounding_text(struct ct*);
|
||||||
void wl_repeat_ends(struct ct*);
|
void wl_repeat_ends(struct ct*);
|
||||||
|
|||||||
@@ -149,6 +149,7 @@ static const struct ct_test tests[] = {
|
|||||||
{ "xim/commit-encoding", xim_adapter_commit_encoding },
|
{ "xim/commit-encoding", xim_adapter_commit_encoding },
|
||||||
{ "wl/modifier-mask", wl_modifier_mask },
|
{ "wl/modifier-mask", wl_modifier_mask },
|
||||||
{ "wl/forwarded-keys", wl_forwarded_keys },
|
{ "wl/forwarded-keys", wl_forwarded_keys },
|
||||||
|
{ "wl/surrounding-text", wl_surrounding_text },
|
||||||
{ "wl/repeat-ends", wl_repeat_ends },
|
{ "wl/repeat-ends", wl_repeat_ends },
|
||||||
};
|
};
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -107,6 +107,30 @@ wl_forwarded_keys(struct ct *t)
|
|||||||
* Arming a repeat needs the engine, which is not here; ending one does
|
* Arming a repeat needs the engine, which is not here; ending one does
|
||||||
* not, and a repeat that outlives its key is the worst this can do.
|
* not, and a repeat that outlives its key is the worst this can do.
|
||||||
*/
|
*/
|
||||||
|
/*
|
||||||
|
* The text before the cursor is what a reading may reach into, and a
|
||||||
|
* take-back is measured in the bytes those runes hold.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
wl_surrounding_text(struct ct *t)
|
||||||
|
{
|
||||||
|
sclear(&pendingsurround);
|
||||||
|
imsurrounding(nil, nil, "가나다라", 9, 9);
|
||||||
|
checkstr(t, "the text before the cursor", "가나다", &pendingsurround);
|
||||||
|
surround = pendingsurround;
|
||||||
|
CT_EQ_INT(t, 3, backbytes(1));
|
||||||
|
CT_EQ_INT(t, 6, backbytes(2));
|
||||||
|
CT_EQ_INT(t, 9, backbytes(9));
|
||||||
|
CT_EQ_INT(t, 0, backbytes(0));
|
||||||
|
/* A cursor past the end of the buffer is the whole of it. */
|
||||||
|
imsurrounding(nil, nil, "ab", 99, 99);
|
||||||
|
checkstr(t, "a cursor past the end", "ab", &pendingsurround);
|
||||||
|
/* An activation starts with none, whatever the last one had. */
|
||||||
|
imactivate(nil, nil);
|
||||||
|
CT_EQ_INT(t, 0, pendingsurround.n);
|
||||||
|
sclear(&surround);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
wl_repeat_ends(struct ct *t)
|
wl_repeat_ends(struct ct *t)
|
||||||
{
|
{
|
||||||
|
|||||||
34
wl.c
34
wl.c
@@ -65,6 +65,7 @@ static int active; /* a text input is being served */
|
|||||||
static int pendingactive;
|
static int pendingactive;
|
||||||
static int activated; /* an activate arrived since the last done */
|
static int activated; /* an activate arrived since the last done */
|
||||||
static u32int purpose, pendingpurpose;
|
static u32int purpose, pendingpurpose;
|
||||||
|
static Str surround, pendingsurround; /* the client's text before the cursor */
|
||||||
static u32int sent[Maxcode/32]; /* keycodes passed on and still down */
|
static u32int sent[Maxcode/32]; /* keycodes passed on and still down */
|
||||||
static u32int lasttime; /* the compositor's clock, for a release of our own */
|
static u32int lasttime; /* the compositor's clock, for a release of our own */
|
||||||
static int reprate; /* repeats a second the seat asks for; 0 is none */
|
static int reprate; /* repeats a second the seat asks for; 0 is none */
|
||||||
@@ -116,11 +117,26 @@ sendrequest(int op, u32int ks, u32int mod, Keyres *res)
|
|||||||
kr.op = op;
|
kr.op = op;
|
||||||
kr.ks = ks;
|
kr.ks = ks;
|
||||||
kr.mod = mod;
|
kr.mod = mod;
|
||||||
|
kr.surround = surround;
|
||||||
kr.reply = replyc;
|
kr.reply = replyc;
|
||||||
chansend(keyc, &kr);
|
chansend(keyc, &kr);
|
||||||
chanrecv(replyc, res);
|
chanrecv(replyc, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The bytes the last n runes of the client's text take. */
|
||||||
|
static int
|
||||||
|
backbytes(int n)
|
||||||
|
{
|
||||||
|
char utf[Maxutf];
|
||||||
|
Str s;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
sclear(&s);
|
||||||
|
for(i = max(surround.n - n, 0); i < surround.n; i++)
|
||||||
|
sputr(&s, surround.r[i]);
|
||||||
|
return stoutf(&s, utf, sizeof utf);
|
||||||
|
}
|
||||||
|
|
||||||
/* The engine's modifier bits, read from the grab's own keyboard state. */
|
/* The engine's modifier bits, read from the grab's own keyboard state. */
|
||||||
static u32int
|
static u32int
|
||||||
modmask(void)
|
modmask(void)
|
||||||
@@ -187,6 +203,10 @@ answer(Keyres *res, char *tail)
|
|||||||
char utf[2*Maxutf];
|
char utf[2*Maxutf];
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
|
/* The compositor takes the text back before it inserts ours. */
|
||||||
|
if(res->del > 0)
|
||||||
|
zwp_input_method_v2_delete_surrounding_text(im,
|
||||||
|
backbytes(res->del), 0);
|
||||||
n = stoutf(&res->commit, utf, sizeof utf);
|
n = stoutf(&res->commit, utf, sizeof utf);
|
||||||
if(tail[0] != '\0')
|
if(tail[0] != '\0')
|
||||||
n += snprint(utf+n, sizeof utf - n, "%s", tail);
|
n += snprint(utf+n, sizeof utf - n, "%s", tail);
|
||||||
@@ -407,6 +427,7 @@ imactivate(void*, struct zwp_input_method_v2*)
|
|||||||
pendingactive = 1;
|
pendingactive = 1;
|
||||||
activated = 1;
|
activated = 1;
|
||||||
pendingpurpose = 0;
|
pendingpurpose = 0;
|
||||||
|
sclear(&pendingsurround);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -415,9 +436,19 @@ imdeactivate(void*, struct zwp_input_method_v2*)
|
|||||||
pendingactive = 0;
|
pendingactive = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text around the cursor, of which a reading can use what comes
|
||||||
|
* before it. A text input that sends none leaves this empty, and then
|
||||||
|
* nothing is ever reached back into or taken away.
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
imsurrounding(void*, struct zwp_input_method_v2*, const char*, u32int, u32int)
|
imsurrounding(void*, struct zwp_input_method_v2*, const char *text,
|
||||||
|
u32int cursor, u32int)
|
||||||
{
|
{
|
||||||
|
u32int n;
|
||||||
|
|
||||||
|
n = strlen(text);
|
||||||
|
stail(&pendingsurround, (char*)text, cursor < n ? cursor : n);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -444,6 +475,7 @@ imdone(void*, struct zwp_input_method_v2*)
|
|||||||
serial++;
|
serial++;
|
||||||
washidden = hidden();
|
washidden = hidden();
|
||||||
purpose = pendingpurpose;
|
purpose = pendingpurpose;
|
||||||
|
surround = pendingsurround;
|
||||||
if(activated || (active && !pendingactive))
|
if(activated || (active && !pendingactive))
|
||||||
leave();
|
leave();
|
||||||
else if(active && !washidden && hidden())
|
else if(active && !washidden && hidden())
|
||||||
|
|||||||
Reference in New Issue
Block a user