ibus: honor preedit and private-input policy
This commit is contained in:
190
ibus.c
190
ibus.c
@@ -17,6 +17,11 @@ enum
|
|||||||
Maxcontexts = 64,
|
Maxcontexts = 64,
|
||||||
Relmask = 1<<30,
|
Relmask = 1<<30,
|
||||||
Ibussupermask = 1<<26,
|
Ibussupermask = 1<<26,
|
||||||
|
/* IBus wire constants; the daemon does not link libibus. */
|
||||||
|
Ibuscappreedit = 1<<0,
|
||||||
|
Ibuspurposepassword = 8,
|
||||||
|
Ibuspurposepin = 9,
|
||||||
|
Ibushinthidden = 1<<12,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct Ictx Ictx;
|
typedef struct Ictx Ictx;
|
||||||
@@ -25,6 +30,9 @@ struct Ictx
|
|||||||
DBusConnection *conn;
|
DBusConnection *conn;
|
||||||
char path[64];
|
char path[64];
|
||||||
int focused;
|
int focused;
|
||||||
|
u32int cap;
|
||||||
|
u32int purpose;
|
||||||
|
u32int hints;
|
||||||
Caret caret;
|
Caret caret;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -303,7 +311,7 @@ sendrequest(Ictx *ctx, int op, u32int ks, u32int mod, Keyres *res)
|
|||||||
|
|
||||||
memset(&kr, 0, sizeof kr);
|
memset(&kr, 0, sizeof kr);
|
||||||
kr.owner = ctx;
|
kr.owner = ctx;
|
||||||
kr.cap = Cclientpreedit;
|
kr.cap = ctx->cap & Ibuscappreedit ? Cclientpreedit : 0;
|
||||||
kr.op = op;
|
kr.op = op;
|
||||||
kr.ks = ks;
|
kr.ks = ks;
|
||||||
kr.mod = mod;
|
kr.mod = mod;
|
||||||
@@ -341,10 +349,18 @@ dropconncontexts(DBusConnection *conn)
|
|||||||
dropcontext(&contexts[i]);
|
dropcontext(&contexts[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hidden(Ictx *ctx)
|
||||||
|
{
|
||||||
|
return ctx->purpose == Ibuspurposepassword ||
|
||||||
|
ctx->purpose == Ibuspurposepin ||
|
||||||
|
(ctx->hints & Ibushinthidden) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
processkey(Ictx *ctx, u32int sym, u32int state, Keyres *res)
|
processkey(Ictx *ctx, u32int sym, u32int state, Keyres *res)
|
||||||
{
|
{
|
||||||
if(state & Relmask || !ctx->focused)
|
if(state & Relmask || !ctx->focused || hidden(ctx))
|
||||||
return 0;
|
return 0;
|
||||||
sendrequest(ctx, Keypress, kget(sym), mget(state), res);
|
sendrequest(ctx, Keypress, kget(sym), mget(state), res);
|
||||||
return 1;
|
return 1;
|
||||||
@@ -522,6 +538,7 @@ handlekey(DBusConnection *c, DBusMessage *m, Ictx *ctx)
|
|||||||
stoutf(&res.preedit, preedit, sizeof preedit);
|
stoutf(&res.preedit, preedit, sizeof preedit);
|
||||||
if(commit[0] != '\0')
|
if(commit[0] != '\0')
|
||||||
emitcommit(c, dbus_message_get_path(m), commit);
|
emitcommit(c, dbus_message_get_path(m), commit);
|
||||||
|
if(ctx->cap & Ibuscappreedit)
|
||||||
emitpreedit(c, dbus_message_get_path(m), preedit);
|
emitpreedit(c, dbus_message_get_path(m), preedit);
|
||||||
return handlebool(c, m, res.eaten);
|
return handlebool(c, m, res.eaten);
|
||||||
}
|
}
|
||||||
@@ -562,6 +579,149 @@ handlefocusout(DBusConnection *c, DBusMessage *m, Ictx *ctx)
|
|||||||
return handlenoop(c, m);
|
return handlenoop(c, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DBusHandlerResult
|
||||||
|
handlecap(DBusConnection *c, DBusMessage *m, Ictx *ctx)
|
||||||
|
{
|
||||||
|
DBusError err;
|
||||||
|
dbus_uint32_t cap;
|
||||||
|
Keyres res;
|
||||||
|
char preedit[Maxutf];
|
||||||
|
u32int old;
|
||||||
|
|
||||||
|
dbus_error_init(&err);
|
||||||
|
if(!dbus_message_get_args(m, &err, DBUS_TYPE_UINT32, &cap,
|
||||||
|
DBUS_TYPE_INVALID)){
|
||||||
|
dbus_error_free(&err);
|
||||||
|
return handleerror(c, m, DBUS_ERROR_INVALID_ARGS,
|
||||||
|
"SetCapabilities expects one unsigned integer");
|
||||||
|
}
|
||||||
|
old = ctx->cap;
|
||||||
|
ctx->cap = cap;
|
||||||
|
if(ctx->focused){
|
||||||
|
sendrequest(ctx, Keycap, 0, 0, &res);
|
||||||
|
if((old & Ibuscappreedit) != (ctx->cap & Ibuscappreedit)){
|
||||||
|
if((ctx->cap & Ibuscappreedit) && res.eaten){
|
||||||
|
stoutf(&res.preedit, preedit, sizeof preedit);
|
||||||
|
emitpreedit(c, ctx->path, preedit);
|
||||||
|
}else if(!(ctx->cap & Ibuscappreedit))
|
||||||
|
emitpreedit(c, ctx->path, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return handlenoop(c, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
getcontent(DBusMessage *m, const char **iface, const char **name,
|
||||||
|
u32int *purpose, u32int *hints)
|
||||||
|
{
|
||||||
|
DBusMessageIter it, v, st;
|
||||||
|
dbus_uint32_t p, h;
|
||||||
|
|
||||||
|
if(!dbus_message_has_signature(m, "ssv") ||
|
||||||
|
!dbus_message_iter_init(m, &it))
|
||||||
|
return 0;
|
||||||
|
dbus_message_iter_get_basic(&it, iface);
|
||||||
|
dbus_message_iter_next(&it);
|
||||||
|
dbus_message_iter_get_basic(&it, name);
|
||||||
|
dbus_message_iter_next(&it);
|
||||||
|
dbus_message_iter_recurse(&it, &v);
|
||||||
|
if(dbus_message_iter_get_arg_type(&v) != DBUS_TYPE_STRUCT)
|
||||||
|
return 0;
|
||||||
|
dbus_message_iter_recurse(&v, &st);
|
||||||
|
if(dbus_message_iter_get_arg_type(&st) != DBUS_TYPE_UINT32)
|
||||||
|
return 0;
|
||||||
|
dbus_message_iter_get_basic(&st, &p);
|
||||||
|
if(!dbus_message_iter_next(&st) ||
|
||||||
|
dbus_message_iter_get_arg_type(&st) != DBUS_TYPE_UINT32)
|
||||||
|
return 0;
|
||||||
|
dbus_message_iter_get_basic(&st, &h);
|
||||||
|
if(dbus_message_iter_next(&st))
|
||||||
|
return 0;
|
||||||
|
*purpose = p;
|
||||||
|
*hints = h;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DBusHandlerResult
|
||||||
|
handlepropertyset(DBusConnection *c, DBusMessage *m, Ictx *ctx)
|
||||||
|
{
|
||||||
|
const char *iface, *name;
|
||||||
|
u32int purpose, hints;
|
||||||
|
Keyres res;
|
||||||
|
int washidden;
|
||||||
|
|
||||||
|
if(!getcontent(m, &iface, &name, &purpose, &hints))
|
||||||
|
return handleerror(c, m, DBUS_ERROR_INVALID_ARGS,
|
||||||
|
"Properties.Set expects ContentType as (uu)");
|
||||||
|
if(strcmp(iface, "org.freedesktop.IBus.InputContext") != 0)
|
||||||
|
return handleerror(c, m, DBUS_ERROR_UNKNOWN_INTERFACE,
|
||||||
|
"unknown property interface");
|
||||||
|
if(strcmp(name, "ContentType") != 0)
|
||||||
|
return handleerror(c, m, DBUS_ERROR_UNKNOWN_PROPERTY,
|
||||||
|
"unknown input context property");
|
||||||
|
washidden = hidden(ctx);
|
||||||
|
ctx->purpose = purpose;
|
||||||
|
ctx->hints = hints;
|
||||||
|
if(ctx->focused && !washidden && hidden(ctx)){
|
||||||
|
sendrequest(ctx, Keyreset, 0, 0, &res);
|
||||||
|
emitpreedit(c, ctx->path, "");
|
||||||
|
}
|
||||||
|
return handlenoop(c, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DBusHandlerResult
|
||||||
|
handlepropertyget(DBusConnection *c, DBusMessage *m, Ictx *ctx)
|
||||||
|
{
|
||||||
|
DBusError err;
|
||||||
|
const char *iface, *name;
|
||||||
|
|
||||||
|
USED(ctx);
|
||||||
|
dbus_error_init(&err);
|
||||||
|
if(!dbus_message_get_args(m, &err,
|
||||||
|
DBUS_TYPE_STRING, &iface, DBUS_TYPE_STRING, &name,
|
||||||
|
DBUS_TYPE_INVALID)){
|
||||||
|
dbus_error_free(&err);
|
||||||
|
return handleerror(c, m, DBUS_ERROR_INVALID_ARGS,
|
||||||
|
"Properties.Get expects interface and property names");
|
||||||
|
}
|
||||||
|
if(strcmp(iface, "org.freedesktop.IBus.InputContext") != 0)
|
||||||
|
return handleerror(c, m, DBUS_ERROR_UNKNOWN_INTERFACE,
|
||||||
|
"unknown property interface");
|
||||||
|
USED(name);
|
||||||
|
return handleerror(c, m, DBUS_ERROR_UNKNOWN_PROPERTY,
|
||||||
|
"input context properties are write-only");
|
||||||
|
}
|
||||||
|
|
||||||
|
static DBusHandlerResult
|
||||||
|
handlepropertygetall(DBusConnection *c, DBusMessage *m, Ictx *ctx)
|
||||||
|
{
|
||||||
|
DBusMessage *r;
|
||||||
|
DBusMessageIter it, a;
|
||||||
|
DBusError err;
|
||||||
|
const char *iface;
|
||||||
|
|
||||||
|
USED(ctx);
|
||||||
|
dbus_error_init(&err);
|
||||||
|
if(!dbus_message_get_args(m, &err, DBUS_TYPE_STRING, &iface,
|
||||||
|
DBUS_TYPE_INVALID)){
|
||||||
|
dbus_error_free(&err);
|
||||||
|
return handleerror(c, m, DBUS_ERROR_INVALID_ARGS,
|
||||||
|
"Properties.GetAll expects an interface name");
|
||||||
|
}
|
||||||
|
if(strcmp(iface, "org.freedesktop.IBus.InputContext") != 0)
|
||||||
|
return handleerror(c, m, DBUS_ERROR_UNKNOWN_INTERFACE,
|
||||||
|
"unknown property interface");
|
||||||
|
r = dbus_message_new_method_return(m);
|
||||||
|
if(r == nil)
|
||||||
|
return DBUS_HANDLER_RESULT_NEED_MEMORY;
|
||||||
|
dbus_message_iter_init_append(r, &it);
|
||||||
|
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "{sv}", &a);
|
||||||
|
dbus_message_iter_close_container(&it, &a);
|
||||||
|
dbus_connection_send(c, r, nil);
|
||||||
|
dbus_message_unref(r);
|
||||||
|
return DBUS_HANDLER_RESULT_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
static DBusHandlerResult
|
static DBusHandlerResult
|
||||||
handledestroy(DBusConnection *c, DBusMessage *m, Ictx *ctx)
|
handledestroy(DBusConnection *c, DBusMessage *m, Ictx *ctx)
|
||||||
{
|
{
|
||||||
@@ -617,10 +777,19 @@ static const char introspectxml[] =
|
|||||||
"<arg direction=\"in\" type=\"i\"/><arg direction=\"in\" type=\"i\"/>"
|
"<arg direction=\"in\" type=\"i\"/><arg direction=\"in\" type=\"i\"/>"
|
||||||
"<arg direction=\"in\" type=\"i\"/><arg direction=\"in\" type=\"i\"/></method>\n"
|
"<arg direction=\"in\" type=\"i\"/><arg direction=\"in\" type=\"i\"/></method>\n"
|
||||||
" <method name=\"SetEngine\"><arg direction=\"in\" type=\"s\"/></method>\n"
|
" <method name=\"SetEngine\"><arg direction=\"in\" type=\"s\"/></method>\n"
|
||||||
|
" <property name=\"ContentType\" type=\"(uu)\" access=\"write\"/>\n"
|
||||||
" <signal name=\"CommitText\"><arg type=\"v\"/></signal>\n"
|
" <signal name=\"CommitText\"><arg type=\"v\"/></signal>\n"
|
||||||
" <signal name=\"UpdatePreeditText\">"
|
" <signal name=\"UpdatePreeditText\">"
|
||||||
"<arg type=\"v\"/><arg type=\"u\"/><arg type=\"b\"/></signal>\n"
|
"<arg type=\"v\"/><arg type=\"u\"/><arg type=\"b\"/></signal>\n"
|
||||||
" </interface>\n"
|
" </interface>\n"
|
||||||
|
" <interface name=\"org.freedesktop.DBus.Properties\">\n"
|
||||||
|
" <method name=\"Get\"><arg direction=\"in\" type=\"s\"/>"
|
||||||
|
"<arg direction=\"in\" type=\"s\"/><arg direction=\"out\" type=\"v\"/></method>\n"
|
||||||
|
" <method name=\"Set\"><arg direction=\"in\" type=\"s\"/>"
|
||||||
|
"<arg direction=\"in\" type=\"s\"/><arg direction=\"in\" type=\"v\"/></method>\n"
|
||||||
|
" <method name=\"GetAll\"><arg direction=\"in\" type=\"s\"/>"
|
||||||
|
"<arg direction=\"out\" type=\"a{sv}\"/></method>\n"
|
||||||
|
" </interface>\n"
|
||||||
"</node>\n";
|
"</node>\n";
|
||||||
|
|
||||||
static DBusHandlerResult
|
static DBusHandlerResult
|
||||||
@@ -664,6 +833,18 @@ onmsg(DBusConnection *c, DBusMessage *m, void *_)
|
|||||||
if(strcmp(member, "CreateInputContext") == 0)
|
if(strcmp(member, "CreateInputContext") == 0)
|
||||||
return handlecreate(c, m);
|
return handlecreate(c, m);
|
||||||
}
|
}
|
||||||
|
if(strcmp(iface, "org.freedesktop.DBus.Properties") == 0){
|
||||||
|
ctx = findcontext(c, path);
|
||||||
|
if(ctx == nil)
|
||||||
|
return handleerror(c, m, DBUS_ERROR_UNKNOWN_OBJECT,
|
||||||
|
"unknown input context");
|
||||||
|
if(strcmp(member, "Set") == 0)
|
||||||
|
return handlepropertyset(c, m, ctx);
|
||||||
|
if(strcmp(member, "Get") == 0)
|
||||||
|
return handlepropertyget(c, m, ctx);
|
||||||
|
if(strcmp(member, "GetAll") == 0)
|
||||||
|
return handlepropertygetall(c, m, ctx);
|
||||||
|
}
|
||||||
if(strcmp(iface, "org.freedesktop.IBus.InputContext") == 0){
|
if(strcmp(iface, "org.freedesktop.IBus.InputContext") == 0){
|
||||||
ctx = findcontext(c, path);
|
ctx = findcontext(c, path);
|
||||||
if(ctx == nil)
|
if(ctx == nil)
|
||||||
@@ -681,8 +862,9 @@ onmsg(DBusConnection *c, DBusMessage *m, void *_)
|
|||||||
return handledestroy(c, m, ctx);
|
return handledestroy(c, m, ctx);
|
||||||
if(strcmp(member, "SetCursorLocation") == 0)
|
if(strcmp(member, "SetCursorLocation") == 0)
|
||||||
return handlecursor(c, m, ctx);
|
return handlecursor(c, m, ctx);
|
||||||
if(strcmp(member, "SetCapabilities") == 0
|
if(strcmp(member, "SetCapabilities") == 0)
|
||||||
|| strcmp(member, "SetEngine") == 0)
|
return handlecap(c, m, ctx);
|
||||||
|
if(strcmp(member, "SetEngine") == 0)
|
||||||
return handlenoop(c, m);
|
return handlenoop(c, m);
|
||||||
}
|
}
|
||||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||||
|
|||||||
@@ -26,6 +26,12 @@ enum
|
|||||||
Stoptimeout = 3000,
|
Stoptimeout = 3000,
|
||||||
Relmask = 1<<30,
|
Relmask = 1<<30,
|
||||||
Ctrlmask = 1<<2,
|
Ctrlmask = 1<<2,
|
||||||
|
Cappreedit = 1<<0,
|
||||||
|
Purposefree = 0,
|
||||||
|
Purposepassword = 8,
|
||||||
|
Purposepin = 9,
|
||||||
|
Hintprivate = 1<<11,
|
||||||
|
Hinthidden = 1<<12,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct Daemon Daemon;
|
typedef struct Daemon Daemon;
|
||||||
@@ -837,6 +843,66 @@ emptycall(DBusConnection *conn, Siglog *log, char *path, char *member)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
capcall(DBusConnection *conn, Siglog *log, char *path, dbus_uint32_t cap)
|
||||||
|
{
|
||||||
|
DBusMessage *m, *reply;
|
||||||
|
|
||||||
|
resetsig(log);
|
||||||
|
m = method(path, "org.freedesktop.IBus.InputContext", "SetCapabilities");
|
||||||
|
if(m == NULL || !dbus_message_append_args(m, DBUS_TYPE_UINT32, &cap,
|
||||||
|
DBUS_TYPE_INVALID)){
|
||||||
|
if(m != NULL) dbus_message_unref(m);
|
||||||
|
return fail("build SetCapabilities call");
|
||||||
|
}
|
||||||
|
reply = sendcall(conn, m);
|
||||||
|
if(reply == NULL)
|
||||||
|
return 0;
|
||||||
|
if(!dbus_message_has_signature(reply, "")){
|
||||||
|
dbus_message_unref(reply);
|
||||||
|
return fail("SetCapabilities returned a nonempty reply");
|
||||||
|
}
|
||||||
|
dbus_message_unref(reply);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
contentcall(DBusConnection *conn, Siglog *log, char *path,
|
||||||
|
dbus_uint32_t purpose, dbus_uint32_t hints)
|
||||||
|
{
|
||||||
|
DBusMessage *m, *reply;
|
||||||
|
DBusMessageIter it, v, st;
|
||||||
|
const char *iface, *property;
|
||||||
|
|
||||||
|
resetsig(log);
|
||||||
|
iface = "org.freedesktop.IBus.InputContext";
|
||||||
|
property = "ContentType";
|
||||||
|
m = method(path, "org.freedesktop.DBus.Properties", "Set");
|
||||||
|
if(m == NULL)
|
||||||
|
return 0;
|
||||||
|
dbus_message_iter_init_append(m, &it);
|
||||||
|
if(!dbus_message_iter_append_basic(&it, DBUS_TYPE_STRING, &iface) ||
|
||||||
|
!dbus_message_iter_append_basic(&it, DBUS_TYPE_STRING, &property) ||
|
||||||
|
!dbus_message_iter_open_container(&it, DBUS_TYPE_VARIANT, "(uu)", &v) ||
|
||||||
|
!dbus_message_iter_open_container(&v, DBUS_TYPE_STRUCT, NULL, &st) ||
|
||||||
|
!dbus_message_iter_append_basic(&st, DBUS_TYPE_UINT32, &purpose) ||
|
||||||
|
!dbus_message_iter_append_basic(&st, DBUS_TYPE_UINT32, &hints) ||
|
||||||
|
!dbus_message_iter_close_container(&v, &st) ||
|
||||||
|
!dbus_message_iter_close_container(&it, &v)){
|
||||||
|
dbus_message_unref(m);
|
||||||
|
return fail("build Properties.Set ContentType call");
|
||||||
|
}
|
||||||
|
reply = sendcall(conn, m);
|
||||||
|
if(reply == NULL)
|
||||||
|
return 0;
|
||||||
|
if(!dbus_message_has_signature(reply, "")){
|
||||||
|
dbus_message_unref(reply);
|
||||||
|
return fail("Properties.Set ContentType returned a nonempty reply");
|
||||||
|
}
|
||||||
|
dbus_message_unref(reply);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
keycall(DBusConnection *conn, Siglog *log, char *path, dbus_uint32_t sym,
|
keycall(DBusConnection *conn, Siglog *log, char *path, dbus_uint32_t sym,
|
||||||
dbus_uint32_t state, int *eaten)
|
dbus_uint32_t state, int *eaten)
|
||||||
@@ -1037,18 +1103,18 @@ runconnectioncapacity(Daemon *d)
|
|||||||
!createcontext(conn[i], paths[i], sizeof paths[i]) ||
|
!createcontext(conn[i], paths[i], sizeof paths[i]) ||
|
||||||
!emptycall(conn[i], &logs[i], paths[i], "FocusIn") ||
|
!emptycall(conn[i], &logs[i], paths[i], "FocusIn") ||
|
||||||
!nosignal(&logs[i], "connection capacity FocusIn") ||
|
!nosignal(&logs[i], "connection capacity FocusIn") ||
|
||||||
!expectkey(conn[i], &logs[i], paths[i], 0xffe1, 0, 0, "",
|
!expectkey(conn[i], &logs[i], paths[i], 0xffe1, 0, 0, NULL,
|
||||||
"connection capacity key"))
|
"connection capacity key"))
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if(!overflowrejected(d->address))
|
if(!overflowrejected(d->address))
|
||||||
goto out;
|
goto out;
|
||||||
for(i = 0; i < Maxconnections; i++)
|
for(i = 0; i < Maxconnections; i++)
|
||||||
if(!expectkey(conn[i], &logs[i], paths[i], 0xffe1, 0, 0, "",
|
if(!expectkey(conn[i], &logs[i], paths[i], 0xffe1, 0, 0, NULL,
|
||||||
"accepted connection after rejection"))
|
"accepted connection after rejection"))
|
||||||
goto out;
|
goto out;
|
||||||
closebus(&conn[Maxconnections-1], &logs[Maxconnections-1]);
|
closebus(&conn[Maxconnections-1], &logs[Maxconnections-1]);
|
||||||
if(!expectkey(conn[0], &logs[0], paths[0], 0xffe1, 0, 0, "",
|
if(!expectkey(conn[0], &logs[0], paths[0], 0xffe1, 0, 0, NULL,
|
||||||
"connection close barrier"))
|
"connection close barrier"))
|
||||||
goto out;
|
goto out;
|
||||||
conn[Maxconnections-1] = openbus(d->address,
|
conn[Maxconnections-1] = openbus(d->address,
|
||||||
@@ -1061,6 +1127,9 @@ runconnectioncapacity(Daemon *d)
|
|||||||
!emptycall(conn[Maxconnections-1], &logs[Maxconnections-1],
|
!emptycall(conn[Maxconnections-1], &logs[Maxconnections-1],
|
||||||
paths[Maxconnections-1], "FocusIn") ||
|
paths[Maxconnections-1], "FocusIn") ||
|
||||||
!nosignal(&logs[Maxconnections-1], "recovered connection FocusIn") ||
|
!nosignal(&logs[Maxconnections-1], "recovered connection FocusIn") ||
|
||||||
|
!capcall(conn[Maxconnections-1], &logs[Maxconnections-1],
|
||||||
|
paths[Maxconnections-1], Cappreedit) ||
|
||||||
|
!nosignal(&logs[Maxconnections-1], "recovered connection capability") ||
|
||||||
!expectkey(conn[Maxconnections-1], &logs[Maxconnections-1],
|
!expectkey(conn[Maxconnections-1], &logs[Maxconnections-1],
|
||||||
paths[Maxconnections-1], 'n', Ctrlmask, 1, "",
|
paths[Maxconnections-1], 'n', Ctrlmask, 1, "",
|
||||||
"recovered connection select Japanese") ||
|
"recovered connection select Japanese") ||
|
||||||
@@ -1069,7 +1138,7 @@ runconnectioncapacity(Daemon *d)
|
|||||||
"recovered connection key"))
|
"recovered connection key"))
|
||||||
goto out;
|
goto out;
|
||||||
for(i = 0; i < Maxconnections-1; i++)
|
for(i = 0; i < Maxconnections-1; i++)
|
||||||
if(!expectkey(conn[i], &logs[i], paths[i], 0xffe1, 0, 0, "",
|
if(!expectkey(conn[i], &logs[i], paths[i], 0xffe1, 0, 0, NULL,
|
||||||
"accepted connection after recovery"))
|
"accepted connection after recovery"))
|
||||||
goto out;
|
goto out;
|
||||||
ok = 1;
|
ok = 1;
|
||||||
@@ -1107,9 +1176,11 @@ runlifecycle(Daemon *d)
|
|||||||
goto out;
|
goto out;
|
||||||
if(!expectkey(c1, &s1, a, 'x', 0, 0, NULL, "unfocused key"))
|
if(!expectkey(c1, &s1, a, 'x', 0, 0, NULL, "unfocused key"))
|
||||||
goto out;
|
goto out;
|
||||||
if(!cursorcall(c1, &s1, a, 10, 20, 0, 14) ||
|
if(!cursorcall(c1, &s1, a, -10, -20, 0, 14) ||
|
||||||
!nosignal(&s1, "pre-focus cursor") ||
|
!nosignal(&s1, "pre-focus cursor") ||
|
||||||
!emptycall(c1, &s1, a, "FocusIn") || !nosignal(&s1, "FocusIn") ||
|
!emptycall(c1, &s1, a, "FocusIn") || !nosignal(&s1, "FocusIn") ||
|
||||||
|
!capcall(c1, &s1, a, Cappreedit) ||
|
||||||
|
!nosignal(&s1, "A capability") ||
|
||||||
!expectkey(c1, &s1, a, 'x', Relmask, 0, NULL, "physical release"))
|
!expectkey(c1, &s1, a, 'x', Relmask, 0, NULL, "physical release"))
|
||||||
goto out;
|
goto out;
|
||||||
if(!expectkey(c1, &s1, a, 'n', Ctrlmask, 1, "", "select Japanese") ||
|
if(!expectkey(c1, &s1, a, 'n', Ctrlmask, 1, "", "select Japanese") ||
|
||||||
@@ -1117,6 +1188,8 @@ runlifecycle(Daemon *d)
|
|||||||
!expectkey(c1, &s1, a, 'a', 0, 1, "か", "A key a"))
|
!expectkey(c1, &s1, a, 'a', 0, 1, "か", "A key a"))
|
||||||
goto out;
|
goto out;
|
||||||
if(!emptycall(c2, &s2, b, "FocusIn") || !nosignal(&s2, "B FocusIn") ||
|
if(!emptycall(c2, &s2, b, "FocusIn") || !nosignal(&s2, "B FocusIn") ||
|
||||||
|
!capcall(c2, &s2, b, Cappreedit) ||
|
||||||
|
!nosignal(&s2, "inactive B capability") ||
|
||||||
!expectkey(c2, &s2, b, 'n', 0, 1, "ん", "B takeover") ||
|
!expectkey(c2, &s2, b, 'n', 0, 1, "ん", "B takeover") ||
|
||||||
!expectkey(c1, &s1, a, 0xffe1, 0, 0, "", "stale A state") ||
|
!expectkey(c1, &s1, a, 0xffe1, 0, 0, "", "stale A state") ||
|
||||||
!expectkey(c2, &s2, b, 0xffe1, 0, 0, "ん", "active B state"))
|
!expectkey(c2, &s2, b, 0xffe1, 0, 0, "ん", "active B state"))
|
||||||
@@ -1138,6 +1211,8 @@ runlifecycle(Daemon *d)
|
|||||||
goto out;
|
goto out;
|
||||||
if(!createcontext(c1, a2, sizeof a2) ||
|
if(!createcontext(c1, a2, sizeof a2) ||
|
||||||
!emptycall(c1, &s1, a2, "FocusIn") || !nosignal(&s1, "A2 FocusIn") ||
|
!emptycall(c1, &s1, a2, "FocusIn") || !nosignal(&s1, "A2 FocusIn") ||
|
||||||
|
!capcall(c1, &s1, a2, Cappreedit) ||
|
||||||
|
!nosignal(&s1, "A2 capability") ||
|
||||||
!cursorcall(c1, &s1, a2, 120, 130, 0, 18) ||
|
!cursorcall(c1, &s1, a2, 120, 130, 0, 18) ||
|
||||||
!nosignal(&s1, "A2 stale cursor"))
|
!nosignal(&s1, "A2 stale cursor"))
|
||||||
goto out;
|
goto out;
|
||||||
@@ -1150,7 +1225,7 @@ runlifecycle(Daemon *d)
|
|||||||
!expectkey(c2, &s2, b, 'k', 0, 1, "k", "reset owner key k") ||
|
!expectkey(c2, &s2, b, 'k', 0, 1, "k", "reset owner key k") ||
|
||||||
!expectkey(c2, &s2, b, 'a', 0, 1, "か", "reset owner key a"))
|
!expectkey(c2, &s2, b, 'a', 0, 1, "か", "reset owner key a"))
|
||||||
goto out;
|
goto out;
|
||||||
if(!keycall(c2, &s2, b, 0xff0d, 0, &eaten) || !eaten ||
|
if(!keycall(c2, &s2, b, '0', 0, &eaten) || !eaten ||
|
||||||
!committed(&s2, b, "か", "active commit"))
|
!committed(&s2, b, "か", "active commit"))
|
||||||
goto out;
|
goto out;
|
||||||
if(!expectkey(c2, &s2, b, 'k', 0, 1, "k", "pre-FocusOut key") ||
|
if(!expectkey(c2, &s2, b, 'k', 0, 1, "k", "pre-FocusOut key") ||
|
||||||
@@ -1173,6 +1248,8 @@ runlifecycle(Daemon *d)
|
|||||||
goto out;
|
goto out;
|
||||||
if(!emptycall(c2, &s2, active, "FocusIn") ||
|
if(!emptycall(c2, &s2, active, "FocusIn") ||
|
||||||
!nosignal(&s2, "capacity owner FocusIn") ||
|
!nosignal(&s2, "capacity owner FocusIn") ||
|
||||||
|
!capcall(c2, &s2, active, Cappreedit) ||
|
||||||
|
!nosignal(&s2, "capacity owner capability") ||
|
||||||
!expectkey(c2, &s2, active, 'k', 0, 1, "k", "capacity owner key"))
|
!expectkey(c2, &s2, active, 'k', 0, 1, "k", "capacity owner key"))
|
||||||
goto out;
|
goto out;
|
||||||
closebus(&c2, &s2);
|
closebus(&c2, &s2);
|
||||||
@@ -1188,6 +1265,8 @@ runlifecycle(Daemon *d)
|
|||||||
if(!limitscall(c3) ||
|
if(!limitscall(c3) ||
|
||||||
!emptycall(c3, &s3, first, "FocusIn") ||
|
!emptycall(c3, &s3, first, "FocusIn") ||
|
||||||
!nosignal(&s3, "reused context FocusIn") ||
|
!nosignal(&s3, "reused context FocusIn") ||
|
||||||
|
!capcall(c3, &s3, first, Cappreedit) ||
|
||||||
|
!nosignal(&s3, "reused context capability") ||
|
||||||
!expectkey(c3, &s3, first, 'k', 0, 1, "k", "reused context key"))
|
!expectkey(c3, &s3, first, 'k', 0, 1, "k", "reused context key"))
|
||||||
goto out;
|
goto out;
|
||||||
ok = 1;
|
ok = 1;
|
||||||
@@ -1198,6 +1277,106 @@ out:
|
|||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
runpolicy(Daemon *d)
|
||||||
|
{
|
||||||
|
DBusConnection *c1, *c2;
|
||||||
|
Siglog s1, s2;
|
||||||
|
char n1[32], n2[32], a[96], b[96], typed[16];
|
||||||
|
char *query;
|
||||||
|
int eaten, i, ok;
|
||||||
|
|
||||||
|
c1 = c2 = NULL;
|
||||||
|
memset(&s1, 0, sizeof s1);
|
||||||
|
memset(&s2, 0, sizeof s2);
|
||||||
|
ok = 0;
|
||||||
|
c1 = openbus(d->address, &s1);
|
||||||
|
c2 = openbus(d->address, &s2);
|
||||||
|
if(c1 == NULL || c2 == NULL ||
|
||||||
|
!hello(c1, n1, sizeof n1) || !hello(c2, n2, sizeof n2) ||
|
||||||
|
!createcontext(c1, a, sizeof a) || !createcontext(c2, b, sizeof b) ||
|
||||||
|
!emptycall(c1, &s1, a, "FocusIn") || !nosignal(&s1, "policy FocusIn"))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* Capability starts at zero; only advertised bit zero affects routing. */
|
||||||
|
if(!expectkey(c1, &s1, a, 'n', Ctrlmask, 1, NULL,
|
||||||
|
"zero-capability language") ||
|
||||||
|
!expectkey(c1, &s1, a, 'k', 0, 1, NULL, "zero-capability key") ||
|
||||||
|
!capcall(c1, &s1, a, 1<<1) || !nosignal(&s1, "non-preedit cap") ||
|
||||||
|
!capcall(c1, &s1, a, Cappreedit|(1<<1)) ||
|
||||||
|
!preedit(&s1, a, "k", 1, 1, "enable inline") ||
|
||||||
|
!capcall(c1, &s1, a, Cappreedit|(1<<1)) ||
|
||||||
|
!nosignal(&s1, "repeat inline capability") ||
|
||||||
|
!capcall(c1, &s1, a, 1<<1) ||
|
||||||
|
!preedit(&s1, a, "", 0, 0, "disable inline") ||
|
||||||
|
!capcall(c1, &s1, a, 1<<1) ||
|
||||||
|
!nosignal(&s1, "repeat popup capability") ||
|
||||||
|
!expectkey(c1, &s1, a, 'a', 0, 1, NULL, "popup-preedit key") ||
|
||||||
|
!capcall(c1, &s1, a, Cappreedit|(1<<1)) ||
|
||||||
|
!preedit(&s1, a, "か", 1, 1, "restore inline"))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* A focused but inactive context cannot acquire ownership through Keycap. */
|
||||||
|
if(!emptycall(c2, &s2, b, "FocusIn") || !nosignal(&s2, "inactive FocusIn") ||
|
||||||
|
!capcall(c2, &s2, b, Cappreedit) ||
|
||||||
|
!nosignal(&s2, "inactive capability") ||
|
||||||
|
!expectkey(c1, &s1, a, 0xffe1, 0, 0, "か", "owner after inactive cap"))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* Toggling inline display leaves the engine-owned candidate list intact. */
|
||||||
|
if(!emptycall(c1, &s1, a, "Reset") ||
|
||||||
|
!preedit(&s1, a, "", 0, 0, "candidate reset") ||
|
||||||
|
!expectkey(c1, &s1, a, 'e', Ctrlmask, 1, "", "begin emoji search"))
|
||||||
|
goto out;
|
||||||
|
query = "smile";
|
||||||
|
typed[0] = '\0';
|
||||||
|
for(i = 0; query[i] != '\0'; i++){
|
||||||
|
typed[i] = query[i];
|
||||||
|
typed[i+1] = '\0';
|
||||||
|
if(!keycall(c1, &s1, a, query[i], 0, &eaten) || !eaten ||
|
||||||
|
!preedit(&s1, a, typed, i+1, 1, "emoji query"))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if(!capcall(c1, &s1, a, 1<<1) ||
|
||||||
|
!preedit(&s1, a, "", 0, 0, "candidate popup policy") ||
|
||||||
|
!capcall(c1, &s1, a, Cappreedit|(1<<1)) ||
|
||||||
|
!preedit(&s1, a, "smile", 5, 1, "candidate inline policy") ||
|
||||||
|
!keycall(c1, &s1, a, '1', 0, &eaten) || !eaten ||
|
||||||
|
!committed(&s1, a, "😀", "candidate after capability toggle"))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* PRIVATE preserves composition; hidden purposes and hints reset it. */
|
||||||
|
if(!expectkey(c1, &s1, a, 'n', Ctrlmask, 1, "", "private select Japanese") ||
|
||||||
|
!expectkey(c1, &s1, a, 'n', 0, 1, "ん", "private preedit") ||
|
||||||
|
!contentcall(c1, &s1, a, Purposefree, Hintprivate) ||
|
||||||
|
!nosignal(&s1, "PRIVATE property") ||
|
||||||
|
!expectkey(c1, &s1, a, 'a', 0, 1, "な", "PRIVATE key") ||
|
||||||
|
!contentcall(c1, &s1, a, Purposepassword, 0) ||
|
||||||
|
!preedit(&s1, a, "", 0, 0, "PASSWORD transition") ||
|
||||||
|
!expectkey(c1, &s1, a, 'x', 0, 0, NULL, "PASSWORD key") ||
|
||||||
|
!contentcall(c1, &s1, a, Purposefree, 0) ||
|
||||||
|
!nosignal(&s1, "leave PASSWORD") ||
|
||||||
|
!expectkey(c1, &s1, a, 'k', 0, 1, "k", "after PASSWORD") ||
|
||||||
|
!contentcall(c1, &s1, a, Purposepin, 0) ||
|
||||||
|
!preedit(&s1, a, "", 0, 0, "PIN transition") ||
|
||||||
|
!expectkey(c1, &s1, a, 'x', 0, 0, NULL, "PIN key") ||
|
||||||
|
!contentcall(c1, &s1, a, Purposefree, Hintprivate) ||
|
||||||
|
!nosignal(&s1, "leave PIN with PRIVATE") ||
|
||||||
|
!expectkey(c1, &s1, a, 'n', 0, 1, "ん", "PRIVATE resumes") ||
|
||||||
|
!contentcall(c1, &s1, a, Purposefree, Hinthidden) ||
|
||||||
|
!preedit(&s1, a, "", 0, 0, "HIDDEN_TEXT transition") ||
|
||||||
|
!expectkey(c1, &s1, a, 'x', 0, 0, NULL, "HIDDEN_TEXT key") ||
|
||||||
|
!contentcall(c1, &s1, a, Purposefree, 0) ||
|
||||||
|
!nosignal(&s1, "free-form property") ||
|
||||||
|
!expectkey(c1, &s1, a, 'n', 0, 1, "ん", "free-form resumes"))
|
||||||
|
goto out;
|
||||||
|
ok = 1;
|
||||||
|
out:
|
||||||
|
closebus(&c1, &s1);
|
||||||
|
closebus(&c2, &s2);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
@@ -1213,12 +1392,14 @@ main(int argc, char **argv)
|
|||||||
ok = runconnectioncapacity(&daemon);
|
ok = runconnectioncapacity(&daemon);
|
||||||
if(ok)
|
if(ok)
|
||||||
ok = runlifecycle(&daemon);
|
ok = runlifecycle(&daemon);
|
||||||
|
if(ok)
|
||||||
|
ok = runpolicy(&daemon);
|
||||||
if(!ok)
|
if(!ok)
|
||||||
showerrors(&daemon);
|
showerrors(&daemon);
|
||||||
if(!stopdaemon(&daemon))
|
if(!stopdaemon(&daemon))
|
||||||
ok = 0;
|
ok = 0;
|
||||||
if(!ok)
|
if(!ok)
|
||||||
return 1;
|
return 1;
|
||||||
printf("ibus live lifecycle and connection capacity: ok\n");
|
printf("ibus live lifecycle, policy, and connection capacity: ok\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -238,7 +238,8 @@ nexttrace(struct ct *t, Ibusfix *f, int op, Ictx *ctx)
|
|||||||
return req;
|
return req;
|
||||||
CT_EQ_INT(t, op, req.op);
|
CT_EQ_INT(t, op, req.op);
|
||||||
CT_EQ_PTR(t, ctx, req.owner);
|
CT_EQ_PTR(t, ctx, req.owner);
|
||||||
CT_EQ_INT(t, Cclientpreedit, req.cap);
|
if(ctx != nil)
|
||||||
|
CT_EQ_INT(t, ctx->cap & 1 ? Cclientpreedit : 0, req.cap);
|
||||||
CT_EQ_PTR(t, replyc, req.reply);
|
CT_EQ_PTR(t, replyc, req.reply);
|
||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
@@ -282,6 +283,102 @@ contextkey(struct ct *t, Ibusfix *f, Ictx *ctx, u32int sym, u32int state)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ibus_capability_policy(struct ct *t)
|
||||||
|
{
|
||||||
|
Ibusfix f;
|
||||||
|
Ictx *a, *b;
|
||||||
|
Keyres res;
|
||||||
|
|
||||||
|
if(!ibusbegin(t, &f))
|
||||||
|
goto cleanup;
|
||||||
|
a = newcontext(f.c1, "/context/cap-a");
|
||||||
|
b = newcontext(f.c2, "/context/cap-b");
|
||||||
|
if(!CT_CHECK(t, a != nil && b != nil))
|
||||||
|
goto cleanup;
|
||||||
|
CT_EQ_INT(t, 0, a->cap);
|
||||||
|
a->focused = 1;
|
||||||
|
res = contextkey(t, &f, a, 'n', Testctrlmask);
|
||||||
|
CT_CHECK(t, res.eaten);
|
||||||
|
res = contextkey(t, &f, a, 'k', 0);
|
||||||
|
checkpreedit(t, "k", &res);
|
||||||
|
CT_EQ_PTR(t, a, testengineowner());
|
||||||
|
|
||||||
|
a->cap = Cclientpreedit;
|
||||||
|
memset(&res, 0, sizeof res);
|
||||||
|
sendrequest(a, Keycap, 0, 0, &res);
|
||||||
|
nexttrace(t, &f, Keycap, a);
|
||||||
|
CT_CHECK(t, res.eaten);
|
||||||
|
checkpreedit(t, "k", &res);
|
||||||
|
|
||||||
|
b->focused = 1;
|
||||||
|
b->cap = Cclientpreedit;
|
||||||
|
memset(&res, 0, sizeof res);
|
||||||
|
sendrequest(b, Keycap, 0, 0, &res);
|
||||||
|
nexttrace(t, &f, Keycap, b);
|
||||||
|
CT_CHECK(t, !res.eaten);
|
||||||
|
CT_EQ_PTR(t, a, testengineowner());
|
||||||
|
checkenginepreedit(t, "k");
|
||||||
|
|
||||||
|
a->cap = 0;
|
||||||
|
memset(&res, 0, sizeof res);
|
||||||
|
sendrequest(a, Keycap, 0, 0, &res);
|
||||||
|
nexttrace(t, &f, Keycap, a);
|
||||||
|
CT_CHECK(t, res.eaten);
|
||||||
|
checkpreedit(t, "k", &res);
|
||||||
|
cleanup:
|
||||||
|
ibusend(&f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ibus_private_input_policy(struct ct *t)
|
||||||
|
{
|
||||||
|
static const struct { u32int purpose, hints; int want; } cases[] = {
|
||||||
|
{ 0, 0, 0 },
|
||||||
|
{ Ibuspurposepassword, 0, 1 },
|
||||||
|
{ Ibuspurposepin, 0, 1 },
|
||||||
|
{ 0, 1<<11, 0 },
|
||||||
|
{ 0, Ibushinthidden, 1 },
|
||||||
|
{ 37, 1<<20, 0 },
|
||||||
|
};
|
||||||
|
Ibusfix f;
|
||||||
|
Ictx *ctx;
|
||||||
|
Keyres res;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if(!ibusbegin(t, &f))
|
||||||
|
goto cleanup;
|
||||||
|
ctx = newcontext(f.c1, "/context/private");
|
||||||
|
if(!CT_CHECK(t, ctx != nil))
|
||||||
|
goto cleanup;
|
||||||
|
for(i = 0; i < nelem(cases); i++){
|
||||||
|
ctx->purpose = cases[i].purpose;
|
||||||
|
ctx->hints = cases[i].hints;
|
||||||
|
CT_EQ_INT(t, cases[i].want, hidden(ctx));
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->focused = 1;
|
||||||
|
ctx->cap = Cclientpreedit;
|
||||||
|
ctx->purpose = 0;
|
||||||
|
ctx->hints = 0;
|
||||||
|
contextkey(t, &f, ctx, 'n', Testctrlmask);
|
||||||
|
res = contextkey(t, &f, ctx, 'k', 0);
|
||||||
|
checkpreedit(t, "k", &res);
|
||||||
|
ctx->purpose = Ibuspurposepassword;
|
||||||
|
memset(&res, 0, sizeof res);
|
||||||
|
CT_CHECK(t, !processkey(ctx, 'x', 0, &res));
|
||||||
|
CT_CHECK(t, !res.eaten);
|
||||||
|
notrace(t, &f);
|
||||||
|
checkenginepreedit(t, "k");
|
||||||
|
|
||||||
|
ctx->purpose = 0;
|
||||||
|
ctx->hints = 1<<11;
|
||||||
|
res = contextkey(t, &f, ctx, 'a', 0);
|
||||||
|
checkpreedit(t, "か", &res);
|
||||||
|
cleanup:
|
||||||
|
ibusend(&f);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ibus_context_lifecycle(struct ct *t)
|
ibus_context_lifecycle(struct ct *t)
|
||||||
{
|
{
|
||||||
@@ -307,7 +404,7 @@ ibus_context_lifecycle(struct ct *t)
|
|||||||
notrace(t, &f);
|
notrace(t, &f);
|
||||||
CT_EQ_PTR(t, nil, testengineowner());
|
CT_EQ_PTR(t, nil, testengineowner());
|
||||||
|
|
||||||
setcursor(a, 10, 20, 14);
|
setcursor(a, -10, -20, 14);
|
||||||
notrace(t, &f);
|
notrace(t, &f);
|
||||||
CT_CHECK(t, a->caret.valid);
|
CT_CHECK(t, a->caret.valid);
|
||||||
a->focused = 1;
|
a->focused = 1;
|
||||||
@@ -322,14 +419,14 @@ ibus_context_lifecycle(struct ct *t)
|
|||||||
req = nexttrace(t, &f, Keypress, a);
|
req = nexttrace(t, &f, Keypress, a);
|
||||||
CT_CHECK(t, !res.eaten);
|
CT_CHECK(t, !res.eaten);
|
||||||
CT_CHECK(t, req.caret.valid);
|
CT_CHECK(t, req.caret.valid);
|
||||||
CT_EQ_INT(t, 10, req.caret.x);
|
CT_EQ_INT(t, -10, req.caret.x);
|
||||||
CT_EQ_INT(t, 20, req.caret.y);
|
CT_EQ_INT(t, -20, req.caret.y);
|
||||||
CT_EQ_INT(t, 14, req.caret.h);
|
CT_EQ_INT(t, 14, req.caret.h);
|
||||||
CT_EQ_PTR(t, a, testengineowner());
|
CT_EQ_PTR(t, a, testengineowner());
|
||||||
testenginecaret(&at);
|
testenginecaret(&at);
|
||||||
CT_CHECK(t, at.valid);
|
CT_CHECK(t, at.valid);
|
||||||
CT_EQ_INT(t, 10, at.x);
|
CT_EQ_INT(t, -10, at.x);
|
||||||
CT_EQ_INT(t, 20, at.y);
|
CT_EQ_INT(t, -20, at.y);
|
||||||
res = contextkey(t, &f, a, 'n', Testctrlmask);
|
res = contextkey(t, &f, a, 'n', Testctrlmask);
|
||||||
CT_CHECK(t, res.eaten);
|
CT_CHECK(t, res.eaten);
|
||||||
contextkey(t, &f, a, 'k', 0);
|
contextkey(t, &f, a, 'k', 0);
|
||||||
|
|||||||
@@ -82,6 +82,8 @@ void server_extension_stream(struct ct*);
|
|||||||
void server_rejects_unknown_extension(struct ct*);
|
void server_rejects_unknown_extension(struct ct*);
|
||||||
void ibus_machine_id_fallback(struct ct*);
|
void ibus_machine_id_fallback(struct ct*);
|
||||||
void ibus_startup_requires_ownership(struct ct*);
|
void ibus_startup_requires_ownership(struct ct*);
|
||||||
|
void ibus_capability_policy(struct ct*);
|
||||||
|
void ibus_private_input_policy(struct ct*);
|
||||||
void ibus_context_lifecycle(struct ct*);
|
void ibus_context_lifecycle(struct ct*);
|
||||||
void ibus_active_release_lifecycle(struct ct*);
|
void ibus_active_release_lifecycle(struct ct*);
|
||||||
void xim_adapter_key_contract(struct ct*);
|
void xim_adapter_key_contract(struct ct*);
|
||||||
|
|||||||
@@ -136,6 +136,8 @@ static const struct ct_test tests[] = {
|
|||||||
{ "server/rejects-unknown-extension", server_rejects_unknown_extension },
|
{ "server/rejects-unknown-extension", server_rejects_unknown_extension },
|
||||||
{ "ibus/machine-id-fallback", ibus_machine_id_fallback },
|
{ "ibus/machine-id-fallback", ibus_machine_id_fallback },
|
||||||
{ "ibus/startup-requires-ownership", ibus_startup_requires_ownership },
|
{ "ibus/startup-requires-ownership", ibus_startup_requires_ownership },
|
||||||
|
{ "ibus/capability-policy", ibus_capability_policy },
|
||||||
|
{ "ibus/private-input-policy", ibus_private_input_policy },
|
||||||
{ "ibus/context-lifecycle", ibus_context_lifecycle },
|
{ "ibus/context-lifecycle", ibus_context_lifecycle },
|
||||||
{ "ibus/active-release-lifecycle", ibus_active_release_lifecycle },
|
{ "ibus/active-release-lifecycle", ibus_active_release_lifecycle },
|
||||||
{ "xim/adapter-key-contract", xim_adapter_key_contract },
|
{ "xim/adapter-key-contract", xim_adapter_key_contract },
|
||||||
|
|||||||
Reference in New Issue
Block a user