summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPhil Jones <philj56@gmail.com>2022-10-21 23:37:24 +0100
committerPhil Jones <philj56@gmail.com>2022-10-21 23:37:24 +0100
commitd1b94b4487c72b13320a281ad6a2fc291e4c79c7 (patch)
treed4b7ce738f9ad14dd55a1054a39901bf835db2a5 /src
parent7bb70c7407f652c584837d651fb9bcdb6b66ff9f (diff)
Initial input handling cleanup.
Also changed keyboard shortcuts to use physical keycodes, rather than XKB keysyms. This means shortcuts don't shift when keyboard layout is changed.
Diffstat (limited to 'src')
-rw-r--r--src/input.c240
-rw-r--r--src/input.h9
-rw-r--r--src/main.c165
-rw-r--r--src/utf8.c5
-rw-r--r--src/utf8.h1
5 files changed, 258 insertions, 162 deletions
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 */
diff --git a/src/main.c b/src/main.c
index 043f6a8..3e84f49 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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;
}
}
diff --git a/src/utf8.c b/src/utf8.c
index 7ed6046..bd0c425 100644
--- a/src/utf8.c
+++ b/src/utf8.c
@@ -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);
diff --git a/src/utf8.h b/src/utf8.h
index b6ee986..fb0fc5f 100644
--- a/src/utf8.h
+++ b/src/utf8.h
@@ -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);