aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Del Campo Romero <xavi.dcr@tutanota.com>2022-09-20 12:34:35 +0200
committerXavier Del Campo Romero <xavi.dcr@tutanota.com>2022-09-20 13:52:14 +0200
commit684587a3c360380e865f9e95cc811fb1276983af (patch)
treec46fe7ade38694cf80b9dce151fdbfd0720b6036
parentb8d3eff412c1c91fa09435238998ba1fc17df3fe (diff)
Implement input component
It is required to redirect keyboard input (both physical or not) when a GUI line edit is focused. This means other components cannot be activated on key presses. Therefore, this new component is meant as a higher-level abstraction compared to the `keyboard`/`pad`/`mouse` components, which: - Implements the same APIs provided by `keyboard`, `mouse` and `pad`. - Returns the same results as the APIs above if no GUI element is focused, no input otherwise. Note: replacing calls to `keyboard`/`pad`/`mouse` with `input` will be implemented in a future commit.
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/input/CMakeLists.txt5
-rw-r--r--src/input/inc/input.h56
-rw-r--r--src/input/src/input.c175
4 files changed, 237 insertions, 0 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index ba57b6f..da04812 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -10,6 +10,7 @@ set(components
gfx
gui
header
+ input
instance
keyboard
menu
diff --git a/src/input/CMakeLists.txt b/src/input/CMakeLists.txt
new file mode 100644
index 0000000..9de4843
--- /dev/null
+++ b/src/input/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_library(input
+ "src/input.c"
+)
+target_include_directories(input PUBLIC "inc")
+target_link_libraries(input PUBLIC keyboard mouse pad peripheral)
diff --git a/src/input/inc/input.h b/src/input/inc/input.h
new file mode 100644
index 0000000..2dd401b
--- /dev/null
+++ b/src/input/inc/input.h
@@ -0,0 +1,56 @@
+#ifndef INPUT_H
+#define INPUT_H
+
+#include <keyboard.h>
+#include <mouse.h>
+#include <pad.h>
+#include <peripheral.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef void (*input_ch)(char ch, void *user);
+typedef void (*input_erase)(void *user);
+
+struct input
+{
+ input_ch cb;
+ input_erase erase;
+ void *user;
+ unsigned char t;
+ bool repeat;
+ struct keyboard_combo prev;
+};
+
+void input_update(struct input *in, const union peripheral *p);
+int input_render(const struct input *in, const union peripheral *p);
+bool input_keyboard_justpressed(const struct input *in,
+ const struct keyboard *k,
+ const struct keyboard_combo *c);
+bool input_keyboard_pressed(const struct input *in,
+ const struct keyboard *k,
+ const struct keyboard_combo *c);
+bool input_keyboard_justreleased(const struct input *in,
+ const struct keyboard *k,
+ const struct keyboard_combo *c);
+bool input_pad_pressed(const struct input *in, const struct pad *p,
+ enum pad_key k);
+bool input_pad_justpressed(const struct input *in, const struct pad *p,
+ enum pad_key k);
+bool input_pad_released(const struct input *in, const struct pad *p,
+ enum pad_key k);
+bool input_mouse_pressed(const struct input *in, const struct mouse *m,
+ enum mouse_button b);
+bool input_mouse_justpressed(const struct input *in, const struct mouse *m,
+ enum mouse_button b);
+bool input_mouse_justreleased(const struct input *in, const struct mouse *m,
+ enum mouse_button b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* INPUT_H */
diff --git a/src/input/src/input.c b/src/input/src/input.c
new file mode 100644
index 0000000..bb94424
--- /dev/null
+++ b/src/input/src/input.c
@@ -0,0 +1,175 @@
+#include <input.h>
+#include <keyboard.h>
+#include <mouse.h>
+#include <pad.h>
+#include <peripheral.h>
+#include <ctype.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+
+static void send_input(struct input *const in, const struct keyboard *const k,
+ const enum keyboard_key key)
+{
+ if (key != KEYBOARD_KEY_NONE)
+ {
+ switch (key)
+ {
+ case KEYBOARD_KEY_BACKSPACE:
+ in->erase(in->user);
+ break;
+
+ case KEYBOARD_KEY_ESC:
+ *in = (const struct input){0};
+ break;
+
+ default:
+ {
+ const char ch = keyboard_to_char(k, key);
+
+ if (isprint(ch))
+ in->cb(ch, in->user);
+ }
+ break;
+ }
+ }
+}
+
+static void update_keyboard(struct input *const in,
+ const struct keyboard *const k)
+{
+ struct keyboard_combo c;
+
+ if (keyboard_any_justpressed(k, &c))
+ for (size_t i = 0; i < sizeof c.keys / sizeof *c.keys; i++)
+ send_input(in, k, c.keys[i]);
+ else if (keyboard_any_pressed(k, &c))
+ {
+ if (memcmp(&c, &in->prev, sizeof c))
+ {
+ in->repeat = false;
+ in->t = 0;
+ }
+ else
+ {
+ enum {LONG_INTERVAL = 25, SHORT_INTERVAL = 2};
+
+ if (!in->repeat)
+ {
+ if (++in->t >= LONG_INTERVAL)
+ in->repeat = true;
+ }
+ else if (++in->t >= SHORT_INTERVAL)
+ {
+ for (size_t i = 0;
+ i < sizeof c.keys / sizeof *c.keys; i++)
+ send_input(in, k, c.keys[i]);
+
+ in->t = 0;
+ }
+ }
+
+ in->prev = c;
+ }
+ else
+ {
+ in->repeat = false;
+ in->t = 0;
+ }
+}
+
+void input_update(struct input *const in, const union peripheral *const p)
+{
+ switch (p->common.type)
+ {
+ case PERIPHERAL_TYPE_KEYBOARD_MOUSE:
+ if (in->cb && in->erase)
+ update_keyboard(in, &p->kbm.keyboard);
+
+ break;
+
+ case PERIPHERAL_TYPE_TOUCH:
+ /* Fall through. */
+ case PERIPHERAL_TYPE_PAD:
+ break;
+ }
+}
+
+int input_render(const struct input *const in, const union peripheral *const p)
+{
+ switch (p->common.type)
+ {
+ case PERIPHERAL_TYPE_KEYBOARD_MOUSE:
+ return 0;
+
+ case PERIPHERAL_TYPE_TOUCH:
+ /* Fall through. */
+ case PERIPHERAL_TYPE_PAD:
+ break;
+ }
+
+ return -1;
+}
+
+bool input_keyboard_justpressed(const struct input *const in,
+ const struct keyboard *const k,
+ const struct keyboard_combo *const c)
+{
+ return in->cb ? false : keyboard_justpressed(k, c);
+}
+
+bool input_keyboard_pressed(const struct input *const in,
+ const struct keyboard *const k,
+ const struct keyboard_combo *const c)
+{
+ return in->cb ? false : keyboard_pressed(k, c);
+}
+
+bool input_keyboard_justreleased(const struct input *const in,
+ const struct keyboard *const k,
+ const struct keyboard_combo *const c)
+{
+ return in->cb ? false : keyboard_justreleased(k, c);
+}
+
+bool input_pad_pressed(const struct input *const in,
+ const struct pad *const p,
+ const enum pad_key k)
+{
+ return in->cb ? false : pad_pressed(p, k);
+}
+
+bool input_pad_justpressed(const struct input *const in,
+ const struct pad *const p,
+ const enum pad_key k)
+{
+ return in->cb ? false : pad_justpressed(p, k);
+}
+
+bool input_pad_released(const struct input *const in,
+ const struct pad *const p,
+ const enum pad_key k)
+{
+ return in->cb ? false : pad_released(p, k);
+}
+
+bool input_mouse_pressed(const struct input *const in,
+ const struct mouse *const m,
+ const enum mouse_button b)
+{
+ return in->cb ? false : mouse_pressed(m, b);
+}
+
+bool input_mouse_justpressed(const struct input *const in,
+ const struct mouse *const m,
+ const enum mouse_button b)
+{
+ return in->cb ? false : mouse_justpressed(m, b);
+}
+
+bool input_mouse_justreleased(const struct input *const in,
+ const struct mouse *const m,
+ const enum mouse_button b)
+{
+ return in->cb ? false : mouse_justreleased(m, b);
+}