diff options
-rw-r--r-- | meson.build | 1 | ||||
-rw-r--r-- | src/input.c | 240 | ||||
-rw-r--r-- | src/input.h | 9 | ||||
-rw-r--r-- | src/main.c | 165 | ||||
-rw-r--r-- | src/utf8.c | 5 | ||||
-rw-r--r-- | src/utf8.h | 1 |
6 files changed, 259 insertions, 162 deletions
diff --git a/meson.build b/meson.build index 5ec1c1f..1d518d3 100644 --- a/meson.build +++ b/meson.build @@ -102,6 +102,7 @@ common_sources = files( 'src/entry_backend/harfbuzz.c', 'src/fuzzy_match.c', 'src/history.c', + 'src/input.c', 'src/log.c', 'src/mkdirp.c', 'src/shm.c', diff --git a/src/input.c b/src/input.c new file mode 100644 index 0000000..a343aef --- /dev/null +++ b/src/input.c @@ -0,0 +1,240 @@ +#include <linux/input-event-codes.h> +#include <wctype.h> +#include "input.h" +#include "nelem.h" +#include "tofi.h" +#include "utf8.h" + + +static void add_character(struct tofi *tofi, xkb_keycode_t keycode); +static void delete_character(struct tofi *tofi); +static void delete_word(struct tofi *tofi); +static void clear_input(struct tofi *tofi); +static void select_previous_result(struct tofi *tofi); +static void select_next_result(struct tofi *tofi); +static void reset_selection(struct tofi *tofi); +static void refresh_results(struct tofi *tofi); + +void input_handle_keypress(struct tofi *tofi, xkb_keycode_t keycode) +{ + if (tofi->xkb_state == NULL) { + return; + } + + /* + * Use physical key code for shortcuts, ignoring layout changes. + * Linux keycodes are 8 less than XKB keycodes. + */ + const uint32_t key = keycode - 8; + + xkb_keysym_t sym = xkb_state_key_get_one_sym(tofi->xkb_state, keycode); + + uint32_t ch = xkb_state_key_get_utf32( + tofi->xkb_state, + keycode); + if (utf8_isprint(ch)) { + add_character(tofi, keycode); + } else if (sym == XKB_KEY_BackSpace) { + delete_character(tofi); + } else if (key == KEY_W + && xkb_state_mod_name_is_active( + tofi->xkb_state, + XKB_MOD_NAME_CTRL, + XKB_STATE_MODS_EFFECTIVE)) + { + delete_word(tofi); + } else if (key == KEY_U + && xkb_state_mod_name_is_active( + tofi->xkb_state, + XKB_MOD_NAME_CTRL, + XKB_STATE_MODS_EFFECTIVE) + ) + { + clear_input(tofi); + } else if (sym == XKB_KEY_Up || sym == XKB_KEY_Left || sym == XKB_KEY_ISO_Left_Tab + || (key == KEY_K + && xkb_state_mod_name_is_active( + tofi->xkb_state, + XKB_MOD_NAME_CTRL, + XKB_STATE_MODS_EFFECTIVE) + ) + ) { + select_previous_result(tofi); + } else if (sym == XKB_KEY_Down || sym == XKB_KEY_Right || sym == XKB_KEY_Tab + || (key == KEY_J + && xkb_state_mod_name_is_active( + tofi->xkb_state, + XKB_MOD_NAME_CTRL, + XKB_STATE_MODS_EFFECTIVE) + ) + ) { + select_next_result(tofi); + } else if (sym == XKB_KEY_Home) { + reset_selection(tofi); + } else if (sym == XKB_KEY_Escape + || (key == KEY_C + && xkb_state_mod_name_is_active( + tofi->xkb_state, + XKB_MOD_NAME_CTRL, + XKB_STATE_MODS_EFFECTIVE) + ) + ) + { + tofi->closed = true; + return; + } else if (sym == XKB_KEY_Return || sym == XKB_KEY_KP_Enter) { + tofi->submit = true; + return; + } + + entry_update(&tofi->window.entry); + tofi->window.surface.redraw = true; +} + +void reset_selection(struct tofi *tofi) { + struct entry *entry = &tofi->window.entry; + entry->selection = 0; + entry->first_result = 0; +} + +void add_character(struct tofi *tofi, xkb_keycode_t keycode) +{ + struct entry *entry = &tofi->window.entry; + + if (entry->input_length >= N_ELEM(entry->input) - 1) { + /* No more room for input */ + return; + } + + char buf[5]; /* 4 UTF-8 bytes plus null terminator. */ + int len = xkb_state_key_get_utf8( + tofi->xkb_state, + keycode, + buf, + sizeof(buf)); + wchar_t ch; + mbtowc(&ch, buf, sizeof(buf)); + entry->input[entry->input_length] = ch; + entry->input_length++; + entry->input[entry->input_length] = L'\0'; + memcpy(&entry->input_mb[entry->input_mb_length], + buf, + N_ELEM(buf)); + entry->input_mb_length += len; + if (entry->drun) { + struct string_vec results = desktop_vec_filter(&entry->apps, entry->input_mb, tofi->fuzzy_match); + string_vec_destroy(&entry->results); + entry->results = results; + } else { + struct string_vec tmp = entry->results; + entry->results = string_vec_filter(&entry->results, entry->input_mb, tofi->fuzzy_match); + string_vec_destroy(&tmp); + } + + reset_selection(tofi); +} + +void refresh_results(struct tofi *tofi) +{ + struct entry *entry = &tofi->window.entry; + + const wchar_t *src = entry->input; + size_t siz = wcsrtombs( + entry->input_mb, + &src, + N_ELEM(entry->input_mb), + NULL); + entry->input_mb_length = siz; + string_vec_destroy(&entry->results); + if (entry->drun) { + entry->results = desktop_vec_filter(&entry->apps, entry->input_mb, tofi->fuzzy_match); + } else { + entry->results = string_vec_filter(&entry->commands, entry->input_mb, tofi->fuzzy_match); + } + + reset_selection(tofi); +} + +void delete_character(struct tofi *tofi) +{ + struct entry *entry = &tofi->window.entry; + + if (entry->input_length == 0) { + /* No input to delete. */ + return; + } + + entry->input_length--; + entry->input[entry->input_length] = L'\0'; + + refresh_results(tofi); +} + +void delete_word(struct tofi *tofi) +{ + struct entry *entry = &tofi->window.entry; + + if (entry->input_length == 0) { + /* No input to delete. */ + return; + } + + while (entry->input_length > 0 && iswspace(entry->input[entry->input_length - 1])) { + entry->input_length--; + } + while (entry->input_length > 0 && !iswspace(entry->input[entry->input_length - 1])) { + entry->input_length--; + } + entry->input[entry->input_length] = L'\0'; + + refresh_results(tofi); +} + +void clear_input(struct tofi *tofi) +{ + struct entry *entry = &tofi->window.entry; + + entry->input_length = 0; + entry->input[0] = L'\0'; + + refresh_results(tofi); +} + +void select_previous_result(struct tofi *tofi) +{ + struct entry *entry = &tofi->window.entry; + + if (entry->selection > 0) { + entry->selection--; + return; + } + + uint32_t nsel = MAX(MIN(entry->num_results_drawn, entry->results.count), 1); + + if (entry->first_result > nsel) { + entry->first_result -= entry->last_num_results_drawn; + entry->selection = entry->last_num_results_drawn - 1; + } else if (entry->first_result > 0) { + entry->selection = entry->first_result - 1; + entry->first_result = 0; + } +} + +void select_next_result(struct tofi *tofi) +{ + struct entry *entry = &tofi->window.entry; + + uint32_t nsel = MAX(MIN(entry->num_results_drawn, entry->results.count), 1); + + entry->selection++; + if (entry->selection >= nsel) { + entry->selection -= nsel; + if (entry->results.count > 0) { + entry->first_result += nsel; + entry->first_result %= entry->results.count; + } else { + entry->first_result = 0; + } + entry->last_num_results_drawn = entry->num_results_drawn; + } +} diff --git a/src/input.h b/src/input.h new file mode 100644 index 0000000..f78c365 --- /dev/null +++ b/src/input.h @@ -0,0 +1,9 @@ +#ifndef INPUT_H +#define INPUT_H + +#include <xkbcommon/xkbcommon.h> +#include "tofi.h" + +void input_handle_keypress(struct tofi *tofi, xkb_keycode_t keycode); + +#endif /* INPUT_H */ @@ -21,6 +21,7 @@ #include "config.h" #include "entry.h" #include "image.h" +#include "input.h" #include "log.h" #include "nelem.h" #include "shm.h" @@ -143,166 +144,6 @@ static void wl_keyboard_leave( /* Deliberately left blank */ } -static void handle_keypress(struct tofi *tofi, xkb_keycode_t keycode) -{ - if (tofi->xkb_state == NULL) { - return; - } - xkb_keysym_t sym = xkb_state_key_get_one_sym(tofi->xkb_state, keycode); - - bool reset_selection = false; - struct entry *entry = &tofi->window.entry; - char buf[5]; /* 4 UTF-8 bytes plus null terminator. */ - int len = xkb_state_key_get_utf8( - tofi->xkb_state, - keycode, - buf, - sizeof(buf)); - wchar_t ch; - mbtowc(&ch, buf, sizeof(buf)); - if (len > 0 && iswprint(ch)) { - if (entry->input_length < N_ELEM(entry->input) - 1) { - reset_selection = true; - entry->input[entry->input_length] = ch; - entry->input_length++; - entry->input[entry->input_length] = L'\0'; - memcpy(&entry->input_mb[entry->input_mb_length], - buf, - N_ELEM(buf)); - entry->input_mb_length += len; - if (entry->drun) { - struct string_vec results = desktop_vec_filter(&entry->apps, entry->input_mb, tofi->fuzzy_match); - string_vec_destroy(&entry->results); - entry->results = results; - } else { - struct string_vec tmp = entry->results; - entry->results = string_vec_filter(&entry->results, entry->input_mb, tofi->fuzzy_match); - string_vec_destroy(&tmp); - } - } - } else if (entry->input_length > 0 - && (sym == XKB_KEY_BackSpace - || (sym == XKB_KEY_w - && xkb_state_mod_name_is_active( - tofi->xkb_state, - XKB_MOD_NAME_CTRL, - XKB_STATE_MODS_EFFECTIVE)))) - { - reset_selection = true; - if (sym == XKB_KEY_BackSpace) { - entry->input_length--; - entry->input[entry->input_length] = L'\0'; - } else { - while (entry->input_length > 0 && iswspace(entry->input[entry->input_length - 1])) { - entry->input_length--; - } - while (entry->input_length > 0 && !iswspace(entry->input[entry->input_length - 1])) { - entry->input_length--; - } - entry->input[entry->input_length] = L'\0'; - } - const wchar_t *src = entry->input; - size_t siz = wcsrtombs( - entry->input_mb, - &src, - N_ELEM(entry->input_mb), - NULL); - entry->input_mb_length = siz; - string_vec_destroy(&entry->results); - if (entry->drun) { - entry->results = desktop_vec_filter(&entry->apps, entry->input_mb, tofi->fuzzy_match); - } else { - entry->results = string_vec_filter(&entry->commands, entry->input_mb, tofi->fuzzy_match); - } - } else if (sym == XKB_KEY_u - && xkb_state_mod_name_is_active( - tofi->xkb_state, - XKB_MOD_NAME_CTRL, - XKB_STATE_MODS_EFFECTIVE) - ) - { - reset_selection = true; - entry->input_length = 0; - entry->input[0] = L'\0'; - entry->input_mb_length = 0; - entry->input_mb[0] = '\0'; - string_vec_destroy(&entry->results); - if (entry->drun) { - entry->results = desktop_vec_filter(&entry->apps, entry->input_mb, tofi->fuzzy_match); - } else { - entry->results = string_vec_filter(&entry->commands, entry->input_mb, tofi->fuzzy_match); - } - } else if (sym == XKB_KEY_Escape - || (sym == XKB_KEY_c - && xkb_state_mod_name_is_active( - tofi->xkb_state, - XKB_MOD_NAME_CTRL, - XKB_STATE_MODS_EFFECTIVE) - ) - ) - { - tofi->closed = true; - return; - } else if (sym == XKB_KEY_Return || sym == XKB_KEY_KP_Enter) { - tofi->submit = true; - return; - } - - uint32_t nsel = MAX(MIN(entry->num_results_drawn, entry->results.count), 1); - if (sym == XKB_KEY_Up || sym == XKB_KEY_Left || sym == XKB_KEY_ISO_Left_Tab - || (sym == XKB_KEY_k - && xkb_state_mod_name_is_active( - tofi->xkb_state, - XKB_MOD_NAME_CTRL, - XKB_STATE_MODS_EFFECTIVE) - ) - ) { - reset_selection = false; - if (entry->selection > 0) { - entry->selection--; - } else { - if (entry->first_result > nsel) { - entry->first_result -= entry->last_num_results_drawn; - entry->selection = entry->last_num_results_drawn - 1; - } else if (entry->first_result > 0) { - entry->selection = entry->first_result - 1; - entry->first_result = 0; - } - } - } else if (sym == XKB_KEY_Down || sym == XKB_KEY_Right || sym == XKB_KEY_Tab - || (sym == XKB_KEY_j - && xkb_state_mod_name_is_active( - tofi->xkb_state, - XKB_MOD_NAME_CTRL, - XKB_STATE_MODS_EFFECTIVE) - ) - ) { - reset_selection = false; - entry->selection++; - if (entry->selection >= nsel) { - entry->selection -= nsel; - if (entry->results.count > 0) { - entry->first_result += nsel; - entry->first_result %= entry->results.count; - } else { - entry->first_result = 0; - } - entry->last_num_results_drawn = entry->num_results_drawn; - } - } else if (sym == XKB_KEY_Home) { - reset_selection = true; - } - - if (reset_selection) { - entry->selection = 0; - entry->first_result = 0; - } - - entry_update(&tofi->window.entry); - tofi->window.surface.redraw = true; - -} - static void wl_keyboard_key( void *data, struct wl_keyboard *wl_keyboard, @@ -333,7 +174,7 @@ static void wl_keyboard_key( tofi->repeat.keycode = keycode; tofi->repeat.next = gettime_ms() + tofi->repeat.delay; } - handle_keypress(tofi, keycode); + input_handle_keypress(tofi, keycode); } static void wl_keyboard_modifiers( @@ -1463,7 +1304,7 @@ int main(int argc, char *argv[]) if (tofi.repeat.active) { int64_t wait = (int64_t)tofi.repeat.next - (int64_t)gettime_ms(); if (wait <= 0) { - handle_keypress(&tofi, tofi.repeat.keycode); + input_handle_keypress(&tofi, tofi.repeat.keycode); tofi.repeat.next += 1000 / tofi.repeat.rate; } } @@ -2,6 +2,11 @@ #include "utf8.h" +uint32_t utf8_isprint(uint32_t c) +{ + return g_unichar_isprint(c); +} + uint32_t utf8_isupper(uint32_t c) { return g_unichar_isupper(c); @@ -4,6 +4,7 @@ #include <glib.h> #include <stdint.h> +uint32_t utf8_isprint(uint32_t c); uint32_t utf8_isupper(uint32_t c); uint32_t utf8_islower(uint32_t c); uint32_t utf8_isalnum(uint32_t c); |