return mods;
}
+static inline uint32_t shl_get_ascii(struct xkb_state *state, uint32_t keycode,
+ const uint32_t *keysyms,
+ unsigned int num_keysyms)
+{
+ struct xkb_keymap *keymap;
+ xkb_layout_index_t num_layouts;
+ xkb_layout_index_t layout;
+ xkb_level_index_t level;
+ const xkb_keysym_t *syms;
+ int num_syms;
+
+ if (num_keysyms == 1 && keysyms[0] < 128)
+ return keysyms[0];
+
+ keymap = xkb_state_get_map(state);
+ num_layouts = xkb_keymap_num_layouts_for_key(keymap, keycode);
+
+ for (layout = 0; layout < num_layouts; layout++) {
+ level = xkb_state_key_get_level(state, keycode, layout);
+ num_syms = xkb_keymap_key_get_syms_by_level(keymap, keycode,
+ layout, level, &syms);
+ if (num_syms != 1)
+ continue;
+
+ if (syms[0] < 128)
+ return syms[0];
+ }
+
+ return XKB_KEY_NoSymbol;
+}
+
#endif /* SHL_MISC_H */
if (ev->num_syms > 1)
return;
- if (tsm_vte_handle_keyboard(term->vte, ev->keysyms[0], ev->mods,
- ev->codepoints[0])) {
+ if (tsm_vte_handle_keyboard(term->vte, ev->keysyms[0], ev->ascii,
+ ev->mods, ev->codepoints[0])) {
tsm_screen_sb_reset(term->console);
schedule_redraw(term);
ev->handled = true;
}
bool tsm_vte_handle_keyboard(struct tsm_vte *vte, uint32_t keysym,
- unsigned int mods, uint32_t unicode)
+ uint32_t ascii, unsigned int mods,
+ uint32_t unicode)
{
char val, u8[4];
size_t len;
+ uint32_t sym;
/* MOD1 (mostly labeled 'Alt') prepends an escape character to every
* input that is sent by a key.
if (mods & TSM_ALT_MASK)
vte->flags |= FLAG_PREPEND_ESCAPE;
+ /* A user might actually use multiple layouts for keyboard input. The
+ * @keysym variable contains the actual keysym that the user used. But
+ * if this keysym is not in the ascii range, the input handler does
+ * check all other layouts that the user specified whether one of them
+ * maps the key to some ASCII keysym and provides this via @ascii.
+ * We always use the real keysym except when handling CTRL+<XY>
+ * shortcuts we use the ascii keysym. This is for compatibility to xterm
+ * et. al. so ctrl+c always works regardless of the currently active
+ * keyboard layout.
+ * But if no ascii-sym is found, we still use the real keysym. */
+ sym = ascii;
+ if (sym == XKB_KEY_NoSymbol)
+ sym = keysym;
+
if (mods & TSM_CONTROL_MASK) {
- switch (keysym) {
+ switch (sym) {
case XKB_KEY_2:
case XKB_KEY_space:
vte_write(vte, "\x00", 1);
void tsm_vte_hard_reset(struct tsm_vte *vte);
void tsm_vte_input(struct tsm_vte *vte, const char *u8, size_t len);
bool tsm_vte_handle_keyboard(struct tsm_vte *vte, uint32_t keysym,
- unsigned int mods, uint32_t unicode);
+ uint32_t ascii, unsigned int mods,
+ uint32_t unicode);
#endif /* TSM_VTE_H */
struct uterm_input_event {
bool handled; /* user-controlled, default is false */
uint16_t keycode; /* linux keycode - KEY_* - linux/input.h */
+ uint32_t ascii; /* ascii keysym for @keycode */
unsigned int mods; /* active modifiers - uterm_modifier mask */
unsigned int num_syms; /* number of keysyms */
dev->event.handled = false;
dev->event.keycode = code;
+ dev->event.ascii = shl_get_ascii(state, code, keysyms, num_keysyms);
dev->event.mods = shl_get_xkb_mods(state);
dev->event.num_syms = num_keysyms;
memcpy(dev->event.keysyms, keysyms, sizeof(uint32_t) * num_keysyms);
};
static bool widget_key(struct wlt_widget *widget, unsigned int mask,
- uint32_t sym, uint32_t state, bool handled, void *data)
+ uint32_t sym, uint32_t ascii, uint32_t state,
+ bool handled, void *data)
{
struct wlt_terminal *term = data;
uint32_t ucs4;
return true;
}
- if (tsm_vte_handle_keyboard(term->vte, sym, mask, ucs4)) {
+ if (tsm_vte_handle_keyboard(term->vte, sym, ascii, mask, ucs4)) {
tsm_screen_sb_reset(term->scr);
wlt_window_schedule_redraw(term->wnd);
return true;
}
static bool widget_key(struct wlt_widget *widget, unsigned int mask,
- uint32_t sym, uint32_t state, bool handled, void *data)
+ uint32_t sym, uint32_t ascii, uint32_t state,
+ bool handled, void *data)
{
struct wlt_theme *theme = data;
struct wlt_window *keyboard_focus;
struct ev_timer *repeat_timer;
uint32_t repeat_sym;
+ uint32_t repeat_ascii;
struct wl_data_device_manager *w_manager;
struct wl_data_device *w_data_dev;
{
struct wlt_display *disp = data;
struct wlt_window *wnd = disp->keyboard_focus;
- uint32_t code, num_syms;
+ uint32_t code, num_syms, ascii;
unsigned int mask;
enum wl_keyboard_key_state state = state_w;
const xkb_keysym_t *syms;
mask = shl_get_xkb_mods(disp->xkb_state);
num_syms = xkb_key_get_syms(disp->xkb_state, code, &syms);
+ ascii = shl_get_ascii(disp->xkb_state, code, syms, num_syms);
sym = XKB_KEY_NoSymbol;
if (num_syms == 1)
sym = syms[0];
shl_dlist_for_each(iter, &wnd->widget_list) {
widget = shl_dlist_entry(iter, struct wlt_widget, list);
if (widget->keyboard_cb) {
- if (widget->keyboard_cb(widget, mask, sym, state,
+ if (widget->keyboard_cb(widget, mask, sym, ascii, state,
handled, widget->data))
handled = true;
}
ev_timer_update(disp->repeat_timer, NULL);
} else if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
disp->repeat_sym = sym;
+ disp->repeat_ascii = ascii;
spec.it_interval.tv_sec = 0;
spec.it_interval.tv_nsec = wlt_conf.xkb_repeat_rate * 1000000;
spec.it_value.tv_sec = 0;
widget = shl_dlist_entry(iter, struct wlt_widget, list);
if (widget->keyboard_cb) {
if (widget->keyboard_cb(widget, mask, disp->repeat_sym,
+ disp->repeat_ascii,
WL_KEYBOARD_KEY_STATE_PRESSED,
handled, widget->data))
handled = true;
typedef bool (*wlt_widget_keyboard_cb) (struct wlt_widget *widget,
unsigned int mods,
uint32_t key,
+ uint32_t ascii,
uint32_t state,
bool handled,
void *data);