forked from RepoMirrors/bemenu
mouse and touch support on wayland
This commit is contained in:
parent
391bf16c85
commit
a111aa2afa
@ -502,11 +502,15 @@ run_menu(const struct client *client, struct bm_menu *menu, void (*item_cb)(cons
|
||||
|
||||
uint32_t unicode;
|
||||
enum bm_key key;
|
||||
struct bm_pointer pointer;
|
||||
struct bm_touch touch;
|
||||
enum bm_run_result status = BM_RUN_RESULT_RUNNING;
|
||||
do {
|
||||
bm_menu_render(menu);
|
||||
key = bm_menu_poll_key(menu, &unicode);
|
||||
} while ((status = bm_menu_run_with_key(menu, key, unicode)) == BM_RUN_RESULT_RUNNING);
|
||||
pointer = bm_menu_poll_pointer(menu);
|
||||
touch = bm_menu_poll_touch(menu);
|
||||
} while ((status = bm_menu_run_with_events(menu, key, pointer, touch, unicode)) == BM_RUN_RESULT_RUNNING);
|
||||
|
||||
switch (status) {
|
||||
case BM_RUN_RESULT_SELECTED:
|
||||
|
111
lib/bemenu.h
111
lib/bemenu.h
@ -253,6 +253,70 @@ enum bm_key {
|
||||
BM_KEY_LAST
|
||||
};
|
||||
|
||||
enum bm_pointer_key {
|
||||
BM_POINTER_KEY_NONE,
|
||||
BM_POINTER_KEY_PRIMARY,
|
||||
};
|
||||
|
||||
enum bm_pointer_axis {
|
||||
BM_POINTER_AXIS_VERTICAL = 0,
|
||||
BM_POINTER_AXIS_HORIZONTAL = 1,
|
||||
};
|
||||
|
||||
enum bm_pointer_event_mask {
|
||||
POINTER_EVENT_ENTER = 1 << 1,
|
||||
POINTER_EVENT_LEAVE = 1 << 2,
|
||||
POINTER_EVENT_MOTION = 1 << 3,
|
||||
POINTER_EVENT_BUTTON = 1 << 4,
|
||||
POINTER_EVENT_AXIS = 1 << 5,
|
||||
POINTER_EVENT_AXIS_SOURCE = 1 << 6,
|
||||
POINTER_EVENT_AXIS_STOP = 1 << 7,
|
||||
POINTER_EVENT_AXIS_DISCRETE = 1 << 8,
|
||||
};
|
||||
|
||||
enum bm_pointer_state_mask {
|
||||
POINTER_STATE_RELEASED,
|
||||
POINTER_STATE_PRESSED,
|
||||
};
|
||||
|
||||
struct bm_pointer {
|
||||
uint32_t event_mask;
|
||||
uint32_t pos_x, pos_y;
|
||||
uint32_t button, state;
|
||||
uint32_t time;
|
||||
struct {
|
||||
bool valid;
|
||||
int32_t value;
|
||||
int32_t discrete;
|
||||
} axes[2];
|
||||
uint32_t axis_source;
|
||||
};
|
||||
|
||||
enum bm_touch_event_mask {
|
||||
TOUCH_EVENT_DOWN = 1 << 0,
|
||||
TOUCH_EVENT_UP = 1 << 1,
|
||||
TOUCH_EVENT_MOTION = 1 << 2,
|
||||
TOUCH_EVENT_CANCEL = 1 << 3,
|
||||
TOUCH_EVENT_SHAPE = 1 << 4,
|
||||
TOUCH_EVENT_ORIENTATION = 1 << 5,
|
||||
};
|
||||
|
||||
struct bm_touch_point {
|
||||
bool valid;
|
||||
int32_t id;
|
||||
uint32_t event_mask;
|
||||
int32_t start_x, start_y;
|
||||
int32_t pos_x, pos_y;
|
||||
uint32_t major, minor;
|
||||
uint32_t orientation;
|
||||
};
|
||||
|
||||
struct bm_touch {
|
||||
uint32_t time;
|
||||
uint32_t serial;
|
||||
struct bm_touch_point points[2];
|
||||
};
|
||||
|
||||
/**
|
||||
* Colorable element constants.
|
||||
*
|
||||
@ -486,6 +550,22 @@ BM_PUBLIC void bm_menu_set_cursor_height(struct bm_menu *menu, uint32_t cursor_h
|
||||
*/
|
||||
BM_PUBLIC uint32_t bm_menu_get_cursor_height(struct bm_menu *menu);
|
||||
|
||||
/**
|
||||
* Get with of menu in pixels.
|
||||
*
|
||||
* @param menu bm_menu instance where to get line height.
|
||||
* @return uint32_t for max amount the menu height.
|
||||
*/
|
||||
BM_PUBLIC uint32_t bm_menu_get_height(struct bm_menu *menu);
|
||||
|
||||
/**
|
||||
* Get with of menu in pixels.
|
||||
*
|
||||
* @param menu bm_menu instance where to get line width.
|
||||
* @return uint32_t for max amount the menu width.
|
||||
*/
|
||||
BM_PUBLIC uint32_t bm_menu_get_width(struct bm_menu *menu);
|
||||
|
||||
/**
|
||||
* Set a hexadecimal color for element.
|
||||
*
|
||||
@ -809,15 +889,44 @@ BM_PUBLIC void bm_menu_filter(struct bm_menu *menu);
|
||||
*/
|
||||
BM_PUBLIC enum bm_key bm_menu_poll_key(struct bm_menu *menu, uint32_t *out_unicode);
|
||||
|
||||
/**
|
||||
* Poll pointer and unicode from underlying UI toolkit.
|
||||
*
|
||||
* This function will block on **curses** renderer.
|
||||
*
|
||||
* @param menu bm_menu instance from which to poll.
|
||||
* @return bm_pointer for polled pointer.
|
||||
*/
|
||||
BM_PUBLIC struct bm_pointer bm_menu_poll_pointer(struct bm_menu *menu);
|
||||
|
||||
/**
|
||||
* Poll touch and unicode from underlying UI toolkit.
|
||||
*
|
||||
* This function will block on **curses** renderer.
|
||||
*
|
||||
* @param menu bm_menu instance from which to poll.
|
||||
* @return bm_touch for polled touch.
|
||||
*/
|
||||
BM_PUBLIC struct bm_touch bm_menu_poll_touch(struct bm_menu *menu);
|
||||
|
||||
/**
|
||||
* Enforce a release of the touches.
|
||||
*
|
||||
* @param menu bm_menu instance from which to poll.
|
||||
*/
|
||||
BM_PUBLIC void bm_menu_release_touch(struct bm_menu *menu);
|
||||
|
||||
/**
|
||||
* Advances menu logic with key and unicode as input.
|
||||
*
|
||||
* @param menu bm_menu instance to be advanced.
|
||||
* @param key Key input that will advance menu logic.
|
||||
* @param pointer Pointer input that will advance menu logic.
|
||||
* @param touch Touch input that will advance menu logic.
|
||||
* @param unicode Unicode input that will advance menu logic.
|
||||
* @return bm_run_result for menu state.
|
||||
*/
|
||||
BM_PUBLIC enum bm_run_result bm_menu_run_with_key(struct bm_menu *menu, enum bm_key key, uint32_t unicode);
|
||||
BM_PUBLIC enum bm_run_result bm_menu_run_with_events(struct bm_menu *menu, enum bm_key key, struct bm_pointer pointer, struct bm_touch touch, uint32_t unicode);
|
||||
|
||||
/** @} Menu Logic */
|
||||
|
||||
|
@ -66,12 +66,40 @@ struct render_api {
|
||||
*/
|
||||
uint32_t (*get_displayed_count)(const struct bm_menu *menu);
|
||||
|
||||
/**
|
||||
* Get height by the underlying renderer;
|
||||
*/
|
||||
uint32_t (*get_height)(const struct bm_menu *menu);
|
||||
|
||||
/**
|
||||
* Get width by the underlying renderer;
|
||||
*/
|
||||
uint32_t (*get_width)(const struct bm_menu *menu);
|
||||
|
||||
/**
|
||||
* If the underlying renderer is a UI toolkit. (curses, etc...)
|
||||
* There might be possibility to get user input, and this should be thus implemented.
|
||||
*/
|
||||
enum bm_key (*poll_key)(const struct bm_menu *menu, uint32_t *unicode);
|
||||
|
||||
/**
|
||||
* If the underlying renderer is a UI toolkit. (curses, etc...)
|
||||
* There might be possibility to get user pointer, and this should be thus implemented.
|
||||
*/
|
||||
struct bm_pointer (*poll_pointer)(const struct bm_menu *menu);
|
||||
|
||||
/**
|
||||
* If the underlying renderer is a UI toolkit. (curses, etc...)
|
||||
* There might be possibility to get user touch, and this should be thus implemented.
|
||||
*/
|
||||
struct bm_touch (*poll_touch)(const struct bm_menu *menu);
|
||||
|
||||
/**
|
||||
* Enforce a release of the touches
|
||||
* There might be possibility to get user touch, and this should be thus implemented.
|
||||
*/
|
||||
void (*release_touch)(const struct bm_menu *menu);
|
||||
|
||||
/**
|
||||
* Tells underlying renderer to draw the menu.
|
||||
*/
|
||||
|
264
lib/menu.c
264
lib/menu.c
@ -293,6 +293,7 @@ uint32_t
|
||||
bm_menu_get_line_height(struct bm_menu *menu)
|
||||
{
|
||||
assert(menu);
|
||||
|
||||
return menu->line_height;
|
||||
}
|
||||
|
||||
@ -310,6 +311,34 @@ bm_menu_get_cursor_height(struct bm_menu *menu)
|
||||
return menu->cursor_height;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
bm_menu_get_height(struct bm_menu *menu)
|
||||
{
|
||||
assert(menu);
|
||||
|
||||
uint32_t height = 0;
|
||||
|
||||
if (menu->renderer->api.get_height) {
|
||||
height = menu->renderer->api.get_height(menu);
|
||||
}
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
bm_menu_get_width(struct bm_menu *menu)
|
||||
{
|
||||
assert(menu);
|
||||
|
||||
uint32_t width = 0;
|
||||
|
||||
if (menu->renderer->api.get_width) {
|
||||
width = menu->renderer->api.get_width(menu);
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
bool
|
||||
bm_menu_set_color(struct bm_menu *menu, enum bm_color color, const char *hex)
|
||||
{
|
||||
@ -707,6 +736,41 @@ bm_menu_poll_key(struct bm_menu *menu, uint32_t *out_unicode)
|
||||
return key;
|
||||
}
|
||||
|
||||
struct bm_pointer
|
||||
bm_menu_poll_pointer(struct bm_menu *menu)
|
||||
{
|
||||
assert(menu);
|
||||
|
||||
struct bm_pointer pointer = {0};
|
||||
|
||||
if (menu->renderer->api.poll_pointer)
|
||||
pointer = menu->renderer->api.poll_pointer(menu);
|
||||
|
||||
return pointer;
|
||||
}
|
||||
|
||||
struct bm_touch
|
||||
bm_menu_poll_touch(struct bm_menu *menu)
|
||||
{
|
||||
assert(menu);
|
||||
|
||||
struct bm_touch touch = {0};
|
||||
|
||||
if (menu->renderer->api.poll_touch)
|
||||
touch = menu->renderer->api.poll_touch(menu);
|
||||
|
||||
return touch;
|
||||
}
|
||||
|
||||
void
|
||||
bm_menu_release_touch(struct bm_menu *menu)
|
||||
{
|
||||
assert(menu);
|
||||
|
||||
if (menu->renderer->api.release_touch)
|
||||
menu->renderer->api.release_touch(menu);
|
||||
}
|
||||
|
||||
static void
|
||||
menu_next(struct bm_menu *menu, uint32_t count, bool wrap)
|
||||
{
|
||||
@ -727,6 +791,41 @@ menu_prev(struct bm_menu *menu, uint32_t count, bool wrap)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
menu_point_select(struct bm_menu *menu, uint32_t posx, uint32_t posy, uint32_t displayed)
|
||||
{
|
||||
(void) posx;
|
||||
uint32_t selected_line = posy / (bm_menu_get_height(menu) / displayed);
|
||||
uint16_t current_page_index = menu->index / menu->lines;
|
||||
|
||||
if (0 == selected_line) { // Mouse over title bar
|
||||
return;
|
||||
}
|
||||
|
||||
if (selected_line >= displayed) { // This might be useless
|
||||
return;
|
||||
}
|
||||
|
||||
menu->index = current_page_index * menu->lines + (selected_line - 1);
|
||||
}
|
||||
|
||||
static void
|
||||
menu_scroll_down(struct bm_menu *menu, uint16_t count)
|
||||
{
|
||||
if (menu->index / menu->lines != count / menu->lines) { // not last page
|
||||
menu->index = ((menu->index / menu->lines) + 1) * menu->lines;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
menu_scroll_up(struct bm_menu *menu, uint16_t count)
|
||||
{
|
||||
(void) count;
|
||||
if (menu->index / menu->lines) { // not first page
|
||||
menu->index = ((menu->index / menu->lines) - 1) * menu->lines + menu->lines - 1;
|
||||
}
|
||||
}
|
||||
|
||||
enum bm_run_result
|
||||
bm_menu_run_with_key(struct bm_menu *menu, enum bm_key key, uint32_t unicode)
|
||||
{
|
||||
@ -954,4 +1053,169 @@ bm_menu_run_with_key(struct bm_menu *menu, enum bm_key key, uint32_t unicode)
|
||||
return BM_RUN_RESULT_RUNNING;
|
||||
}
|
||||
|
||||
enum bm_run_result
|
||||
bm_menu_run_with_pointer(struct bm_menu *menu, struct bm_pointer pointer, uint32_t unicode)
|
||||
{
|
||||
(void) unicode;
|
||||
uint32_t count;
|
||||
bm_menu_get_filtered_items(menu, &count);
|
||||
|
||||
uint32_t displayed = 0;
|
||||
if (menu->renderer->api.get_displayed_count)
|
||||
displayed = menu->renderer->api.get_displayed_count(menu);
|
||||
|
||||
if (!displayed)
|
||||
displayed = count;
|
||||
|
||||
if (!menu->lines) {
|
||||
if (pointer.axes[BM_POINTER_AXIS_VERTICAL].valid) {
|
||||
if (0 < pointer.axes[BM_POINTER_AXIS_VERTICAL].value) {
|
||||
menu_next(menu, count, menu->wrap);
|
||||
} else {
|
||||
menu_prev(menu, count, menu->wrap);
|
||||
}
|
||||
}
|
||||
if (pointer.event_mask & POINTER_EVENT_BUTTON && pointer.state == POINTER_STATE_PRESSED) {
|
||||
switch (pointer.button) {
|
||||
case BM_POINTER_KEY_PRIMARY:
|
||||
{
|
||||
struct bm_item *highlighted = bm_menu_get_highlighted_item(menu);
|
||||
if (highlighted && !bm_menu_item_is_selected(menu, highlighted))
|
||||
list_add_item(&menu->selection, highlighted);
|
||||
}
|
||||
return BM_RUN_RESULT_SELECTED;
|
||||
}
|
||||
}
|
||||
return BM_RUN_RESULT_RUNNING;
|
||||
}
|
||||
|
||||
if (pointer.axes[BM_POINTER_AXIS_VERTICAL].valid) {
|
||||
if (0 < pointer.axes[BM_POINTER_AXIS_VERTICAL].value) {
|
||||
menu_scroll_down(menu, count);
|
||||
} else {
|
||||
menu_scroll_up(menu, count);
|
||||
}
|
||||
}
|
||||
|
||||
if (pointer.event_mask & POINTER_EVENT_MOTION) {
|
||||
menu_point_select(menu, pointer.pos_x, pointer.pos_y, displayed);
|
||||
}
|
||||
|
||||
if (pointer.event_mask & POINTER_EVENT_BUTTON && pointer.state == POINTER_STATE_PRESSED) {
|
||||
switch (pointer.button) {
|
||||
case BM_POINTER_KEY_PRIMARY:
|
||||
{
|
||||
struct bm_item *highlighted = bm_menu_get_highlighted_item(menu);
|
||||
if (highlighted && !bm_menu_item_is_selected(menu, highlighted))
|
||||
list_add_item(&menu->selection, highlighted);
|
||||
}
|
||||
return BM_RUN_RESULT_SELECTED;
|
||||
}
|
||||
}
|
||||
|
||||
return BM_RUN_RESULT_RUNNING;
|
||||
}
|
||||
|
||||
enum bm_run_result
|
||||
bm_menu_run_with_touch(struct bm_menu *menu, struct bm_touch touch, uint32_t unicode)
|
||||
{
|
||||
(void) unicode;
|
||||
uint32_t count;
|
||||
bm_menu_get_filtered_items(menu, &count);
|
||||
|
||||
uint32_t displayed = 0;
|
||||
if (menu->renderer->api.get_displayed_count)
|
||||
displayed = menu->renderer->api.get_displayed_count(menu);
|
||||
|
||||
if (!displayed)
|
||||
displayed = count;
|
||||
|
||||
if (!menu->lines) {
|
||||
// Not implemented yet
|
||||
return BM_RUN_RESULT_RUNNING;
|
||||
}
|
||||
|
||||
uint16_t count_down = 0;
|
||||
for (size_t i = 0; i < 2; ++i) {
|
||||
struct bm_touch_point point = touch.points[i];
|
||||
if (point.event_mask & TOUCH_EVENT_DOWN) {
|
||||
count_down += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (count_down == 2) {
|
||||
int16_t scroll_count = 0;
|
||||
int16_t scroll_directions[2];
|
||||
int16_t distance_trigger = displayed * bm_menu_get_line_height(menu) / 4;
|
||||
for (size_t i = 0; i < 2; ++i) {
|
||||
struct bm_touch_point point = touch.points[i];
|
||||
if (!(point.event_mask & TOUCH_EVENT_DOWN))
|
||||
continue;
|
||||
|
||||
int32_t movement_y = point.pos_y - point.start_y;
|
||||
if (abs(movement_y) > distance_trigger) {
|
||||
scroll_directions[i] = movement_y / abs(movement_y);
|
||||
scroll_count++;
|
||||
}
|
||||
}
|
||||
|
||||
int16_t scroll_direction_sum = scroll_directions[0] + scroll_directions[1];
|
||||
if (2 == abs(scroll_direction_sum)) {
|
||||
uint16_t current_page = menu->index / menu->lines;
|
||||
if (scroll_direction_sum < 0 && current_page != count / menu->lines) { // not already the first page
|
||||
menu_scroll_down(menu, count);
|
||||
bm_menu_release_touch(menu);
|
||||
} else if (scroll_direction_sum > 0 && current_page) { // not already the first page
|
||||
menu_scroll_up(menu, count);
|
||||
bm_menu_release_touch(menu);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count_down != 1)
|
||||
return BM_RUN_RESULT_RUNNING;
|
||||
|
||||
for (size_t i = 0; i < 2; ++i) {
|
||||
struct bm_touch_point point = touch.points[i];
|
||||
if (!(point.event_mask & TOUCH_EVENT_DOWN))
|
||||
continue;
|
||||
|
||||
menu_point_select(menu, point.pos_x, point.pos_y, displayed);
|
||||
|
||||
if (point.event_mask & TOUCH_EVENT_UP) {
|
||||
if (point.pos_y < (int32_t) (bm_menu_get_height(menu) / displayed)) {
|
||||
menu_scroll_up(menu, count);
|
||||
} else if ((uint32_t) point.pos_y > bm_menu_get_height(menu)) {
|
||||
menu_scroll_down(menu, count);
|
||||
} else if (point.pos_x > 0
|
||||
&& (uint32_t) point.pos_x < bm_menu_get_width(menu)) {
|
||||
{
|
||||
struct bm_item *highlighted = bm_menu_get_highlighted_item(menu);
|
||||
if (highlighted && !bm_menu_item_is_selected(menu, highlighted))
|
||||
list_add_item(&menu->selection, highlighted);
|
||||
}
|
||||
return BM_RUN_RESULT_SELECTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
return BM_RUN_RESULT_RUNNING;
|
||||
}
|
||||
|
||||
enum bm_run_result
|
||||
bm_menu_run_with_events(struct bm_menu *menu, enum bm_key key,
|
||||
struct bm_pointer pointer, struct bm_touch touch, uint32_t unicode)
|
||||
{
|
||||
enum bm_run_result key_result = bm_menu_run_with_key(menu, key, unicode);
|
||||
if (key_result != BM_RUN_RESULT_RUNNING) {
|
||||
return key_result;
|
||||
}
|
||||
|
||||
enum bm_run_result pointer_result = bm_menu_run_with_pointer(menu, pointer, unicode);
|
||||
if (pointer_result != BM_RUN_RESULT_RUNNING) {
|
||||
return pointer_result;
|
||||
}
|
||||
|
||||
return bm_menu_run_with_touch(menu, touch, unicode);
|
||||
}
|
||||
|
||||
/* vim: set ts=8 sw=4 tw=0 :*/
|
||||
|
@ -201,6 +201,258 @@ keyboard_handle_repeat_info(void *data, struct wl_keyboard *keyboard, int32_t ra
|
||||
set_repeat_info(data, rate, delay);
|
||||
}
|
||||
|
||||
static void
|
||||
pointer_handle_enter(void *data, struct wl_pointer *wl_pointer,
|
||||
uint32_t serial, struct wl_surface *surface,
|
||||
wl_fixed_t surface_x, wl_fixed_t surface_y)
|
||||
{
|
||||
(void)wl_pointer, (void)surface;
|
||||
struct input *input = data;
|
||||
input->pointer_event.event_mask |= POINTER_EVENT_ENTER;
|
||||
input->pointer_event.serial = serial;
|
||||
input->pointer_event.surface_x = surface_x,
|
||||
input->pointer_event.surface_y = surface_y;
|
||||
}
|
||||
|
||||
static void
|
||||
pointer_handle_leave(void *data, struct wl_pointer *wl_pointer,
|
||||
uint32_t serial, struct wl_surface *surface)
|
||||
{
|
||||
(void)wl_pointer, (void)surface;
|
||||
struct input *input = data;
|
||||
input->pointer_event.serial = serial;
|
||||
input->pointer_event.event_mask |= POINTER_EVENT_LEAVE;
|
||||
}
|
||||
|
||||
static void
|
||||
pointer_handle_motion(void *data, struct wl_pointer *wl_pointer, uint32_t time,
|
||||
wl_fixed_t surface_x, wl_fixed_t surface_y)
|
||||
{
|
||||
(void)wl_pointer;
|
||||
struct input *input = data;
|
||||
input->pointer_event.event_mask |= POINTER_EVENT_MOTION;
|
||||
input->pointer_event.time = time;
|
||||
input->pointer_event.surface_x = surface_x,
|
||||
input->pointer_event.surface_y = surface_y;
|
||||
}
|
||||
|
||||
static void
|
||||
pointer_handle_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial,
|
||||
uint32_t time, uint32_t button, uint32_t state)
|
||||
{
|
||||
(void)wl_pointer;
|
||||
struct input *input = data;
|
||||
input->pointer_event.event_mask |= POINTER_EVENT_BUTTON;
|
||||
input->pointer_event.time = time;
|
||||
input->pointer_event.serial = serial;
|
||||
input->pointer_event.button = button,
|
||||
input->pointer_event.state |= state;
|
||||
}
|
||||
|
||||
static void
|
||||
pointer_handle_axis(void *data, struct wl_pointer *wl_pointer, uint32_t time,
|
||||
uint32_t axis, wl_fixed_t value)
|
||||
{
|
||||
(void)wl_pointer;
|
||||
struct input *input = data;
|
||||
input->pointer_event.event_mask |= POINTER_EVENT_AXIS;
|
||||
input->pointer_event.time = time;
|
||||
input->pointer_event.axes[axis].valid = true;
|
||||
input->pointer_event.axes[axis].value = value;
|
||||
}
|
||||
|
||||
static void
|
||||
pointer_handle_axis_source(void *data, struct wl_pointer *wl_pointer,
|
||||
uint32_t axis_source)
|
||||
{
|
||||
(void)wl_pointer;
|
||||
struct input *input = data;
|
||||
input->pointer_event.event_mask |= POINTER_EVENT_AXIS_SOURCE;
|
||||
input->pointer_event.axis_source = axis_source;
|
||||
}
|
||||
|
||||
static void
|
||||
pointer_handle_axis_stop(void *data, struct wl_pointer *wl_pointer,
|
||||
uint32_t time, uint32_t axis)
|
||||
{
|
||||
(void)wl_pointer;
|
||||
struct input *input = data;
|
||||
input->pointer_event.time = time;
|
||||
input->pointer_event.event_mask |= POINTER_EVENT_AXIS_STOP;
|
||||
input->pointer_event.axes[axis].valid = true;
|
||||
}
|
||||
|
||||
static void
|
||||
pointer_handle_axis_discrete(void *data, struct wl_pointer *wl_pointer,
|
||||
uint32_t axis, int32_t discrete)
|
||||
{
|
||||
(void)wl_pointer;
|
||||
struct input *input = data;
|
||||
input->pointer_event.event_mask |= POINTER_EVENT_AXIS_DISCRETE;
|
||||
input->pointer_event.axes[axis].valid = true;
|
||||
input->pointer_event.axes[axis].discrete = discrete;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
pointer_handle_frame(void *data, struct wl_pointer *wl_pointer)
|
||||
{
|
||||
(void) data, (void) wl_pointer;
|
||||
}
|
||||
|
||||
static struct touch_point *
|
||||
get_touch_point(struct input *input, int32_t id)
|
||||
{
|
||||
struct touch_event *touch = &input->touch_event;
|
||||
int invalid = -1;
|
||||
for (size_t i = 0; i < 2; ++i) {
|
||||
if (touch->points[i].id == id) {
|
||||
invalid = i;
|
||||
}
|
||||
if (invalid == -1 && !touch->points[i].valid) {
|
||||
invalid = i;
|
||||
}
|
||||
}
|
||||
if (invalid == -1) {
|
||||
return NULL;
|
||||
}
|
||||
touch->points[invalid].id = id;
|
||||
return &touch->points[invalid];
|
||||
}
|
||||
|
||||
static void
|
||||
reset_all_start_position(struct input *input)
|
||||
{
|
||||
struct touch_event *event = &input->touch_event;
|
||||
for (size_t i = 0; i < 2; ++i) {
|
||||
struct touch_point *point = &event->points[i];
|
||||
|
||||
if (!point->valid)
|
||||
continue;
|
||||
|
||||
point->surface_start_x = point->surface_x;
|
||||
point->surface_start_y = point->surface_y;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
revalidate_all_released(struct input *input)
|
||||
{
|
||||
struct touch_event *event = &input->touch_event;
|
||||
for (size_t i = 0; i < 2; ++i) {
|
||||
struct touch_point *point = &event->points[i];
|
||||
|
||||
if (!point->valid && point->event_mask & TOUCH_EVENT_DOWN)
|
||||
point->valid = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
touch_handle_down(void *data, struct wl_touch *wl_touch, uint32_t serial,
|
||||
uint32_t time, struct wl_surface *surface, int32_t id,
|
||||
wl_fixed_t x, wl_fixed_t y)
|
||||
{
|
||||
(void) wl_touch, (void) surface;
|
||||
struct input *input = data;
|
||||
struct touch_point *point = get_touch_point(input, id);
|
||||
if (point == NULL) {
|
||||
return;
|
||||
}
|
||||
point->valid = true;
|
||||
point->event_mask = TOUCH_EVENT_DOWN;
|
||||
point->surface_x = x,
|
||||
point->surface_y = y;
|
||||
input->touch_event.time = time;
|
||||
input->touch_event.serial = serial;
|
||||
input->touch_event.active += 1;
|
||||
|
||||
revalidate_all_released(input);
|
||||
reset_all_start_position(input);
|
||||
}
|
||||
|
||||
static void
|
||||
touch_handle_up(void *data, struct wl_touch *wl_touch, uint32_t serial,
|
||||
uint32_t time, int32_t id)
|
||||
{
|
||||
(void) time, (void) wl_touch, (void) serial;
|
||||
struct input *input = data;
|
||||
struct touch_point *point = get_touch_point(input, id);
|
||||
if (point == NULL) {
|
||||
return;
|
||||
}
|
||||
point->event_mask |= TOUCH_EVENT_UP;
|
||||
input->touch_event.active -= 1;
|
||||
|
||||
reset_all_start_position(input);
|
||||
}
|
||||
|
||||
static void
|
||||
touch_handle_motion(void *data, struct wl_touch *wl_touch, uint32_t time,
|
||||
int32_t id, wl_fixed_t x, wl_fixed_t y)
|
||||
{
|
||||
(void) wl_touch;
|
||||
struct input *input = data;
|
||||
struct touch_point *point = get_touch_point(input, id);
|
||||
if (point == NULL) {
|
||||
return;
|
||||
}
|
||||
point->event_mask |= TOUCH_EVENT_MOTION;
|
||||
point->surface_x = x, point->surface_y = y;
|
||||
input->touch_event.time = time;
|
||||
}
|
||||
|
||||
static void
|
||||
touch_handle_cancel(void *data, struct wl_touch *wl_touch)
|
||||
{
|
||||
(void) wl_touch, (void) data;
|
||||
}
|
||||
|
||||
static void
|
||||
touch_handle_shape(void *data, struct wl_touch *wl_touch,
|
||||
int32_t id, wl_fixed_t major, wl_fixed_t minor)
|
||||
{
|
||||
(void) wl_touch;
|
||||
struct input *input = data;
|
||||
struct touch_point *point = get_touch_point(input, id);
|
||||
if (point == NULL) {
|
||||
return;
|
||||
}
|
||||
point->event_mask |= TOUCH_EVENT_SHAPE;
|
||||
point->major = major, point->minor = minor;
|
||||
}
|
||||
|
||||
static void
|
||||
touch_handle_orientation(void *data, struct wl_touch *wl_touch,
|
||||
int32_t id, wl_fixed_t orientation)
|
||||
{
|
||||
(void) wl_touch;
|
||||
struct input *input = data;
|
||||
struct touch_point *point = get_touch_point(input, id);
|
||||
if (point == NULL) {
|
||||
return;
|
||||
}
|
||||
point->event_mask |= TOUCH_EVENT_ORIENTATION;
|
||||
point->orientation = orientation;
|
||||
}
|
||||
|
||||
static void
|
||||
touch_handle_frame(void *data, struct wl_touch *wl_touch)
|
||||
{
|
||||
(void) data, (void) wl_touch;
|
||||
}
|
||||
|
||||
static const struct wl_pointer_listener pointer_listener = {
|
||||
.enter = pointer_handle_enter,
|
||||
.leave = pointer_handle_leave,
|
||||
.motion = pointer_handle_motion,
|
||||
.button = pointer_handle_button,
|
||||
.axis = pointer_handle_axis,
|
||||
.frame = pointer_handle_frame,
|
||||
.axis_source = pointer_handle_axis_source,
|
||||
.axis_stop = pointer_handle_axis_stop,
|
||||
.axis_discrete = pointer_handle_axis_discrete,
|
||||
};
|
||||
|
||||
static const struct wl_keyboard_listener keyboard_listener = {
|
||||
.keymap = keyboard_handle_keymap,
|
||||
.enter = keyboard_handle_enter,
|
||||
@ -210,19 +462,46 @@ static const struct wl_keyboard_listener keyboard_listener = {
|
||||
.repeat_info = keyboard_handle_repeat_info
|
||||
};
|
||||
|
||||
static const struct wl_touch_listener wl_touch_listener = {
|
||||
.down = touch_handle_down,
|
||||
.up = touch_handle_up,
|
||||
.motion = touch_handle_motion,
|
||||
.frame = touch_handle_frame,
|
||||
.cancel = touch_handle_cancel,
|
||||
.shape = touch_handle_shape,
|
||||
.orientation = touch_handle_orientation,
|
||||
};
|
||||
|
||||
static void
|
||||
seat_handle_capabilities(void *data, struct wl_seat *seat, enum wl_seat_capability caps)
|
||||
{
|
||||
struct input *input = data;
|
||||
|
||||
if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->seat) {
|
||||
if (!input->seat) {
|
||||
input->seat = seat;
|
||||
}
|
||||
|
||||
if (caps & WL_SEAT_CAPABILITY_KEYBOARD) {
|
||||
input->keyboard = wl_seat_get_keyboard(seat);
|
||||
wl_keyboard_add_listener(input->keyboard, &keyboard_listener, data);
|
||||
} else if (seat == input->seat && !(caps & WL_SEAT_CAPABILITY_KEYBOARD)) {
|
||||
}
|
||||
|
||||
if (caps & WL_SEAT_CAPABILITY_POINTER) {
|
||||
input->pointer = wl_seat_get_pointer(seat);
|
||||
wl_pointer_add_listener(input->pointer, &pointer_listener, data);
|
||||
}
|
||||
|
||||
if (caps & WL_SEAT_CAPABILITY_TOUCH) {
|
||||
input->touch = wl_seat_get_touch(seat);
|
||||
wl_touch_add_listener(input->touch, &wl_touch_listener, data);
|
||||
}
|
||||
|
||||
if (seat == input->seat && !(caps & WL_SEAT_CAPABILITY_KEYBOARD) && !(caps & WL_SEAT_CAPABILITY_POINTER)) {
|
||||
wl_keyboard_destroy(input->keyboard);
|
||||
input->seat = NULL;
|
||||
input->keyboard = NULL;
|
||||
input->pointer = NULL;
|
||||
input->touch = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,9 @@ render(const struct bm_menu *menu)
|
||||
}
|
||||
}
|
||||
|
||||
if (wayland->input.code != wayland->input.last_code) {
|
||||
if (wayland->input.code != wayland->input.last_code ||
|
||||
wayland->input.touch_event.active ||
|
||||
wayland->input.pointer_event.event_mask) {
|
||||
wl_list_for_each(window, &wayland->windows, link) {
|
||||
bm_wl_window_schedule_render(window);
|
||||
}
|
||||
@ -217,6 +219,96 @@ poll_key(const struct bm_menu *menu, unsigned int *unicode)
|
||||
return BM_KEY_UNICODE;
|
||||
}
|
||||
|
||||
struct bm_pointer
|
||||
poll_pointer(const struct bm_menu *menu)
|
||||
{
|
||||
struct wayland *wayland = menu->renderer->internal;
|
||||
struct input *input = &wayland->input;
|
||||
struct pointer_event *event = &input->pointer_event;
|
||||
assert(wayland && event);
|
||||
|
||||
struct bm_pointer bm_pointer;
|
||||
|
||||
bm_pointer.event_mask = event->event_mask;
|
||||
bm_pointer.pos_x = wl_fixed_to_int(event->surface_x);
|
||||
bm_pointer.pos_y = wl_fixed_to_int(event->surface_y);
|
||||
bm_pointer.time = event->time;
|
||||
bm_pointer.axes[0].valid = event->axes[0].valid;
|
||||
bm_pointer.axes[0].value = event->axes[0].value;
|
||||
bm_pointer.axes[0].discrete = event->axes[0].discrete;
|
||||
bm_pointer.axes[1].valid = event->axes[1].valid;
|
||||
bm_pointer.axes[1].value = event->axes[1].value;
|
||||
bm_pointer.axes[1].discrete = event->axes[1].discrete;
|
||||
bm_pointer.axis_source = event->axis_source;
|
||||
|
||||
bm_pointer.button = BM_POINTER_KEY_NONE;
|
||||
switch (event->button) {
|
||||
case BTN_LEFT:
|
||||
bm_pointer.button = BM_POINTER_KEY_PRIMARY;
|
||||
break;
|
||||
}
|
||||
|
||||
if (event->state & WL_POINTER_BUTTON_STATE_PRESSED) {
|
||||
bm_pointer.state |= POINTER_STATE_PRESSED;
|
||||
}
|
||||
if (event->state & WL_POINTER_BUTTON_STATE_RELEASED) {
|
||||
bm_pointer.state |= POINTER_STATE_RELEASED;
|
||||
}
|
||||
|
||||
memset(event, 0, sizeof(*event));
|
||||
return bm_pointer;
|
||||
}
|
||||
|
||||
struct bm_touch
|
||||
poll_touch(const struct bm_menu *menu)
|
||||
{
|
||||
struct wayland *wayland = menu->renderer->internal;
|
||||
struct input *input = &wayland->input;
|
||||
struct touch_event *event = &input->touch_event;
|
||||
assert(wayland && event);
|
||||
|
||||
struct bm_touch bm_touch;
|
||||
|
||||
for (size_t i = 0; i < 2; ++i) {
|
||||
struct touch_point *point = &event->points[i];
|
||||
|
||||
if (!point->valid) {
|
||||
bm_touch.points[i].event_mask = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
bm_touch.points[i].event_mask = point->event_mask;
|
||||
bm_touch.points[i].pos_x = wl_fixed_to_int(point->surface_x);
|
||||
bm_touch.points[i].pos_y = wl_fixed_to_int(point->surface_y);
|
||||
bm_touch.points[i].start_x = wl_fixed_to_int(point->surface_start_x);
|
||||
bm_touch.points[i].start_y = wl_fixed_to_int(point->surface_start_y);
|
||||
bm_touch.points[i].major = point->major;
|
||||
bm_touch.points[i].minor = point->minor;
|
||||
bm_touch.points[i].orientation = point->orientation;
|
||||
|
||||
if (point->event_mask & TOUCH_EVENT_UP) {
|
||||
point->valid = false;
|
||||
point->event_mask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return bm_touch;
|
||||
}
|
||||
|
||||
void
|
||||
release_touch(const struct bm_menu *menu)
|
||||
{
|
||||
struct wayland *wayland = menu->renderer->internal;
|
||||
struct input *input = &wayland->input;
|
||||
struct touch_event *event = &input->touch_event;
|
||||
assert(wayland && event);
|
||||
|
||||
for (size_t i = 0; i < 2; ++i) {
|
||||
struct touch_point *point = &event->points[i];
|
||||
point->valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
get_displayed_count(const struct bm_menu *menu)
|
||||
{
|
||||
@ -231,6 +323,34 @@ get_displayed_count(const struct bm_menu *menu)
|
||||
return max;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
get_height(const struct bm_menu *menu)
|
||||
{
|
||||
struct wayland *wayland = menu->renderer->internal;
|
||||
assert(wayland);
|
||||
uint32_t max = 0;
|
||||
struct window *window;
|
||||
wl_list_for_each(window, &wayland->windows, link) {
|
||||
if (window->displayed > max)
|
||||
max = window->height;
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
get_width(const struct bm_menu *menu)
|
||||
{
|
||||
struct wayland *wayland = menu->renderer->internal;
|
||||
assert(wayland);
|
||||
uint32_t max = 0;
|
||||
struct window *window;
|
||||
wl_list_for_each(window, &wayland->windows, link) {
|
||||
if (window->displayed > max)
|
||||
max = window->width;
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
static void
|
||||
set_width(const struct bm_menu *menu, uint32_t margin, float factor)
|
||||
{
|
||||
@ -447,7 +567,12 @@ register_renderer(struct render_api *api)
|
||||
api->constructor = constructor;
|
||||
api->destructor = destructor;
|
||||
api->get_displayed_count = get_displayed_count;
|
||||
api->get_height = get_height;
|
||||
api->get_width = get_width;
|
||||
api->poll_key = poll_key;
|
||||
api->poll_pointer = poll_pointer;
|
||||
api->poll_touch = poll_touch;
|
||||
api->release_touch = release_touch;
|
||||
api->render = render;
|
||||
api->set_align = set_align;
|
||||
api->set_width = set_width;
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include <wayland-client.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <linux/input-event-codes.h>
|
||||
|
||||
#include "wlr-layer-shell-unstable-v1.h"
|
||||
#include "xdg-output-unstable-v1.h"
|
||||
@ -45,11 +46,46 @@ struct xkb {
|
||||
xkb_mod_mask_t masks[MASK_LAST];
|
||||
};
|
||||
|
||||
struct pointer_event {
|
||||
uint32_t event_mask;
|
||||
wl_fixed_t surface_x, surface_y;
|
||||
uint32_t button, state;
|
||||
uint32_t time;
|
||||
uint32_t serial;
|
||||
struct {
|
||||
bool valid;
|
||||
wl_fixed_t value;
|
||||
int32_t discrete;
|
||||
} axes[2];
|
||||
uint32_t axis_source;
|
||||
};
|
||||
|
||||
struct touch_point {
|
||||
bool valid;
|
||||
int32_t id;
|
||||
uint32_t event_mask;
|
||||
wl_fixed_t surface_x, surface_y;
|
||||
wl_fixed_t surface_start_x, surface_start_y;
|
||||
wl_fixed_t major, minor;
|
||||
wl_fixed_t orientation;
|
||||
};
|
||||
|
||||
struct touch_event {
|
||||
uint32_t time;
|
||||
uint32_t serial;
|
||||
uint16_t active;
|
||||
struct touch_point points[2];
|
||||
};
|
||||
|
||||
struct input {
|
||||
int *repeat_fd;
|
||||
|
||||
struct wl_seat *seat;
|
||||
struct wl_keyboard *keyboard;
|
||||
struct wl_pointer *pointer;
|
||||
struct wl_touch *touch;
|
||||
struct pointer_event pointer_event;
|
||||
struct touch_event touch_event;
|
||||
struct xkb xkb;
|
||||
|
||||
xkb_keysym_t sym;
|
||||
|
Loading…
Reference in New Issue
Block a user