mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-06-14 14:32:57 -04:00
backend/wscons: introduce new backend
This commit is contained in:
parent
f56f21b98f
commit
900ff30921
12 changed files with 1208 additions and 7 deletions
332
backend/wscons/backend.c
Normal file
332
backend/wscons/backend.c
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
#define _BSD_SOURCE
|
||||
#include <sys/ioctl.h>
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/event.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <wlr/backend/interface.h>
|
||||
#include <wlr/backend/session.h>
|
||||
#include <dev/wscons/wsconsio.h>
|
||||
#include <dev/wscons/wsksymdef.h>
|
||||
#include <wlr/interfaces/wlr_keyboard.h>
|
||||
#include <wlr/interfaces/wlr_pointer.h>
|
||||
|
||||
#include "backend/wscons.h"
|
||||
#include "util/time.h"
|
||||
|
||||
#include "atKeynames.h"
|
||||
#include "bsd_KbdMap.h"
|
||||
|
||||
static struct wlr_wscons_backend *get_wscons_backend_from_backend(
|
||||
struct wlr_backend *wlr_backend) {
|
||||
assert(wlr_backend_is_wscons(wlr_backend));
|
||||
struct wlr_wscons_backend *backend = wl_container_of(wlr_backend, backend, backend);
|
||||
return backend;
|
||||
}
|
||||
|
||||
static int ws_to_xkb(unsigned type, int key) {
|
||||
switch (type) {
|
||||
case WSKBD_TYPE_PC_XT:
|
||||
case WSKBD_TYPE_PC_AT:
|
||||
return wsXtMap[key];
|
||||
case WSKBD_TYPE_USB:
|
||||
return wsUsbMap[key];
|
||||
default:
|
||||
wlr_log(WLR_INFO, "Unknown wskbd type %d", type);
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
static int wsmouse_to_evdev(int button) {
|
||||
// The right and middle mouse buttons must be swapped
|
||||
switch (button) {
|
||||
case 1: // Middle
|
||||
return 0x112;
|
||||
case 2: // Right
|
||||
return 0x111;
|
||||
default:
|
||||
return button + 0x110;
|
||||
}
|
||||
}
|
||||
|
||||
static void notify_key(struct wlr_keyboard *wlr_kbd, uint32_t msec,
|
||||
uint32_t state, uint32_t keycode) {
|
||||
struct wlr_keyboard_key_event ev;
|
||||
ev.update_state = true;
|
||||
ev.time_msec = msec;
|
||||
ev.state = state;
|
||||
ev.keycode = keycode;
|
||||
|
||||
wlr_keyboard_notify_key(wlr_kbd, &ev);
|
||||
}
|
||||
|
||||
static void notify_button(struct wlr_pointer *wlr_ptr, uint32_t msec,
|
||||
uint32_t state, uint32_t button) {
|
||||
struct wlr_pointer_button_event ev;
|
||||
ev.pointer = wlr_ptr;
|
||||
ev.time_msec = msec;
|
||||
ev.button = button;
|
||||
ev.state = state;
|
||||
|
||||
wlr_pointer_notify_button(wlr_ptr, &ev);
|
||||
wl_signal_emit_mutable(&wlr_ptr->events.frame, wlr_ptr);
|
||||
}
|
||||
|
||||
static void notify_motion(struct wlr_pointer *wlr_ptr, uint32_t msec,
|
||||
double x, double y) {
|
||||
struct wlr_pointer_motion_event ev;
|
||||
ev.pointer = wlr_ptr;
|
||||
ev.time_msec = msec;
|
||||
ev.delta_x = x;
|
||||
ev.delta_y = y;
|
||||
ev.unaccel_dx = x;
|
||||
ev.unaccel_dy = y;
|
||||
|
||||
wl_signal_emit_mutable(&wlr_ptr->events.motion, &ev);
|
||||
wl_signal_emit_mutable(&wlr_ptr->events.frame, wlr_ptr);
|
||||
}
|
||||
|
||||
static void notify_axis(struct wlr_pointer *wlr_ptr, uint32_t msec,
|
||||
uint32_t axis, double delta) {
|
||||
struct wlr_pointer_axis_event ev;
|
||||
ev.pointer = wlr_ptr;
|
||||
ev.time_msec = msec;
|
||||
ev.source = WL_POINTER_AXIS_SOURCE_WHEEL;
|
||||
ev.relative_direction = WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL;
|
||||
ev.delta_discrete = 0; // XXX
|
||||
ev.orientation = axis;
|
||||
ev.delta = delta;
|
||||
|
||||
wl_signal_emit_mutable(&wlr_ptr->events.axis, &ev);
|
||||
wl_signal_emit_mutable(&wlr_ptr->events.frame, wlr_ptr);
|
||||
}
|
||||
|
||||
static void notify_motion_abs(struct wlr_pointer *wlr_ptr, uint32_t msec,
|
||||
double x, double y) {
|
||||
struct wlr_pointer_motion_absolute_event ev;
|
||||
ev.pointer = wlr_ptr;
|
||||
ev.time_msec = msec;
|
||||
ev.x = x;
|
||||
ev.y = y;
|
||||
|
||||
wl_signal_emit_mutable(&wlr_ptr->events.motion_absolute, &ev);
|
||||
wl_signal_emit_mutable(&wlr_ptr->events.frame, wlr_ptr);
|
||||
}
|
||||
|
||||
static void handle_event(struct wlr_wscons_backend *backend, struct wscons_event *ws_ev) {
|
||||
struct wlr_keyboard *wlr_kbd = &backend->kbd;
|
||||
struct wlr_pointer *wlr_ptr = &backend->mouse;
|
||||
|
||||
uint32_t msec = timespec_to_msec(&ws_ev->time);
|
||||
// TODO: make sure all types are handled
|
||||
switch (ws_ev->type) {
|
||||
case WSCONS_EVENT_KEY_UP:
|
||||
notify_key(wlr_kbd, msec, WL_KEYBOARD_KEY_STATE_RELEASED,
|
||||
ws_to_xkb(backend->kbd_type, ws_ev->value));
|
||||
break;
|
||||
case WSCONS_EVENT_KEY_DOWN:
|
||||
notify_key(wlr_kbd, msec, WL_KEYBOARD_KEY_STATE_PRESSED,
|
||||
ws_to_xkb(backend->kbd_type, ws_ev->value));
|
||||
break;
|
||||
case WSCONS_EVENT_MOUSE_UP:
|
||||
notify_button(wlr_ptr, msec, WL_POINTER_BUTTON_STATE_RELEASED,
|
||||
wsmouse_to_evdev(ws_ev->value));
|
||||
break;
|
||||
case WSCONS_EVENT_MOUSE_DOWN:
|
||||
notify_button(wlr_ptr, msec, WL_POINTER_BUTTON_STATE_PRESSED,
|
||||
wsmouse_to_evdev(ws_ev->value));
|
||||
break;
|
||||
case WSCONS_EVENT_MOUSE_DELTA_X:
|
||||
notify_motion(wlr_ptr, msec, ws_ev->value, 0);
|
||||
break;
|
||||
case WSCONS_EVENT_MOUSE_DELTA_Y:
|
||||
notify_motion(wlr_ptr, msec, 0, -ws_ev->value);
|
||||
break;
|
||||
case WSCONS_EVENT_MOUSE_DELTA_Z:
|
||||
notify_axis(wlr_ptr, msec, WL_POINTER_AXIS_VERTICAL_SCROLL,
|
||||
ws_ev->value * 10);
|
||||
break;
|
||||
case WSCONS_EVENT_MOUSE_DELTA_W:
|
||||
notify_axis(wlr_ptr, msec, WL_POINTER_AXIS_HORIZONTAL_SCROLL,
|
||||
ws_ev->value * 10);
|
||||
break;
|
||||
case WSCONS_EVENT_MOUSE_ABSOLUTE_X:
|
||||
notify_motion_abs(wlr_ptr, msec, ws_ev->value, 0);
|
||||
break;
|
||||
case WSCONS_EVENT_MOUSE_ABSOLUTE_Y:
|
||||
notify_motion_abs(wlr_ptr, msec, 0, -ws_ev->value);
|
||||
break;
|
||||
case WSCONS_EVENT_ALL_KEYS_UP:
|
||||
case WSCONS_EVENT_WSMOUSED_ON:
|
||||
case WSCONS_EVENT_WSMOUSED_OFF:
|
||||
break;
|
||||
default:
|
||||
wlr_log(WLR_DEBUG, "Unknown wscons event type: %x", ws_ev->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int handle_wscons_readable(int fd, uint32_t mask, void *_backend) {
|
||||
struct wlr_wscons_backend *backend = _backend;
|
||||
|
||||
while (backend->session->active) {
|
||||
struct kevent kq_ev;
|
||||
static const struct timespec dontblock = {0};
|
||||
if (kevent(fd, NULL, 0, &kq_ev, 1, &dontblock) <= 0) {
|
||||
return 0;
|
||||
}
|
||||
assert(kq_ev.filter == EVFILT_READ);
|
||||
int in_fd = kq_ev.ident;
|
||||
|
||||
struct wscons_event ws_ev;
|
||||
if (read(in_fd, &ws_ev, sizeof(ws_ev)) <= 0) {
|
||||
continue;
|
||||
}
|
||||
handle_event(backend, &ws_ev);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void keyboard_set_leds(struct wlr_keyboard *wlr_kb, uint32_t leds) {
|
||||
// TODO: use WSKBDIO_SETLEDS
|
||||
}
|
||||
|
||||
const struct wlr_keyboard_impl wscons_keyboard_impl = {
|
||||
.name = "wscons-keyboard",
|
||||
.led_update = keyboard_set_leds
|
||||
};
|
||||
|
||||
const struct wlr_pointer_impl wscons_pointer_impl = {
|
||||
.name = "wscons-pointer",
|
||||
};
|
||||
|
||||
static int init_wscons(struct wlr_wscons_backend *backend) {
|
||||
struct wlr_device *mouse_dev = wlr_session_open_file(backend->session, "/dev/wsmouse");
|
||||
struct wlr_device *kbd_dev = wlr_session_open_file(backend->session, "/dev/wskbd");
|
||||
if (!mouse_dev || !kbd_dev) {
|
||||
wlr_log(WLR_ERROR, "Failed to open input devices");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ioctl(kbd_dev->fd, WSKBDIO_GTYPE, &backend->kbd_type) == -1) {
|
||||
// TODO: free
|
||||
wlr_log(WLR_ERROR, "Failed to get keyboard type");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int kfd = kqueue1(O_CLOEXEC);
|
||||
if (kfd == -1) {
|
||||
// TODO: free
|
||||
wlr_log(WLR_ERROR, "Failed to create kqueue fd");
|
||||
return -1;
|
||||
}
|
||||
struct kevent evs[2];
|
||||
EV_SET(&evs[0], mouse_dev->fd, EVFILT_READ, EV_ADD, 0, 0, NULL);
|
||||
EV_SET(&evs[1], kbd_dev->fd, EVFILT_READ, EV_ADD, 0, 0, NULL);
|
||||
if (kevent(kfd, evs, sizeof(evs) / sizeof(evs[0]), NULL, 0, NULL) == -1) {
|
||||
// TODO: free
|
||||
wlr_log(WLR_ERROR, "Failed to setup kqueue");
|
||||
return -1;
|
||||
}
|
||||
|
||||
backend->mouse_dev = mouse_dev;
|
||||
backend->kbd_dev = kbd_dev;
|
||||
|
||||
struct wlr_keyboard *wlr_kbd = &backend->kbd;
|
||||
wlr_keyboard_init(wlr_kbd, &wscons_keyboard_impl, "wscons-keyboard");
|
||||
wl_signal_emit_mutable(&backend->backend.events.new_input, &wlr_kbd->base);
|
||||
|
||||
struct wlr_pointer *wlr_ptr = &backend->mouse;
|
||||
wlr_pointer_init(wlr_ptr, &wscons_pointer_impl, "wscons-pointer");
|
||||
wl_signal_emit_mutable(&backend->backend.events.new_input, &wlr_ptr->base);
|
||||
|
||||
return kfd;
|
||||
}
|
||||
|
||||
static bool backend_start(struct wlr_backend *wlr_backend) {
|
||||
struct wlr_wscons_backend *backend =
|
||||
get_wscons_backend_from_backend(wlr_backend);
|
||||
wlr_log(WLR_DEBUG, "Starting wscons backend");
|
||||
|
||||
int fd = init_wscons(backend);
|
||||
if (fd < 0) {
|
||||
wlr_log(WLR_ERROR, "Failed to initialize wscons backend");
|
||||
return false;
|
||||
}
|
||||
backend->kqueue_fd = fd;
|
||||
|
||||
if (backend->input_event) {
|
||||
wl_event_source_remove(backend->input_event);
|
||||
}
|
||||
backend->input_event = wl_event_loop_add_fd(backend->session->event_loop, fd,
|
||||
WL_EVENT_READABLE, handle_wscons_readable, backend);
|
||||
if (!backend->input_event) {
|
||||
wlr_log(WLR_ERROR, "Failed to create input event on event loop");
|
||||
return false;
|
||||
}
|
||||
wlr_log(WLR_DEBUG, "wscons successfully initialized");
|
||||
return true;
|
||||
}
|
||||
|
||||
static void backend_destroy(struct wlr_backend *wlr_backend) {
|
||||
if (!wlr_backend) {
|
||||
return;
|
||||
}
|
||||
struct wlr_wscons_backend *backend =
|
||||
get_wscons_backend_from_backend(wlr_backend);
|
||||
|
||||
wlr_backend_finish(wlr_backend);
|
||||
|
||||
wl_list_remove(&backend->session_destroy.link);
|
||||
|
||||
if (backend->input_event) {
|
||||
wl_event_source_remove(backend->input_event);
|
||||
}
|
||||
|
||||
close(backend->kqueue_fd);
|
||||
|
||||
if (backend->mouse_dev) {
|
||||
wlr_session_close_file(backend->session, backend->mouse_dev);
|
||||
}
|
||||
if (backend->kbd_dev) {
|
||||
wlr_session_close_file(backend->session, backend->kbd_dev);
|
||||
}
|
||||
|
||||
free(backend);
|
||||
}
|
||||
|
||||
static const struct wlr_backend_impl backend_impl = {
|
||||
.start = backend_start,
|
||||
.destroy = backend_destroy,
|
||||
};
|
||||
|
||||
bool wlr_backend_is_wscons(const struct wlr_backend *b) {
|
||||
return b->impl == &backend_impl;
|
||||
}
|
||||
|
||||
static void handle_session_destroy(struct wl_listener *listener, void *data) {
|
||||
struct wlr_wscons_backend *backend =
|
||||
wl_container_of(listener, backend, session_destroy);
|
||||
backend_destroy(&backend->backend);
|
||||
}
|
||||
|
||||
struct wlr_backend *wlr_wscons_backend_create(struct wlr_session *session) {
|
||||
struct wlr_wscons_backend *backend = calloc(1, sizeof(*backend));
|
||||
if (!backend) {
|
||||
wlr_log(WLR_ERROR, "Allocation failed: %s", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
wlr_backend_init(&backend->backend, &backend_impl);
|
||||
|
||||
backend->session = session;
|
||||
backend->kqueue_fd = -1;
|
||||
|
||||
backend->session_destroy.notify = handle_session_destroy;
|
||||
wl_signal_add(&session->events.destroy, &backend->session_destroy);
|
||||
|
||||
return &backend->backend;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue