xim: dead keys and Compose
Xlib does no local composing for a client on an input method server, so under XIM a dead key was forwarded as a bare keysym and vanished. The XIM frontend now feeds keys through xkbcommon's Compose table for the daemon's locale and commits the composed character itself.
This commit is contained in:
54
xim/xim.c
54
xim/xim.c
@@ -2,10 +2,12 @@
|
|||||||
#include "fn.h"
|
#include "fn.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <locale.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
#include <xcb/xkb.h>
|
#include <xcb/xkb.h>
|
||||||
#include <xkbcommon/xkbcommon.h>
|
#include <xkbcommon/xkbcommon.h>
|
||||||
|
#include <xkbcommon/xkbcommon-compose.h>
|
||||||
#include <xkbcommon/xkbcommon-x11.h>
|
#include <xkbcommon/xkbcommon-x11.h>
|
||||||
#include <xcb-imdkit/imdkit.h>
|
#include <xcb-imdkit/imdkit.h>
|
||||||
#include <xcb-imdkit/encoding.h>
|
#include <xcb-imdkit/encoding.h>
|
||||||
@@ -38,6 +40,7 @@ enum
|
|||||||
static xcb_connection_t *conn;
|
static xcb_connection_t *conn;
|
||||||
static xcb_im_t *xim;
|
static xcb_im_t *xim;
|
||||||
static struct xkb_state *kstate;
|
static struct xkb_state *kstate;
|
||||||
|
static struct xkb_compose_state *compose;
|
||||||
static uint8_t xkbevent;
|
static uint8_t xkbevent;
|
||||||
static xcb_window_t rootwin;
|
static xcb_window_t rootwin;
|
||||||
static Ic *ics;
|
static Ic *ics;
|
||||||
@@ -96,6 +99,26 @@ out:
|
|||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Dead keys and Compose: Xlib leaves them to the input method server. */
|
||||||
|
static void
|
||||||
|
cinit(void)
|
||||||
|
{
|
||||||
|
struct xkb_context *context;
|
||||||
|
struct xkb_compose_table *table;
|
||||||
|
char *locale;
|
||||||
|
|
||||||
|
locale = setlocale(LC_CTYPE, "");
|
||||||
|
context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
||||||
|
if(context == nil)
|
||||||
|
return;
|
||||||
|
table = xkb_compose_table_new_from_locale(context,
|
||||||
|
locale != nil ? locale : "C", XKB_COMPOSE_COMPILE_NO_FLAGS);
|
||||||
|
if(table != nil)
|
||||||
|
compose = xkb_compose_state_new(table, XKB_COMPOSE_STATE_NO_FLAGS);
|
||||||
|
xkb_compose_table_unref(table);
|
||||||
|
xkb_context_unref(context);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
kwatch(void)
|
kwatch(void)
|
||||||
{
|
{
|
||||||
@@ -361,11 +384,25 @@ kpress(Ic *state, xcb_key_press_event_t *ev)
|
|||||||
{
|
{
|
||||||
Keyres res;
|
Keyres res;
|
||||||
char buf[Maxutf];
|
char buf[Maxutf];
|
||||||
u32int key;
|
u32int key, sym;
|
||||||
int n, wasvalid;
|
int composed, n, wasvalid;
|
||||||
|
|
||||||
key = keymaplookup(kstate, ev->detail, ev->state);
|
sym = keymaplookup(kstate, ev->detail, ev->state);
|
||||||
key = ipckeysym(key, xkb_keysym_to_utf32(key));
|
composed = 0;
|
||||||
|
if(compose != nil &&
|
||||||
|
xkb_compose_state_feed(compose, sym) == XKB_COMPOSE_FEED_ACCEPTED)
|
||||||
|
switch(xkb_compose_state_get_status(compose)){
|
||||||
|
case XKB_COMPOSE_COMPOSING:
|
||||||
|
case XKB_COMPOSE_CANCELLED:
|
||||||
|
return;
|
||||||
|
case XKB_COMPOSE_COMPOSED:
|
||||||
|
sym = xkb_compose_state_get_one_sym(compose);
|
||||||
|
composed = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
key = ipckeysym(sym, xkb_keysym_to_utf32(sym));
|
||||||
if(keymeaningful(key)){
|
if(keymeaningful(key)){
|
||||||
wasvalid = state->caret.valid;
|
wasvalid = state->caret.valid;
|
||||||
place(state);
|
place(state);
|
||||||
@@ -376,7 +413,13 @@ kpress(Ic *state, xcb_key_press_event_t *ev)
|
|||||||
n = stoutf(&res.commit, buf, sizeof buf);
|
n = stoutf(&res.commit, buf, sizeof buf);
|
||||||
commit(state, buf, n);
|
commit(state, buf, n);
|
||||||
updatepreedit(state, &res.preedit);
|
updatepreedit(state, &res.preedit);
|
||||||
if(!res.eaten)
|
if(res.eaten)
|
||||||
|
;
|
||||||
|
else if(composed){
|
||||||
|
/* The event holds the last key of the sequence, not its result. */
|
||||||
|
n = xkb_keysym_to_utf8(sym, buf, sizeof buf);
|
||||||
|
commit(state, buf, max(n - 1, 0));
|
||||||
|
}else
|
||||||
xcb_im_forward_event(xim, state->xic, ev);
|
xcb_im_forward_event(xim, state->xic, ev);
|
||||||
xcb_flush(conn);
|
xcb_flush(conn);
|
||||||
}
|
}
|
||||||
@@ -498,6 +541,7 @@ ximinit(void)
|
|||||||
ximlog("cannot read keyboard mapping");
|
ximlog("cannot read keyboard mapping");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
cinit();
|
||||||
kwatch();
|
kwatch();
|
||||||
win = xcb_generate_id(conn);
|
win = xcb_generate_id(conn);
|
||||||
xcb_create_window(conn, XCB_COPY_FROM_PARENT, win, screen->root,
|
xcb_create_window(conn, XCB_COPY_FROM_PARENT, win, screen->root,
|
||||||
|
|||||||
Reference in New Issue
Block a user