tsm: vte: use ASCII keysyms for ctrl+<XY> shortcuts
If a user has multiple active XKB layouts but only one of them has ASCII keysyms on the base level, then ctrl+<XY> might actually never work, because these keys aren't available in the current layout. This patch tries to find a layout of the user that actually _has_ ascii keysyms on the base level and passes this information along with the normal keysym information. The TSM layer can now use this ascii keysym instead of the normal unicode keysym to handle ctrl+<XY> shortcuts. This is the same way xterm et. al. handle this, so it seems to be a good idea to do this in TSM, too. Reported (and mainly written) by Ran Benita. Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
This commit is contained in:
parent
0a03785ffc
commit
33ebc01441
@ -95,4 +95,35 @@ static inline unsigned int shl_get_xkb_mods(struct xkb_state *state)
|
||||
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 */
|
||||
|
@ -393,8 +393,8 @@ static void input_event(struct uterm_input *input,
|
||||
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;
|
||||
|
@ -2152,10 +2152,12 @@ 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)
|
||||
{
|
||||
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.
|
||||
@ -2167,8 +2169,22 @@ bool tsm_vte_handle_keyboard(struct tsm_vte *vte, uint32_t keysym,
|
||||
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);
|
||||
|
@ -79,6 +79,7 @@ void tsm_vte_reset(struct tsm_vte *vte);
|
||||
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 */
|
||||
|
@ -271,6 +271,7 @@ enum uterm_input_modifier {
|
||||
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 */
|
||||
|
@ -164,6 +164,7 @@ int uxkb_dev_process(struct uterm_input_dev *dev,
|
||||
|
||||
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);
|
||||
|
@ -398,7 +398,8 @@ static const struct wl_data_source_listener copy_listener = {
|
||||
};
|
||||
|
||||
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;
|
||||
@ -536,7 +537,7 @@ static bool widget_key(struct wlt_widget *widget, unsigned int mask,
|
||||
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;
|
||||
|
@ -531,7 +531,8 @@ static void widget_pointer_button(struct wlt_widget *widget,
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
@ -101,6 +101,7 @@ struct wlt_display {
|
||||
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;
|
||||
@ -639,7 +640,7 @@ static void keyboard_key(void *data, struct wl_keyboard *keyboard,
|
||||
{
|
||||
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;
|
||||
@ -659,6 +660,7 @@ static void keyboard_key(void *data, struct wl_keyboard *keyboard,
|
||||
|
||||
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];
|
||||
@ -667,7 +669,7 @@ static void keyboard_key(void *data, struct wl_keyboard *keyboard,
|
||||
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;
|
||||
}
|
||||
@ -678,6 +680,7 @@ static void keyboard_key(void *data, struct wl_keyboard *keyboard,
|
||||
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;
|
||||
@ -704,6 +707,7 @@ static void repeat_event(struct ev_timer *timer, uint64_t num, void *data)
|
||||
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;
|
||||
|
@ -115,6 +115,7 @@ typedef void (*wlt_widget_pointer_button_cb) (struct wlt_widget *widget,
|
||||
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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user