uint32_t KeyboardEngine::processCompose(uint32_t keyval, uint32_t state) { // FIXME, should we check if state is 0? FCITX_UNUSED(state); if (!m_xkbComposeState) { return 0; } enum xkb_compose_feed_result result = xkb_compose_state_feed(m_xkbComposeState.get(), keyval); if (result == XKB_COMPOSE_FEED_IGNORED) { return 0; } enum xkb_compose_status status = xkb_compose_state_get_status(m_xkbComposeState.get()); if (status == XKB_COMPOSE_NOTHING) { return 0; } else if (status == XKB_COMPOSE_COMPOSED) { char buffer[FCITX_UTF8_MAX_LENGTH + 1] = {'\0', '\0', '\0', '\0', '\0', '\0', '\0'}; int length = xkb_compose_state_get_utf8(m_xkbComposeState.get(), buffer, sizeof(buffer)); xkb_compose_state_reset(m_xkbComposeState.get()); if (length == 0) { return INVALID_COMPOSE_RESULT; } uint32_t c = 0; fcitx_utf8_get_char(buffer, &c); return c; } else if (status == XKB_COMPOSE_CANCELLED) { xkb_compose_state_reset(m_xkbComposeState.get()); } return INVALID_COMPOSE_RESULT; }
static void handleKeyEvent(WaylandDisplay::SeatData& seatData, uint32_t key, uint32_t state, uint32_t time) { auto& xkb = seatData.xkb; uint32_t keysym = xkb_state_key_get_one_sym(xkb.state, key); uint32_t unicode = xkb_state_key_get_utf32(xkb.state, key); if (state == WL_KEYBOARD_KEY_STATE_PRESSED && xkb_compose_state_feed(xkb.composeState, keysym) == XKB_COMPOSE_FEED_ACCEPTED && xkb_compose_state_get_status(xkb.composeState) == XKB_COMPOSE_COMPOSED) { keysym = xkb_compose_state_get_one_sym(xkb.composeState); unicode = xkb_keysym_to_utf32(keysym); } if (seatData.keyboard.target.first) seatData.keyboard.target.second->handleKeyboardEvent({ time, keysym, unicode, !!state, xkb.modifiers }); }
static xkb_keysym_t composeSymbol(xkb_keysym_t sym) { if (sym == XKB_KEY_NoSymbol || !_glfw.wl.xkb.composeState) return sym; if (xkb_compose_state_feed(_glfw.wl.xkb.composeState, sym) != XKB_COMPOSE_FEED_ACCEPTED) return sym; switch (xkb_compose_state_get_status(_glfw.wl.xkb.composeState)) { case XKB_COMPOSE_COMPOSED: return xkb_compose_state_get_one_sym(_glfw.wl.xkb.composeState); case XKB_COMPOSE_COMPOSING: case XKB_COMPOSE_CANCELLED: return XKB_KEY_NoSymbol; case XKB_COMPOSE_NOTHING: default: return sym; } }
static bool handle_key_press(Keyboard *keyboard, xkb_keycode_t keycode, char *password, char **password_cursor) { xkb_keysym_t keysym = xkb_state_key_get_one_sym(keyboard->state, keycode); enum xkb_compose_status status = XKB_COMPOSE_NOTHING; if (xkb_compose_state_feed(keyboard->compose_state, keysym) == XKB_COMPOSE_FEED_ACCEPTED) { status = xkb_compose_state_get_status(keyboard->compose_state); if (status == XKB_COMPOSE_COMPOSED) { keysym = xkb_compose_state_get_one_sym(keyboard->compose_state); } else if (status == XKB_COMPOSE_COMPOSING || status == XKB_COMPOSE_CANCELLED) { return false; } } if (keysym == XKB_KEY_Return) { return true; } else if (keysym == XKB_KEY_Escape) { running = false; return false; } else if (keysym == XKB_KEY_BackSpace) { if (*password_cursor != &password[0]) { while ((*(--(*password_cursor)) & 0xc0) == 0x80); **password_cursor = '\0'; } return false; } char buffer[16] = { '\0' }; int len; if (status == XKB_COMPOSE_COMPOSED) { len = xkb_compose_state_get_utf8(keyboard->compose_state, buffer, sizeof(buffer)); } else { len = xkb_state_key_get_utf8(keyboard->state, keycode, buffer, sizeof(buffer)); } if (len < 1) { return false; } memcpy(*password_cursor, buffer, len + 1); *password_cursor += len; return false; }
/* * Handle key presses. Fixes state, then looks up the key symbol for the * given keycode, then looks up the key symbol (as UCS-2), converts it to * UTF-8 and stores it in the password array. * */ static void handle_key_press(xcb_key_press_event_t *event) { xkb_keysym_t ksym; char buffer[128]; int n; bool ctrl; bool composed = false; ksym = xkb_state_key_get_one_sym(xkb_state, event->detail); ctrl = xkb_state_mod_name_is_active(xkb_state, XKB_MOD_NAME_CTRL, XKB_STATE_MODS_DEPRESSED); /* The buffer will be null-terminated, so n >= 2 for 1 actual character. */ memset(buffer, '\0', sizeof(buffer)); if (xkb_compose_state && xkb_compose_state_feed(xkb_compose_state, ksym) == XKB_COMPOSE_FEED_ACCEPTED) { switch (xkb_compose_state_get_status(xkb_compose_state)) { case XKB_COMPOSE_NOTHING: break; case XKB_COMPOSE_COMPOSING: return; case XKB_COMPOSE_COMPOSED: /* xkb_compose_state_get_utf8 doesn't include the terminating byte in the return value * as xkb_keysym_to_utf8 does. Adding one makes the variable n consistent. */ n = xkb_compose_state_get_utf8(xkb_compose_state, buffer, sizeof(buffer)) + 1; ksym = xkb_compose_state_get_one_sym(xkb_compose_state); composed = true; break; case XKB_COMPOSE_CANCELLED: xkb_compose_state_reset(xkb_compose_state); return; } } if (!composed) { n = xkb_keysym_to_utf8(ksym, buffer, sizeof(buffer)); } switch (ksym) { case XKB_KEY_Return: case XKB_KEY_KP_Enter: case XKB_KEY_XF86ScreenSaver: if (pam_state == STATE_PAM_WRONG) return; if (skip_without_validation()) { clear_input(); return; } password[input_position] = '\0'; unlock_state = STATE_KEY_PRESSED; redraw_screen(); input_done(); skip_repeated_empty_password = true; return; default: skip_repeated_empty_password = false; } switch (ksym) { case XKB_KEY_u: if (ctrl) { DEBUG("C-u pressed\n"); clear_input(); return; } break; case XKB_KEY_Escape: clear_input(); return; case XKB_KEY_BackSpace: if (input_position == 0) return; /* decrement input_position to point to the previous glyph */ u8_dec(password, &input_position); password[input_position] = '\0'; /* Hide the unlock indicator after a bit if the password buffer is * empty. */ START_TIMER(clear_indicator_timeout, 1.0, clear_indicator_cb); unlock_state = STATE_BACKSPACE_ACTIVE; redraw_screen(); unlock_state = STATE_KEY_PRESSED; return; } if ((input_position + 8) >= sizeof(password)) return; #if 0 /* FIXME: handle all of these? */ printf("is_keypad_key = %d\n", xcb_is_keypad_key(sym)); printf("is_private_keypad_key = %d\n", xcb_is_private_keypad_key(sym)); printf("xcb_is_cursor_key = %d\n", xcb_is_cursor_key(sym)); printf("xcb_is_pf_key = %d\n", xcb_is_pf_key(sym)); printf("xcb_is_function_key = %d\n", xcb_is_function_key(sym)); printf("xcb_is_misc_function_key = %d\n", xcb_is_misc_function_key(sym)); printf("xcb_is_modifier_key = %d\n", xcb_is_modifier_key(sym)); #endif if (n < 2) return; /* store it in the password array as UTF-8 */ memcpy(password + input_position, buffer, n - 1); input_position += n - 1; DEBUG("current password = %.*s\n", input_position, password); if (unlock_indicator) { unlock_state = STATE_KEY_ACTIVE; redraw_screen(); unlock_state = STATE_KEY_PRESSED; struct ev_timer *timeout = NULL; START_TIMER(timeout, TSTAMP_N_SECS(0.25), redraw_timeout); STOP_TIMER(clear_indicator_timeout); } START_TIMER(discard_passwd_timeout, TSTAMP_N_MINS(3), discard_passwd_cb); }
static int keyboard_feed_evdev(idev_keyboard *k, idev_data *data) { struct input_event *ev = &data->evdev.event; enum xkb_state_component compch; enum xkb_compose_status cstatus; const xkb_keysym_t *keysyms; idev_device *d = &k->device; int num, r; if (ev->type != EV_KEY || ev->value > KBDKEY_DOWN) return 0; /* TODO: We should audit xkb-actions, whether they need @resync as * flag. Most actions should just be executed, however, there might * be actions that depend on modifier-orders. Those should be * suppressed. */ num = xkb_state_key_get_syms(k->xkb_state, ev->code + KBDXKB_SHIFT, &keysyms); compch = xkb_state_update_key(k->xkb_state, ev->code + KBDXKB_SHIFT, ev->value); if (compch & XKB_STATE_LEDS) { /* TODO: update LEDs */ } if (num < 0) { r = num; goto error; } if (k->xkb_compose && ev->value == KBDKEY_DOWN) { if (num == 1 && !data->resync) { xkb_compose_state_feed(k->xkb_compose, keysyms[0]); cstatus = xkb_compose_state_get_status(k->xkb_compose); } else { cstatus = XKB_COMPOSE_CANCELLED; } switch (cstatus) { case XKB_COMPOSE_NOTHING: /* keep produced keysyms and forward unchanged */ break; case XKB_COMPOSE_COMPOSING: /* consumed by compose-state, drop keysym */ keysyms = NULL; num = 0; break; case XKB_COMPOSE_COMPOSED: /* compose-state produced sth, replace keysym */ num = keyboard_read_compose(k, &keysyms); xkb_compose_state_reset(k->xkb_compose); break; case XKB_COMPOSE_CANCELLED: /* canceled compose, reset, forward cancellation sym */ xkb_compose_state_reset(k->xkb_compose); break; } } else if (k->xkb_compose && num == 1 && keysyms[0] == XKB_KEY_Multi_key && !data->resync && ev->value == KBDKEY_UP) { /* Reset compose state on Multi-Key UP events. This effectively * requires you to hold the key during the whole sequence. I * think it's pretty handy to avoid accidental * Compose-sequences, but this may break Compose for disabled * people. We really need to make this opional! (TODO) */ xkb_compose_state_reset(k->xkb_compose); } if (ev->value == KBDKEY_UP) { /* never produce keysyms for UP */ keysyms = NULL; num = 0; } r = keyboard_fill(k, &k->evdata, data->resync, ev->code, ev->value, num, keysyms); if (r < 0) goto error; keyboard_repeat(k); return keyboard_raise_data(k, &k->evdata); error: log_debug_errno(r, "idev-keyboard: %s/%s: cannot handle event: %m", d->session->name, d->name); k->repeating = false; keyboard_arm(k, 0); return 0; }