aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJack Jamison <jackqjamison@gmail.com>2025-10-12 00:07:02 -0400
committerJack Jamison <jackqjamison@gmail.com>2025-10-12 00:07:02 -0400
commit60585faf7951cffb6046280bdd5f91275fb97d65 (patch)
tree30aad6fb91d33ed3b9a291d2d3fff7d9ed9a6f0c
parent36d12796644b296f300d9daf631f7702e1d81b86 (diff)
input buffer and key repeat
-rw-r--r--array.c43
-rw-r--r--array.h34
-rw-r--r--input_field.c49
-rw-r--r--input_field.h9
-rw-r--r--keyboard.c30
-rw-r--r--main.c45
-rw-r--r--pointer.c1
-rw-r--r--registry.c6
-rw-r--r--state.h12
9 files changed, 218 insertions, 11 deletions
diff --git a/array.c b/array.c
new file mode 100644
index 0000000..aa25e93
--- /dev/null
+++ b/array.c
@@ -0,0 +1,43 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "array.h"
+
+
+array_info* array_new_(size_t item_size, size_t capacity) {
+ array_info* info = calloc(1, sizeof(array_info) + item_size * capacity);
+ info->capacity = capacity;
+ return info;
+}
+
+void* array_add_(void* array, size_t item_size) {
+ array_info* info = NULL;
+ if (!array) {
+ info = array_new_(item_size, 8);
+ }
+ else {
+ info = ((array_info*)array) - 1;
+ }
+ if (info->size == info->capacity) {
+ info->capacity <<= 1;
+ info = realloc(info, sizeof(array_info) + (info->capacity * item_size));
+ }
+ info->size++;
+ return &(info[1]);
+}
+
+void array_print(void* array) {
+ array_info* info = &((array_info*)array)[-1];
+ printf( "size: %lu\n"
+ "capacity: %lu\n"
+ "array: %p\n",
+ info->size,
+ info->capacity,
+ info->array);
+}
+
+void array_pop(void* array) {
+ array_info* info = &((array_info*)array)[-1];
+ if (info->size)
+ info->size--;
+}
diff --git a/array.h b/array.h
new file mode 100644
index 0000000..c2d908a
--- /dev/null
+++ b/array.h
@@ -0,0 +1,34 @@
+#ifndef ARRAY_H_
+#define ARRAY_H_
+#include <stdlib.h>
+
+typedef struct {
+ size_t size;
+ size_t capacity;
+ char array[];
+} array_info;
+
+array_info* array_new_(size_t item_size, size_t capacity);
+void array_print(void* array);
+void array_pop(void* array);
+void* array_add_(void* array, size_t item_size);
+
+
+#define array_clear(array) (((array_info*)(array))[-1].size = 0)
+#define array_size(array) (((array_info*)(array))[-1].size)
+#define array_new(type, capacity) ((type*)(array_new_(sizeof(type), capacity)->array))
+
+#define array_free(array) do { \
+ free(((array_info*)(array)) - 1); \
+ (array) = NULL; \
+} while (0)
+
+#define array_add(array, value) do { \
+ void* __temp = array_add_((array), sizeof(*(array))); \
+ (array) = __temp; \
+ (array)[array_size((array)) - 1] = value; \
+} while (0)
+
+#define array_last(array) (array_size(array) ? (array)[array_size(array) - 1] : NULL);
+
+#endif // ARRAY_H_
diff --git a/input_field.c b/input_field.c
new file mode 100644
index 0000000..026a22c
--- /dev/null
+++ b/input_field.c
@@ -0,0 +1,49 @@
+#include <string.h>
+
+#include "input_field.h"
+#include "array.h"
+
+void type_key(client_state* state, xkb_keysym_t keysym) {
+ bool ctrl = xkb_state_mod_name_is_active(state->xkb_state, XKB_MOD_NAME_CTRL, XKB_STATE_MODS_EFFECTIVE);
+
+ // exit app
+ if ((keysym == XKB_KEY_c && ctrl) ||
+ (keysym == XKB_KEY_g && ctrl) ||
+ (keysym == XKB_KEY_Escape)) {
+
+ state->running = false;
+ return;
+ }
+
+ // submit line
+ if (keysym == XKB_KEY_Return || keysym == XKB_KEY_KP_Enter) {
+ submit_line(state);
+ return;
+ }
+
+ // delete
+ if (keysym == XKB_KEY_BackSpace || keysym == XKB_KEY_Delete) {
+ if (ctrl) {
+ array_clear(state->input_buffer);
+ } else {
+ array_pop(state->input_buffer);
+ }
+ return;
+ }
+
+ // type char into buffer
+ char buf[16] = {0};
+ int len = xkb_keysym_to_utf8(keysym, buf, sizeof(buf));
+ if (len > 0) {
+ for (int i = 0; i < strlen(buf); i++) {
+ array_add(state->input_buffer, buf[i]);
+ }
+ }
+}
+
+void submit_line(client_state* state) {
+ if (state->input_buffer) {
+ printf("%.*s\n", (int)array_size(state->input_buffer), state->input_buffer);
+ array_clear(state->input_buffer);
+ }
+}
diff --git a/input_field.h b/input_field.h
new file mode 100644
index 0000000..64cb557
--- /dev/null
+++ b/input_field.h
@@ -0,0 +1,9 @@
+#ifndef INPUT_FIELD_H_
+#define INPUT_FIELD_H_
+
+#include "state.h"
+
+void type_key(client_state* state, xkb_keysym_t keysym);
+void submit_line(client_state* state);
+
+#endif
diff --git a/keyboard.c b/keyboard.c
index 932cba7..3be61a9 100644
--- a/keyboard.c
+++ b/keyboard.c
@@ -3,12 +3,15 @@
#include <locale.h>
#include "state.h"
+#include "input_field.h"
struct wl_keyboard_listener keyboard_listener;
void setup_keyboard(client_state* state) {
state->keyboard = wl_seat_get_keyboard(state->seat);
wl_keyboard_add_listener(state->keyboard, &keyboard_listener, state);
+
+ state->key_repeat_timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
}
// listeners
@@ -74,8 +77,30 @@ void wl_keyboard_key(void *data, struct wl_keyboard *wl_keyboard,
client_state *state = data;
xkb_keysym_t keysym = xkb_state_key_get_one_sym(state->xkb_state, key + 8);
- if (keysym == XKB_KEY_q) {
- state->running = false;
+
+ if (key_state == WL_KEYBOARD_KEY_STATE_PRESSED) {
+ type_key(state, keysym);
+
+ // start repeat
+ state->repeat_key = keysym;
+ struct itimerspec timer = {0};
+ if (state->key_repeat_rate > 1)
+ timer.it_interval.tv_nsec = 1000000000 / state->key_repeat_rate;
+ else
+ timer.it_interval.tv_sec = 1;
+ timer.it_value.tv_sec = state->key_repeat_delay / 1000;
+ timer.it_value.tv_nsec = (state->key_repeat_delay % 1000) * 1000000;
+ if (timerfd_settime(state->key_repeat_timer_fd, 0, &timer, NULL) == -1) {
+ printf("error setting key repeat timer\n");
+ }
+
+ } else if (key_state == WL_KEYBOARD_KEY_STATE_RELEASED) {
+
+ if (keysym == state->repeat_key) {
+ // stop repeat
+ struct itimerspec timer = {0};
+ timerfd_settime(state->key_repeat_timer_fd, 0, &timer, NULL);
+ }
}
}
@@ -92,6 +117,7 @@ void wl_keyboard_repeat_info(void *data, struct wl_keyboard *wl_keyboard,
client_state* state = data;
state->key_repeat_rate = rate;
state->key_repeat_delay = delay;
+ printf("repeat info\n");
}
struct wl_keyboard_listener keyboard_listener = {
diff --git a/main.c b/main.c
index a6e261d..bf27838 100644
--- a/main.c
+++ b/main.c
@@ -1,8 +1,13 @@
#include <stdio.h>
+#include <poll.h>
+#include <unistd.h>
#include "state.h"
#include "wayland.h"
#include "graphics.h"
+#include "input_field.h"
+
+void poll_events(client_state* state);
int main() {
client_state state = {0};
@@ -31,7 +36,45 @@ int main() {
// event loop
while (state.running) {
- wl_display_dispatch_pending(state.display);
+ poll_events(&state);
render_frame(&state);
}
}
+
+void poll_events(client_state* state) {
+ enum { DISPLAY_FD, KEYREPEAT_FD };
+ struct pollfd fds[] = {
+ [DISPLAY_FD] = { wl_display_get_fd(state->display), POLLIN },
+ [KEYREPEAT_FD] = { state->key_repeat_timer_fd, POLLIN },
+ };
+
+ bool event = false;
+ while (!event) {
+ while (wl_display_prepare_read(state->display) != 0) {
+ if (wl_display_dispatch_pending(state->display) > 0) {
+ return;
+ }
+ }
+ if (poll(fds, sizeof(fds) / sizeof(fds[0]), -1) == -1) {
+ wl_display_cancel_read(state->display);
+ return;
+ }
+ if (fds[DISPLAY_FD].revents & POLLIN) {
+ wl_display_read_events(state->display);
+ if (wl_display_dispatch_pending(state->display) > 0)
+ event = true;
+ }
+ else {
+ wl_display_cancel_read(state->display);
+ }
+ if (fds[KEYREPEAT_FD].revents & POLLIN) {
+ uint64_t repeats;
+ if (read(state->key_repeat_timer_fd, &repeats, sizeof(repeats)) == 8) {
+ for (uint64_t i = 0; i < repeats; i++) {
+ type_key(state, state->repeat_key);
+ }
+ event = true;
+ }
+ }
+ }
+}
diff --git a/pointer.c b/pointer.c
index 85eff0d..904323f 100644
--- a/pointer.c
+++ b/pointer.c
@@ -7,7 +7,6 @@ void setup_pointer(client_state* state) {
state->cursor_shape_device = wp_cursor_shape_manager_v1_get_pointer(
state->cursor_shape_manager, state->pointer);
wl_pointer_add_listener(state->pointer, &pointer_listener, state);
- printf("setup pointer\n");
}
// listeners
diff --git a/registry.c b/registry.c
index d872e4c..8230339 100644
--- a/registry.c
+++ b/registry.c
@@ -22,13 +22,13 @@ void global(void *data, struct wl_registry *wl_registry, uint32_t name, const ch
state->compositor = wl_registry_bind(wl_registry, name, &wl_compositor_interface, 1);
}
else if (!strcmp(interface, wl_seat_interface.name)) {
- state->seat = wl_registry_bind(state->registry, name, &wl_seat_interface, 1);
+ state->seat = wl_registry_bind(state->registry, name, &wl_seat_interface, 4);
}
else if (!strcmp(interface, zwlr_layer_shell_v1_interface.name)) {
- state->layer_shell = wl_registry_bind(wl_registry, name, &zwlr_layer_shell_v1_interface, version);
+ state->layer_shell = wl_registry_bind(wl_registry, name, &zwlr_layer_shell_v1_interface, 5);
}
else if (!strcmp(interface, wp_cursor_shape_manager_v1_interface.name)) {
- state->cursor_shape_manager = wl_registry_bind( wl_registry, name, &wp_cursor_shape_manager_v1_interface, version);
+ state->cursor_shape_manager = wl_registry_bind( wl_registry, name, &wp_cursor_shape_manager_v1_interface, 1);
}
else {
}
diff --git a/state.h b/state.h
index fec2cd3..352236d 100644
--- a/state.h
+++ b/state.h
@@ -9,39 +9,43 @@
#include <xkbcommon/xkbcommon.h>
#include <xkbcommon/xkbcommon-compose.h>
#include <cursor-shape-v1.h>
+#include <sys/timerfd.h>
#include "./glad/glad.h"
typedef struct {
+ // wayland
struct wl_display* display;
struct wl_registry* registry;
struct wl_compositor* compositor;
struct wl_surface* surface;
-
struct zwlr_layer_shell_v1* layer_shell;
struct zwlr_layer_surface_v1* layer_surface;
-
struct wl_seat* seat;
struct wl_keyboard* keyboard;
struct wl_pointer* pointer;
-
struct wp_cursor_shape_manager_v1* cursor_shape_manager;
struct wp_cursor_shape_device_v1* cursor_shape_device;
+ // xkb
struct xkb_context* xkb_context;
struct xkb_keymap* xkb_keymap;
struct xkb_state* xkb_state;
struct xkb_compose_state* xkb_compose_state;
int key_repeat_rate, key_repeat_delay;
+ int key_repeat_timer_fd;
+ xkb_keysym_t repeat_key;
+ // egl
struct wl_egl_window* egl_window;
EGLDisplay egl_display;
EGLSurface egl_surface;
EGLConfig egl_config;
EGLContext egl_context;
+ // state
+ char* input_buffer;
uint32_t width, height;
-
bool running;
} client_state;