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>
166 lines
4.6 KiB
C
166 lines
4.6 KiB
C
#include <wayland-client.h>
|
|
#include <xkbcommon/xkbcommon.h>
|
|
#include "vkv1.h"
|
|
|
|
/* The virtual keyboard is the only wire call the tested code makes. */
|
|
static int nkeysent;
|
|
static void wirekey(struct zwp_virtual_keyboard_v1*, uint32_t, uint32_t,
|
|
uint32_t);
|
|
|
|
#define zwp_virtual_keyboard_v1_key wirekey
|
|
|
|
#include "wl.c"
|
|
#include "test.h"
|
|
|
|
static void
|
|
wirekey(struct zwp_virtual_keyboard_v1 *vkb, uint32_t time, uint32_t code,
|
|
uint32_t state)
|
|
{
|
|
USED(vkb);
|
|
USED(time);
|
|
USED(code);
|
|
USED(state);
|
|
nkeysent++;
|
|
}
|
|
|
|
/* Only the modifiers are read from it, so nothing else need be here. */
|
|
static char keymaptext[] =
|
|
"xkb_keymap {\n"
|
|
"xkb_keycodes { <AD01> = 24; };\n"
|
|
"xkb_types { type \"ONE_LEVEL\" {\n"
|
|
" modifiers = none; map[none] = 1; level_name[1] = \"Any\"; }; };\n"
|
|
"xkb_compatibility { };\n"
|
|
"xkb_symbols { key <AD01> { [ q ] }; };\n"
|
|
"};\n";
|
|
|
|
void
|
|
wl_modifier_mask(struct ct *t)
|
|
{
|
|
struct xkb_context *ctx;
|
|
struct xkb_keymap *km;
|
|
xkb_mod_mask_t caps, ctrl, shift;
|
|
|
|
ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
|
km = xkb_keymap_new_from_string(ctx, keymaptext,
|
|
XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
|
|
CT_CHECK(t, km != nil);
|
|
if(km != nil){
|
|
kstate = xkb_state_new(km);
|
|
shift = (xkb_mod_mask_t)1 <<
|
|
xkb_keymap_mod_get_index(km, XKB_MOD_NAME_SHIFT);
|
|
ctrl = (xkb_mod_mask_t)1 <<
|
|
xkb_keymap_mod_get_index(km, XKB_MOD_NAME_CTRL);
|
|
caps = (xkb_mod_mask_t)1 <<
|
|
xkb_keymap_mod_get_index(km, XKB_MOD_NAME_CAPS);
|
|
xkb_state_update_mask(kstate, shift, 0, 0, 0, 0, 0);
|
|
CT_EQ_UINT(t, Mshift, modmask());
|
|
xkb_state_update_mask(kstate, shift|ctrl, 0, 0, 0, 0, 0);
|
|
CT_EQ_UINT(t, Mshift|Mctrl, modmask());
|
|
/* Caps Lock is not Shift; a Korean key must not shift under it. */
|
|
xkb_state_update_mask(kstate, 0, 0, caps, 0, 0, 0);
|
|
CT_EQ_UINT(t, 0, modmask());
|
|
xkb_state_unref(kstate);
|
|
kstate = nil;
|
|
xkb_keymap_unref(km);
|
|
}
|
|
xkb_context_unref(ctx);
|
|
}
|
|
|
|
void
|
|
wl_forwarded_keys(struct ct *t)
|
|
{
|
|
haskeymap = 1;
|
|
memset(sent, 0, sizeof sent);
|
|
nkeysent = 0;
|
|
|
|
forward(30, WL_KEYBOARD_KEY_STATE_PRESSED);
|
|
CT_CHECK(t, issent(30));
|
|
forward(30, WL_KEYBOARD_KEY_STATE_RELEASED);
|
|
CT_CHECK(t, !issent(30));
|
|
CT_EQ_INT(t, 2, nkeysent);
|
|
|
|
/* A code the bitmap cannot hold is not passed on at all. */
|
|
nkeysent = 0;
|
|
forward(Maxcode, WL_KEYBOARD_KEY_STATE_PRESSED);
|
|
CT_EQ_INT(t, 0, nkeysent);
|
|
|
|
/* Whatever is still down is released, once each and no more. */
|
|
forward(1, WL_KEYBOARD_KEY_STATE_PRESSED);
|
|
forward(200, WL_KEYBOARD_KEY_STATE_PRESSED);
|
|
nkeysent = 0;
|
|
releasekeys();
|
|
CT_EQ_INT(t, 2, nkeysent);
|
|
CT_CHECK(t, !issent(1));
|
|
CT_CHECK(t, !issent(200));
|
|
releasekeys();
|
|
CT_EQ_INT(t, 2, nkeysent);
|
|
|
|
/* Before a keymap the virtual keyboard must not be touched. */
|
|
haskeymap = 0;
|
|
nkeysent = 0;
|
|
forward(30, WL_KEYBOARD_KEY_STATE_PRESSED);
|
|
CT_EQ_INT(t, 0, nkeysent);
|
|
CT_CHECK(t, !issent(30));
|
|
}
|
|
|
|
/*
|
|
* 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.
|
|
*/
|
|
/*
|
|
* 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
|
|
wl_repeat_ends(struct ct *t)
|
|
{
|
|
haskeymap = 1;
|
|
memset(sent, 0, sizeof sent);
|
|
|
|
/* Not a rate or a delay any seat would pick: the body was empty
|
|
* once, and a stored constant would pass for the real thing. */
|
|
grabrepeat(nil, nil, 33, 410);
|
|
CT_EQ_INT(t, 33, reprate);
|
|
CT_EQ_INT(t, 410, repdelay);
|
|
|
|
/* The key's own release ends it; another key's release does not. */
|
|
repcode = 14;
|
|
repdue = 1;
|
|
grabkey(nil, nil, 0, 0, 15, WL_KEYBOARD_KEY_STATE_RELEASED);
|
|
CT_CHECK(t, repdue != 0);
|
|
grabkey(nil, nil, 0, 0, 14, WL_KEYBOARD_KEY_STATE_RELEASED);
|
|
CT_EQ_INT(t, 0, repdue);
|
|
|
|
/* So does a seat that has stopped repeating anything. */
|
|
repdue = 1;
|
|
grabrepeat(nil, nil, 0, 410);
|
|
CT_EQ_INT(t, 0, repdue);
|
|
|
|
/* A due repeat with no text input to serve is dropped, not sent. */
|
|
grabrepeat(nil, nil, 33, 410);
|
|
active = 0;
|
|
repdue = 1;
|
|
repeat();
|
|
CT_EQ_INT(t, 0, repdue);
|
|
}
|