mirror of
https://github.com/Cloudef/bemenu
synced 2024-06-01 04:16:21 +02:00
Key repeats.
This commit is contained in:
parent
ee3c41f162
commit
0d5cdc2c96
|
@ -1,7 +1,9 @@
|
|||
#define _DEFAULT_SOURCE
|
||||
#include "wayland.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/timerfd.h>
|
||||
|
||||
const char *BM_XKB_MASK_NAMES[MASK_LAST] = {
|
||||
XKB_MOD_NAME_SHIFT,
|
||||
|
@ -104,7 +106,24 @@ keyboard_handle_enter(void *data, struct wl_keyboard *keyboard, uint32_t serial,
|
|||
static void
|
||||
keyboard_handle_leave(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface)
|
||||
{
|
||||
(void)data, (void)keyboard, (void)serial, (void)surface;
|
||||
(void)keyboard, (void)serial, (void)surface;
|
||||
struct input *input = data;
|
||||
struct itimerspec its;
|
||||
its.it_interval.tv_sec = 0;
|
||||
its.it_interval.tv_nsec = 0;
|
||||
its.it_value.tv_sec = 0;
|
||||
its.it_value.tv_nsec = 0;
|
||||
timerfd_settime(*input->repeat_fd, 0, &its, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
press(struct input *input, xkb_keysym_t sym, uint32_t key, enum wl_keyboard_key_state state)
|
||||
{
|
||||
input->sym = (state == WL_KEYBOARD_KEY_STATE_PRESSED ? sym : XKB_KEY_NoSymbol);
|
||||
input->code = (state == WL_KEYBOARD_KEY_STATE_PRESSED ? key + 8 : 0);
|
||||
|
||||
if (input->notify.key)
|
||||
input->notify.key(state, sym, key);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -117,35 +136,26 @@ keyboard_handle_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, u
|
|||
if (!input->xkb.state)
|
||||
return;
|
||||
|
||||
uint32_t code = key + 8;
|
||||
xkb_keysym_t sym = xkb_state_key_get_one_sym(input->xkb.state, code);
|
||||
xkb_keysym_t sym = xkb_state_key_get_one_sym(input->xkb.state, key + 8);
|
||||
press(input, sym, key, state);
|
||||
|
||||
input->sym = (state == WL_KEYBOARD_KEY_STATE_PRESSED ? sym : XKB_KEY_NoSymbol);
|
||||
input->code = (state == WL_KEYBOARD_KEY_STATE_PRESSED ? code : 0);
|
||||
|
||||
if (input->notify.key)
|
||||
input->notify.key(state, sym, code);
|
||||
|
||||
#if 0
|
||||
if (state == WL_KEYBOARD_KEY_STATE_RELEASED &&
|
||||
key == input->repeat_key) {
|
||||
its.it_interval.tv_sec = 0;
|
||||
its.it_interval.tv_nsec = 0;
|
||||
its.it_value.tv_sec = 0;
|
||||
its.it_value.tv_nsec = 0;
|
||||
timerfd_settime(input->repeat_timer_fd, 0, &its, NULL);
|
||||
} else if (state == WL_KEYBOARD_KEY_STATE_PRESSED &&
|
||||
xkb_keymap_key_repeats(input->xkb.keymap, code)) {
|
||||
if (state == WL_KEYBOARD_KEY_STATE_PRESSED && xkb_keymap_key_repeats(input->xkb.keymap, input->code)) {
|
||||
struct itimerspec its;
|
||||
input->repeat_sym = sym;
|
||||
input->repeat_key = key;
|
||||
input->repeat_time = time;
|
||||
its.it_interval.tv_sec = input->repeat_rate_sec;
|
||||
its.it_interval.tv_nsec = input->repeat_rate_nsec;
|
||||
its.it_value.tv_sec = input->repeat_delay_sec;
|
||||
its.it_value.tv_nsec = input->repeat_delay_nsec;
|
||||
timerfd_settime(input->repeat_timer_fd, 0, &its, NULL);
|
||||
timerfd_settime(*input->repeat_fd, 0, &its, NULL);
|
||||
} else if (state == WL_KEYBOARD_KEY_STATE_RELEASED && key == input->repeat_key) {
|
||||
struct itimerspec its;
|
||||
its.it_interval.tv_sec = 0;
|
||||
its.it_interval.tv_nsec = 0;
|
||||
its.it_value.tv_sec = 0;
|
||||
its.it_value.tv_nsec = 0;
|
||||
timerfd_settime(*input->repeat_fd, 0, &its, NULL);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -167,10 +177,33 @@ keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard, uint32_t ser
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_repeat_info(struct input *input, int32_t rate, int32_t delay)
|
||||
{
|
||||
assert(input);
|
||||
|
||||
input->repeat_rate_sec = input->repeat_rate_nsec = 0;
|
||||
input->repeat_delay_sec = input->repeat_delay_nsec = 0;
|
||||
|
||||
/* a rate of zero disables any repeating, regardless of the delay's value */
|
||||
if (rate == 0)
|
||||
return;
|
||||
|
||||
if (rate == 1)
|
||||
input->repeat_rate_sec = 1;
|
||||
else
|
||||
input->repeat_rate_nsec = 1000000000 / rate;
|
||||
|
||||
input->repeat_delay_sec = delay / 1000;
|
||||
delay -= (input->repeat_delay_sec * 1000);
|
||||
input->repeat_delay_nsec = delay * 1000 * 1000;
|
||||
}
|
||||
|
||||
static void
|
||||
keyboard_handle_repeat_info(void *data, struct wl_keyboard *keyboard, int32_t rate, int32_t delay)
|
||||
{
|
||||
(void)data, (void)keyboard, (void)rate, (void)delay;
|
||||
(void)keyboard;
|
||||
set_repeat_info(data, rate, delay);
|
||||
}
|
||||
|
||||
static const struct wl_keyboard_listener keyboard_listener = {
|
||||
|
@ -241,6 +274,19 @@ static const struct wl_registry_listener registry_listener = {
|
|||
registry_handle_global_remove
|
||||
};
|
||||
|
||||
void
|
||||
bm_wl_repeat(struct wayland *wayland)
|
||||
{
|
||||
uint64_t exp;
|
||||
if (read(wayland->fds.repeat, &exp, sizeof(exp)) != sizeof(exp))
|
||||
return;
|
||||
|
||||
if (wayland->input.notify.key)
|
||||
wayland->input.notify.key(WL_KEYBOARD_KEY_STATE_PRESSED, wayland->input.repeat_sym, wayland->input.repeat_key + 8);
|
||||
|
||||
press(&wayland->input, wayland->input.repeat_sym, wayland->input.repeat_key, WL_KEYBOARD_KEY_STATE_PRESSED);
|
||||
}
|
||||
|
||||
void
|
||||
bm_wl_registry_destroy(struct wayland *wayland)
|
||||
{
|
||||
|
@ -282,6 +328,7 @@ bm_wl_registry_register(struct wayland *wayland)
|
|||
if (!wayland->input.keyboard || !(wayland->formats & (1 << WL_SHM_FORMAT_ARGB8888)))
|
||||
return false;
|
||||
|
||||
set_repeat_info(&wayland->input, 40, 400);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#define _DEFAULT_SOURCE
|
||||
#include "internal.h"
|
||||
#include "version.h"
|
||||
#include "wayland.h"
|
||||
|
@ -6,19 +7,41 @@
|
|||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/timerfd.h>
|
||||
|
||||
static int efd;
|
||||
|
||||
static void
|
||||
render(const struct bm_menu *menu)
|
||||
{
|
||||
struct wayland *wayland = menu->renderer->internal;
|
||||
wl_display_dispatch_pending(wayland->display);
|
||||
|
||||
if (wl_display_flush(wayland->display) < 0 && errno != EAGAIN) {
|
||||
wayland->input.sym = XKB_KEY_Escape;
|
||||
return;
|
||||
}
|
||||
|
||||
struct epoll_event ep[16];
|
||||
uint32_t num = epoll_wait(efd, ep, 16, -1);
|
||||
for (uint32_t i = 0; i < num; ++i) {
|
||||
if (ep[i].data.ptr == &wayland->fds.display) {
|
||||
if (ep[i].events & EPOLLERR || ep[i].events & EPOLLHUP ||
|
||||
((ep[i].events & EPOLLIN) && wl_display_dispatch(wayland->display) < 0))
|
||||
wayland->input.sym = XKB_KEY_Escape;
|
||||
} else if (ep[i].data.ptr == &wayland->fds.repeat) {
|
||||
bm_wl_repeat(wayland);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t count;
|
||||
bm_menu_get_filtered_items(menu, &count);
|
||||
uint32_t lines = (count < menu->lines ? count : menu->lines) + 1;
|
||||
bm_wl_window_render(&wayland->window, menu, lines);
|
||||
|
||||
if (wl_display_dispatch(wayland->display) < 0)
|
||||
wayland->input.sym = XKB_KEY_Escape;
|
||||
}
|
||||
|
||||
static enum bm_key
|
||||
|
@ -31,13 +54,17 @@ poll_key(const struct bm_menu *menu, unsigned int *unicode)
|
|||
if (wayland->input.sym == XKB_KEY_NoSymbol)
|
||||
return BM_KEY_UNICODE;
|
||||
|
||||
xkb_keysym_t sym = wayland->input.sym;
|
||||
uint32_t mods = wayland->input.modifiers;
|
||||
*unicode = xkb_state_key_get_utf32(wayland->input.xkb.state, wayland->input.code);
|
||||
|
||||
if (!*unicode && wayland->input.code == 23 && (mods & MOD_SHIFT))
|
||||
return BM_KEY_SHIFT_TAB;
|
||||
|
||||
switch (wayland->input.sym) {
|
||||
wayland->input.sym = XKB_KEY_NoSymbol;
|
||||
wayland->input.code = 0;
|
||||
|
||||
switch (sym) {
|
||||
case XKB_KEY_Up:
|
||||
return BM_KEY_UP;
|
||||
|
||||
|
@ -138,6 +165,9 @@ destructor(struct bm_menu *menu)
|
|||
xkb_context_unref(wayland->input.xkb.context);
|
||||
|
||||
if (wayland->display) {
|
||||
epoll_ctl(efd, EPOLL_CTL_DEL, wayland->fds.repeat, NULL);
|
||||
epoll_ctl(efd, EPOLL_CTL_DEL, wayland->fds.display, NULL);
|
||||
close(wayland->fds.repeat);
|
||||
wl_display_flush(wayland->display);
|
||||
wl_display_disconnect(wayland->display);
|
||||
}
|
||||
|
@ -169,7 +199,24 @@ constructor(struct bm_menu *menu)
|
|||
if (!bm_wl_window_create(&wayland->window, wayland->shm, wayland->shell, wayland->xdg_shell, surface))
|
||||
goto fail;
|
||||
|
||||
if (!efd && (efd = epoll_create(EPOLL_CLOEXEC)) < 0)
|
||||
goto fail;
|
||||
|
||||
wayland->fds.display = wl_display_get_fd(wayland->display);
|
||||
wayland->fds.repeat = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
|
||||
|
||||
struct epoll_event ep;
|
||||
ep.events = EPOLLIN | EPOLLERR | EPOLLHUP;
|
||||
ep.data.ptr = &wayland->fds.display;
|
||||
epoll_ctl(efd, EPOLL_CTL_ADD, wayland->fds.display, &ep);
|
||||
|
||||
struct epoll_event ep2;
|
||||
ep2.events = EPOLLIN;
|
||||
ep2.data.ptr = &wayland->fds.repeat;
|
||||
epoll_ctl(efd, EPOLL_CTL_ADD, wayland->fds.repeat, &ep2);
|
||||
|
||||
wayland->window.notify.render = bm_cairo_paint;
|
||||
wayland->input.repeat_fd = &wayland->fds.repeat;
|
||||
return true;
|
||||
|
||||
fail:
|
||||
|
|
|
@ -44,6 +44,8 @@ struct xkb {
|
|||
};
|
||||
|
||||
struct input {
|
||||
int *repeat_fd;
|
||||
|
||||
struct wl_keyboard *keyboard;
|
||||
struct xkb xkb;
|
||||
|
||||
|
@ -51,6 +53,14 @@ struct input {
|
|||
uint32_t code;
|
||||
uint32_t modifiers;
|
||||
|
||||
xkb_keysym_t repeat_sym;
|
||||
uint32_t repeat_key;
|
||||
|
||||
int32_t repeat_rate_sec;
|
||||
int32_t repeat_rate_nsec;
|
||||
int32_t repeat_delay_sec;
|
||||
int32_t repeat_delay_nsec;
|
||||
|
||||
struct {
|
||||
void (*key)(enum wl_keyboard_key_state state, xkb_keysym_t sym, uint32_t code);
|
||||
} notify;
|
||||
|
@ -66,6 +76,7 @@ struct buffer {
|
|||
struct window {
|
||||
struct wl_surface *surface;
|
||||
struct wl_shell_surface *shell_surface;
|
||||
struct wl_callback *frame_cb;
|
||||
struct xdg_surface *xdg_surface;
|
||||
struct wl_shm *shm;
|
||||
struct buffer buffers[2];
|
||||
|
@ -78,6 +89,11 @@ struct window {
|
|||
};
|
||||
|
||||
struct wayland {
|
||||
struct {
|
||||
int32_t display;
|
||||
int32_t repeat;
|
||||
} fds;
|
||||
|
||||
struct wl_display *display;
|
||||
struct wl_registry *registry;
|
||||
struct wl_compositor *compositor;
|
||||
|
@ -90,6 +106,7 @@ struct wayland {
|
|||
uint32_t formats;
|
||||
};
|
||||
|
||||
void bm_wl_repeat(struct wayland *wayland);
|
||||
bool bm_wl_registry_register(struct wayland *wayland);
|
||||
void bm_wl_registry_destroy(struct wayland *wayland);
|
||||
void bm_wl_window_render(struct window *window, const struct bm_menu *menu, uint32_t lines);
|
||||
|
|
|
@ -246,11 +246,27 @@ static const struct xdg_surface_listener xdg_surface_listener = {
|
|||
.close = xdg_surface_close,
|
||||
};
|
||||
|
||||
static void
|
||||
frame_callback(void *data, struct wl_callback *callback, uint32_t time)
|
||||
{
|
||||
(void)time;
|
||||
struct window *window = data;
|
||||
wl_callback_destroy(callback);
|
||||
window->frame_cb = NULL;
|
||||
}
|
||||
|
||||
static const struct wl_callback_listener listener = {
|
||||
frame_callback
|
||||
};
|
||||
|
||||
void
|
||||
bm_wl_window_render(struct window *window, const struct bm_menu *menu, uint32_t lines)
|
||||
{
|
||||
assert(window && menu);
|
||||
|
||||
if (window->frame_cb)
|
||||
return;
|
||||
|
||||
struct buffer *buffer;
|
||||
if (!(buffer = next_buffer(window)))
|
||||
return;
|
||||
|
@ -265,6 +281,9 @@ bm_wl_window_render(struct window *window, const struct bm_menu *menu, uint32_t
|
|||
if (window->notify.render)
|
||||
window->displayed = window->notify.render(&buffer->cairo, buffer->width, buffer->height, menu);
|
||||
|
||||
window->frame_cb = wl_surface_frame(window->surface);
|
||||
wl_callback_add_listener(window->frame_cb, &listener, window);
|
||||
|
||||
wl_surface_damage(window->surface, 0, 0, buffer->width, buffer->height);
|
||||
wl_surface_attach(window->surface, buffer->buffer, 0, 0);
|
||||
wl_surface_commit(window->surface);
|
||||
|
|
Loading…
Reference in New Issue