diff options
| author | Jack Jamison <jackqjamison@gmail.com> | 2025-10-12 00:07:02 -0400 |
|---|---|---|
| committer | Jack Jamison <jackqjamison@gmail.com> | 2025-10-12 00:07:02 -0400 |
| commit | 60585faf7951cffb6046280bdd5f91275fb97d65 (patch) | |
| tree | 30aad6fb91d33ed3b9a291d2d3fff7d9ed9a6f0c | |
| parent | 36d12796644b296f300d9daf631f7702e1d81b86 (diff) | |
input buffer and key repeat
| -rw-r--r-- | array.c | 43 | ||||
| -rw-r--r-- | array.h | 34 | ||||
| -rw-r--r-- | input_field.c | 49 | ||||
| -rw-r--r-- | input_field.h | 9 | ||||
| -rw-r--r-- | keyboard.c | 30 | ||||
| -rw-r--r-- | main.c | 45 | ||||
| -rw-r--r-- | pointer.c | 1 | ||||
| -rw-r--r-- | registry.c | 6 | ||||
| -rw-r--r-- | state.h | 12 |
9 files changed, 218 insertions, 11 deletions
@@ -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--; +} @@ -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 @@ -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 = { @@ -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; + } + } + } +} @@ -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 @@ -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 { } @@ -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; |
