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:
David Herrmann 2012-10-09 12:26:07 +02:00
parent 0a03785ffc
commit 33ebc01441
10 changed files with 67 additions and 10 deletions

View File

@ -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 */

View File

@ -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;

View File

@ -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);

View File

@ -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 */

View File

@ -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 */

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);