@@ -51,7 +51,7 @@ Below is a summary of contributions upstreamed thus far.
|
|||||||
- [Add support for keypads to libinput driver] (✅ merged)
|
- [Add support for keypads to libinput driver] (✅ merged)
|
||||||
- [Add full keyboard support to libinput/evdev driver] (✅ merged)
|
- [Add full keyboard support to libinput/evdev driver] (✅ merged)
|
||||||
- [Automatic device discovery via libinput] (✅ merged)
|
- [Automatic device discovery via libinput] (✅ merged)
|
||||||
- [Make it possible to use multiple devices with the libinput and XKB drivers] (⏳ in review)
|
- [Make it possible to use multiple devices with the libinput and XKB drivers] (✅ merged)
|
||||||
|
|
||||||
# Usage
|
# Usage
|
||||||
|
|
||||||
|
189
indev.c
Normal file
189
indev.c
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2021 Johannes Marbach
|
||||||
|
*
|
||||||
|
* This file is part of unl0kr, hereafter referred to as the program.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "indev.h"
|
||||||
|
|
||||||
|
#include "cursor.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
#include "lv_drivers/indev/libinput_drv.h"
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MAX_KEYBOARD_DEVS 4
|
||||||
|
#define MAX_POINTER_DEVS 4
|
||||||
|
#define MAX_TOUCHSCREEN_DEVS 1
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static variables
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int num_keyboard_devs = 0;
|
||||||
|
static char *keyboard_devs[MAX_KEYBOARD_DEVS];
|
||||||
|
static lv_indev_t *keyboard_indevs[MAX_KEYBOARD_DEVS];
|
||||||
|
static lv_indev_drv_t keyboard_indev_drvs[MAX_KEYBOARD_DEVS];
|
||||||
|
static libinput_drv_state_t keyboard_drv_states[MAX_KEYBOARD_DEVS];
|
||||||
|
|
||||||
|
static int num_pointer_devs = 0;
|
||||||
|
static char *pointer_devs[MAX_POINTER_DEVS];
|
||||||
|
static lv_indev_t *pointer_indevs[MAX_POINTER_DEVS];
|
||||||
|
static lv_indev_drv_t pointer_indev_drvs[MAX_POINTER_DEVS];
|
||||||
|
static libinput_drv_state_t pointer_drv_states[MAX_POINTER_DEVS];
|
||||||
|
|
||||||
|
static int num_touchscreen_devs = 0;
|
||||||
|
static char *touchscreen_devs[MAX_TOUCHSCREEN_DEVS];
|
||||||
|
static lv_indev_t *touchscreen_indevs[MAX_TOUCHSCREEN_DEVS];
|
||||||
|
static lv_indev_drv_t touchscreen_indev_drvs[MAX_TOUCHSCREEN_DEVS];
|
||||||
|
static libinput_drv_state_t touchscreen_drv_states[MAX_TOUCHSCREEN_DEVS];
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static prototypes
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-connect available input devices having a specific capability.
|
||||||
|
*
|
||||||
|
* @param capability capability to filter devices by
|
||||||
|
* @param max_num_devs maximum number of devices to connect
|
||||||
|
* @param num_devs pointer for writing the actual number of connected devices into
|
||||||
|
* @param devs array for storing device paths
|
||||||
|
* @param indevs array for storing LVGL indevs
|
||||||
|
* @param indev_drvs array for storing LVGL indev drivers
|
||||||
|
* @param drv_states array for storing LVGL libinput driver states
|
||||||
|
*/
|
||||||
|
static void auto_connect(libinput_capability capability, int max_num_devs, int *num_devs, char *devs[], lv_indev_t *indevs[],
|
||||||
|
lv_indev_drv_t indev_drvs[], libinput_drv_state_t drv_states[]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log a message announcing the connection of an input device.
|
||||||
|
*
|
||||||
|
* @param capability the device's capability
|
||||||
|
* @param dev the device path
|
||||||
|
*/
|
||||||
|
static void log_connection(libinput_capability capability, char *dev);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform an input read on a device using the libinput driver.
|
||||||
|
*
|
||||||
|
* @param indev_drv input device driver
|
||||||
|
* @param data input device data to write into
|
||||||
|
*/
|
||||||
|
static void libinput_read_cb(lv_indev_drv_t *indev_drv, lv_indev_data_t *data);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void auto_connect(libinput_capability capability, int max_num_devs, int *num_devs, char *devs[], lv_indev_t *indevs[],
|
||||||
|
lv_indev_drv_t indev_drvs[], libinput_drv_state_t drv_states[]) {
|
||||||
|
|
||||||
|
memset(devs, 0, max_num_devs * sizeof(char *));
|
||||||
|
memset(indevs, 0, max_num_devs * sizeof(lv_indev_t));
|
||||||
|
memset(indev_drvs, 0, max_num_devs * sizeof(lv_indev_drv_t));
|
||||||
|
memset(drv_states, 0, max_num_devs * sizeof(libinput_drv_state_t));
|
||||||
|
|
||||||
|
*num_devs = libinput_find_devs(capability, devs, max_num_devs, false);
|
||||||
|
|
||||||
|
for (int i = 0; i < *num_devs; ++i) {
|
||||||
|
log_connection(capability, devs[i]);
|
||||||
|
|
||||||
|
libinput_init_state(&(drv_states[i]), devs[i]);
|
||||||
|
lv_indev_drv_init(&(indev_drvs[i]));
|
||||||
|
|
||||||
|
indev_drvs[i].read_cb = libinput_read_cb;
|
||||||
|
indev_drvs[i].user_data = &(drv_states[i]);
|
||||||
|
|
||||||
|
if (capability == LIBINPUT_CAPABILITY_KEYBOARD) {
|
||||||
|
indev_drvs[i].type = LV_INDEV_TYPE_KEYPAD;
|
||||||
|
} else {
|
||||||
|
indev_drvs[i].type = LV_INDEV_TYPE_POINTER;
|
||||||
|
indev_drvs[i].long_press_repeat_time = USHRT_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
indevs[i] = lv_indev_drv_register(&(indev_drvs[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void log_connection(libinput_capability capability, char *dev) {
|
||||||
|
switch (capability) {
|
||||||
|
case LIBINPUT_CAPABILITY_KEYBOARD:
|
||||||
|
ul_log(UL_LOG_LEVEL_VERBOSE, "Connecting keyboard device %s\n", dev);
|
||||||
|
break;
|
||||||
|
case LIBINPUT_CAPABILITY_POINTER:
|
||||||
|
ul_log(UL_LOG_LEVEL_VERBOSE, "Connecting pointer device %s\n", dev);
|
||||||
|
break;
|
||||||
|
case LIBINPUT_CAPABILITY_TOUCH:
|
||||||
|
ul_log(UL_LOG_LEVEL_VERBOSE, "Connecting touchscreen device %s\n", dev);
|
||||||
|
break;
|
||||||
|
case LIBINPUT_CAPABILITY_NONE:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void libinput_read_cb(lv_indev_drv_t *indev_drv, lv_indev_data_t *data) {
|
||||||
|
libinput_read_state(indev_drv->user_data, indev_drv, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
void ul_indev_auto_connect() {
|
||||||
|
auto_connect(LIBINPUT_CAPABILITY_KEYBOARD, MAX_KEYBOARD_DEVS, &num_keyboard_devs, keyboard_devs, keyboard_indevs,
|
||||||
|
keyboard_indev_drvs, keyboard_drv_states);
|
||||||
|
auto_connect(LIBINPUT_CAPABILITY_POINTER, MAX_POINTER_DEVS, &num_pointer_devs, pointer_devs, pointer_indevs,
|
||||||
|
pointer_indev_drvs, pointer_drv_states);
|
||||||
|
auto_connect(LIBINPUT_CAPABILITY_TOUCH, MAX_TOUCHSCREEN_DEVS, &num_touchscreen_devs, touchscreen_devs, touchscreen_indevs,
|
||||||
|
touchscreen_indev_drvs, touchscreen_drv_states);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ul_indev_is_keyboard_connected() {
|
||||||
|
return num_keyboard_devs > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ul_indev_set_up_textarea_for_keyboard_input(lv_obj_t *textarea) {
|
||||||
|
if (!ul_indev_is_keyboard_connected()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lv_group_t *group = lv_group_create();
|
||||||
|
lv_group_add_obj(group, textarea);
|
||||||
|
|
||||||
|
for (int i = 0; i < num_keyboard_devs; ++i) {
|
||||||
|
lv_indev_set_group(keyboard_indevs[i], group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ul_indev_set_up_mouse_cursor() {
|
||||||
|
lv_obj_t *cursor_obj = lv_img_create(lv_scr_act());
|
||||||
|
lv_img_set_src(cursor_obj, &ul_cursor_img_dsc);
|
||||||
|
for (int i = 0; i < num_pointer_devs; ++i) {
|
||||||
|
lv_indev_set_cursor(pointer_indevs[i], cursor_obj);
|
||||||
|
}
|
||||||
|
}
|
52
indev.h
Normal file
52
indev.h
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2021 Johannes Marbach
|
||||||
|
*
|
||||||
|
* This file is part of unl0kr, hereafter referred to as the program.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef UL_INDEV_H
|
||||||
|
#define UL_INDEV_H
|
||||||
|
|
||||||
|
#include "lvgl/lvgl.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-connect currently available keyboard, pointer and touchscreen input devices.
|
||||||
|
*/
|
||||||
|
void ul_indev_auto_connect();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if any keyboard devices are connected.
|
||||||
|
*
|
||||||
|
* @return true if at least one keyboard device is connected, false otherwise
|
||||||
|
*/
|
||||||
|
bool ul_indev_is_keyboard_connected();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up an LVGL text area to receive input from currently connected keyboard devices.
|
||||||
|
*
|
||||||
|
* @param textarea textarea widget
|
||||||
|
*/
|
||||||
|
void ul_indev_set_up_textarea_for_keyboard_input(lv_obj_t *textarea);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up the mouse cursor image for currently connected pointer devices.
|
||||||
|
*/
|
||||||
|
void ul_indev_set_up_mouse_cursor();
|
||||||
|
|
||||||
|
#endif /* UL_INDEV_H */
|
249
libinput_multi.c
249
libinput_multi.c
@@ -1,249 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file libinput_multi.c
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*********************
|
|
||||||
* INCLUDES
|
|
||||||
*********************/
|
|
||||||
#include "libinput_multi.h"
|
|
||||||
#if USE_LIBINPUT || USE_BSD_LIBINPUT
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <linux/limits.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <poll.h>
|
|
||||||
#include <libinput.h>
|
|
||||||
|
|
||||||
#if USE_BSD_LIBINPUT
|
|
||||||
#include <dev/evdev/input.h>
|
|
||||||
#else
|
|
||||||
#include <linux/input.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "libinput_xkb.h"
|
|
||||||
|
|
||||||
/*********************
|
|
||||||
* DEFINES
|
|
||||||
*********************/
|
|
||||||
|
|
||||||
/**********************
|
|
||||||
* TYPEDEFS
|
|
||||||
**********************/
|
|
||||||
|
|
||||||
/**********************
|
|
||||||
* STATIC PROTOTYPES
|
|
||||||
**********************/
|
|
||||||
static int open_restricted(const char *path, int flags, void *user_data);
|
|
||||||
static void close_restricted(int fd, void *user_data);
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int button;
|
|
||||||
int libinput_key_val;
|
|
||||||
struct libinput_device *device;
|
|
||||||
void *keyboard_state;
|
|
||||||
|
|
||||||
int libinput_fd;
|
|
||||||
struct libinput *libinput_context;
|
|
||||||
struct pollfd fds[1];
|
|
||||||
} libinput_multi_state;
|
|
||||||
|
|
||||||
/**********************
|
|
||||||
* STATIC VARIABLES
|
|
||||||
**********************/
|
|
||||||
static const int timeout = 0; // do not block
|
|
||||||
static const nfds_t nfds = 1;
|
|
||||||
static lv_point_t most_recent_touch_point = { .x = 0, .y = 0};
|
|
||||||
|
|
||||||
static const struct libinput_interface interface = {
|
|
||||||
.open_restricted = open_restricted,
|
|
||||||
.close_restricted = close_restricted,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**********************
|
|
||||||
* MACROS
|
|
||||||
**********************/
|
|
||||||
|
|
||||||
/**********************
|
|
||||||
* GLOBAL FUNCTIONS
|
|
||||||
**********************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* reconfigure the device file for libinput
|
|
||||||
* @param indev_drv driver object (must be initialised)
|
|
||||||
* @param dev_name set the libinput device filename
|
|
||||||
* @return true: the device file set complete
|
|
||||||
* false: the device file doesn't exist current system
|
|
||||||
*/
|
|
||||||
bool libinput_multi_set_file(lv_indev_drv_t * indev_drv, char* dev_name)
|
|
||||||
{
|
|
||||||
libinput_multi_state *state = (libinput_multi_state *)indev_drv->user_data;
|
|
||||||
if (!state) {
|
|
||||||
perror("unable to read state from driver:");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This check *should* not be necessary, yet applications crashes even on NULL handles.
|
|
||||||
// citing libinput.h:libinput_path_remove_device:
|
|
||||||
// > If no matching device exists, this function does nothing.
|
|
||||||
if (state->device) {
|
|
||||||
state->device = libinput_device_unref(state->device);
|
|
||||||
libinput_path_remove_device(state->device);
|
|
||||||
}
|
|
||||||
|
|
||||||
state->device = libinput_path_add_device(state->libinput_context, dev_name);
|
|
||||||
if(!state->device) {
|
|
||||||
perror("unable to add device to libinput context:");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
state->device = libinput_device_ref(state->device);
|
|
||||||
if(!state->device) {
|
|
||||||
perror("unable to reference device within libinput context:");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
state->button = LV_INDEV_STATE_REL;
|
|
||||||
state->libinput_key_val = 0;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* initialise a driver with fresh state data
|
|
||||||
* @param indev_drv driver object
|
|
||||||
*/
|
|
||||||
void libinput_multi_init_driver(lv_indev_drv_t * indev_drv) {
|
|
||||||
libinput_multi_state *state = (libinput_multi_state *)malloc(sizeof(libinput_multi_state));
|
|
||||||
state->device = NULL;
|
|
||||||
|
|
||||||
state->libinput_context = libinput_path_create_context(&interface, NULL);
|
|
||||||
state->libinput_fd = libinput_get_fd(state->libinput_context);
|
|
||||||
|
|
||||||
/* prepare poll */
|
|
||||||
state->fds[0].fd = state->libinput_fd;
|
|
||||||
state->fds[0].events = POLLIN;
|
|
||||||
state->fds[0].revents = 0;
|
|
||||||
|
|
||||||
state->keyboard_state = libinput_xkb_create_state();
|
|
||||||
|
|
||||||
indev_drv->user_data = (void *)state;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* destroy any existing state data on a driver
|
|
||||||
* @param indev_drv driver object
|
|
||||||
*/
|
|
||||||
void libinput_multi_deinit_driver(lv_indev_drv_t * indev_drv) {
|
|
||||||
if (indev_drv->user_data) {
|
|
||||||
libinput_multi_state *state = (libinput_multi_state *)indev_drv->user_data;
|
|
||||||
|
|
||||||
struct libinput_device *device = libinput_device_unref(state->device);
|
|
||||||
libinput_path_remove_device(device);
|
|
||||||
|
|
||||||
libinput_unref(state->libinput_context);
|
|
||||||
|
|
||||||
// TODO: dealloc keyboard state
|
|
||||||
|
|
||||||
free(indev_drv->user_data);
|
|
||||||
indev_drv->user_data = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the current position and state of the libinput
|
|
||||||
* @param indev_drv driver object itself
|
|
||||||
* @param data store the libinput data here
|
|
||||||
* @return false: because the points are not buffered, so no more data to be read
|
|
||||||
*/
|
|
||||||
void libinput_multi_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
|
|
||||||
{
|
|
||||||
libinput_multi_state *state = (libinput_multi_state *)indev_drv->user_data;
|
|
||||||
if (!state) {
|
|
||||||
perror("unable to read state from driver:");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct libinput_event *event;
|
|
||||||
struct libinput_event_touch *touch_event = NULL;
|
|
||||||
struct libinput_event_pointer *pointer_event = NULL;
|
|
||||||
struct libinput_event_keyboard *keyboard_event = NULL;
|
|
||||||
int rc = 0;
|
|
||||||
|
|
||||||
rc = poll(state->fds, nfds, timeout);
|
|
||||||
switch (rc){
|
|
||||||
case -1:
|
|
||||||
perror(NULL);
|
|
||||||
case 0:
|
|
||||||
goto report_most_recent_state;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
libinput_dispatch(state->libinput_context);
|
|
||||||
while((event = libinput_get_event(state->libinput_context)) != NULL) {
|
|
||||||
enum libinput_event_type type = libinput_event_get_type(event);
|
|
||||||
switch (type) {
|
|
||||||
case LIBINPUT_EVENT_TOUCH_MOTION:
|
|
||||||
case LIBINPUT_EVENT_TOUCH_DOWN:
|
|
||||||
touch_event = libinput_event_get_touch_event(event);
|
|
||||||
most_recent_touch_point.x = libinput_event_touch_get_x_transformed(touch_event, LV_HOR_RES);
|
|
||||||
most_recent_touch_point.y = libinput_event_touch_get_y_transformed(touch_event, LV_VER_RES);
|
|
||||||
state->button = LV_INDEV_STATE_PR;
|
|
||||||
break;
|
|
||||||
case LIBINPUT_EVENT_TOUCH_UP:
|
|
||||||
state->button = LV_INDEV_STATE_REL;
|
|
||||||
break;
|
|
||||||
case LIBINPUT_EVENT_POINTER_MOTION:
|
|
||||||
pointer_event = libinput_event_get_pointer_event(event);
|
|
||||||
most_recent_touch_point.x += libinput_event_pointer_get_dx(pointer_event);
|
|
||||||
most_recent_touch_point.y += libinput_event_pointer_get_dy(pointer_event);
|
|
||||||
most_recent_touch_point.x = most_recent_touch_point.x < 0 ? 0 : most_recent_touch_point.x;
|
|
||||||
most_recent_touch_point.x = most_recent_touch_point.x > LV_HOR_RES - 1 ? LV_HOR_RES - 1 : most_recent_touch_point.x;
|
|
||||||
most_recent_touch_point.y = most_recent_touch_point.y < 0 ? 0 : most_recent_touch_point.y;
|
|
||||||
most_recent_touch_point.y = most_recent_touch_point.y > LV_VER_RES - 1 ? LV_VER_RES - 1 : most_recent_touch_point.y;
|
|
||||||
break;
|
|
||||||
case LIBINPUT_EVENT_POINTER_BUTTON:
|
|
||||||
pointer_event = libinput_event_get_pointer_event(event);
|
|
||||||
enum libinput_button_state button_state = libinput_event_pointer_get_button_state(pointer_event);
|
|
||||||
state->button = button_state == LIBINPUT_BUTTON_STATE_RELEASED ? LV_INDEV_STATE_REL : LV_INDEV_STATE_PR;
|
|
||||||
break;
|
|
||||||
case LIBINPUT_EVENT_KEYBOARD_KEY:
|
|
||||||
keyboard_event = libinput_event_get_keyboard_event(event);
|
|
||||||
enum libinput_key_state key_state = libinput_event_keyboard_get_key_state(keyboard_event);
|
|
||||||
uint32_t code = libinput_event_keyboard_get_key(keyboard_event);
|
|
||||||
state->libinput_key_val = libinput_xkb_process_key(code, key_state == LIBINPUT_KEY_STATE_PRESSED, state->keyboard_state);
|
|
||||||
if (state->libinput_key_val != 0) {
|
|
||||||
state->button = (key_state == LIBINPUT_KEY_STATE_RELEASED) ? LV_INDEV_STATE_REL : LV_INDEV_STATE_PR; //
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
libinput_event_destroy(event);
|
|
||||||
}
|
|
||||||
report_most_recent_state:
|
|
||||||
data->point.x = most_recent_touch_point.x;
|
|
||||||
data->point.y = most_recent_touch_point.y;
|
|
||||||
data->state = state->button;
|
|
||||||
data->key = state->libinput_key_val;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**********************
|
|
||||||
* STATIC FUNCTIONS
|
|
||||||
**********************/
|
|
||||||
|
|
||||||
static int open_restricted(const char *path, int flags, void *user_data)
|
|
||||||
{
|
|
||||||
int fd = open(path, flags);
|
|
||||||
return fd < 0 ? -errno : fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void close_restricted(int fd, void *user_data)
|
|
||||||
{
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* USE_LIBINPUT || USE_BSD_LIBINPUT */
|
|
@@ -1,81 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file libinput_multi.h
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef LVGL_LIBINPUT_MULTI_H
|
|
||||||
#define LVGL_LIBINPUT_MULTI_H
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*********************
|
|
||||||
* INCLUDES
|
|
||||||
*********************/
|
|
||||||
// #ifndef LV_DRV_NO_CONF
|
|
||||||
// #ifdef LV_CONF_INCLUDE_SIMPLE
|
|
||||||
#include "lv_drv_conf.h"
|
|
||||||
// #else
|
|
||||||
// #include "../../lv_drv_conf.h"
|
|
||||||
// #endif
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
#if USE_LIBINPUT || USE_BSD_LIBINPUT
|
|
||||||
|
|
||||||
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
|
||||||
#include "lvgl.h"
|
|
||||||
#else
|
|
||||||
#include "lvgl/lvgl.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*********************
|
|
||||||
* DEFINES
|
|
||||||
*********************/
|
|
||||||
|
|
||||||
/**********************
|
|
||||||
* TYPEDEFS
|
|
||||||
**********************/
|
|
||||||
|
|
||||||
/**********************
|
|
||||||
* GLOBAL PROTOTYPES
|
|
||||||
**********************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* initialise a driver with fresh state data
|
|
||||||
* @param indev_drv driver object
|
|
||||||
*/
|
|
||||||
void libinput_multi_init_driver(lv_indev_drv_t * indev_drv);
|
|
||||||
/**
|
|
||||||
* destroy any existing state data on a driver
|
|
||||||
* @param indev_drv driver object
|
|
||||||
*/
|
|
||||||
void libinput_multi_deinit_driver(lv_indev_drv_t * indev_drv);
|
|
||||||
/**
|
|
||||||
* reconfigure the device file for libinput
|
|
||||||
* @param indev_drv driver object (must be initialised)
|
|
||||||
* @param dev_name set the libinput device filename
|
|
||||||
* @return true: the device file set complete
|
|
||||||
* false: the device file doesn't exist current system
|
|
||||||
*/
|
|
||||||
bool libinput_multi_set_file(lv_indev_drv_t * indev_drv, char* dev_name);
|
|
||||||
/**
|
|
||||||
* Get the current position and state of the libinput
|
|
||||||
* @param indev_drv driver object itself
|
|
||||||
* @param data store the libinput data here
|
|
||||||
* @return false: because the points are not buffered, so no more data to be read
|
|
||||||
*/
|
|
||||||
void libinput_multi_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
|
|
||||||
|
|
||||||
|
|
||||||
/**********************
|
|
||||||
* MACROS
|
|
||||||
**********************/
|
|
||||||
|
|
||||||
#endif /* USE_LIBINPUT || USE_BSD_LIBINPUT */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
} /* extern "C" */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* LVGL_LIBINPUT_MULTI_H */
|
|
146
libinput_xkb.c
146
libinput_xkb.c
@@ -1,146 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file libinput_xkb.c
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*********************
|
|
||||||
* INCLUDES
|
|
||||||
*********************/
|
|
||||||
#include "libinput_xkb.h"
|
|
||||||
#if USE_LIBINPUT || USE_BSD_LIBINPUT
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <xkbcommon/xkbcommon.h>
|
|
||||||
|
|
||||||
/*********************
|
|
||||||
* DEFINES
|
|
||||||
*********************/
|
|
||||||
|
|
||||||
/**********************
|
|
||||||
* TYPEDEFS
|
|
||||||
**********************/
|
|
||||||
|
|
||||||
/**********************
|
|
||||||
* STATIC PROTOTYPES
|
|
||||||
**********************/
|
|
||||||
|
|
||||||
/**********************
|
|
||||||
* STATIC VARIABLES
|
|
||||||
**********************/
|
|
||||||
static struct xkb_context *ctx = NULL;
|
|
||||||
static struct xkb_keymap *keymap = NULL;
|
|
||||||
|
|
||||||
/**********************
|
|
||||||
* MACROS
|
|
||||||
**********************/
|
|
||||||
|
|
||||||
/**********************
|
|
||||||
* GLOBAL FUNCTIONS
|
|
||||||
**********************/
|
|
||||||
|
|
||||||
bool libinput_xkb_init(void) {
|
|
||||||
if (ctx) {
|
|
||||||
perror("context is already initialised");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
|
||||||
if (!ctx) {
|
|
||||||
perror("could not create new XKB context");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct xkb_rule_names names = {
|
|
||||||
.rules = NULL,
|
|
||||||
.model = "pc105",
|
|
||||||
.layout = "de",
|
|
||||||
.variant = "nodeadkeys",
|
|
||||||
.options = NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
keymap = xkb_keymap_new_from_names(ctx, &names, XKB_KEYMAP_COMPILE_NO_FLAGS);
|
|
||||||
if (!keymap) {
|
|
||||||
perror("could not create XKB keymap");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
keymap = xkb_keymap_ref(keymap);
|
|
||||||
if (!keymap) {
|
|
||||||
perror("could not reference XKB keymap");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *libinput_xkb_create_state(void) {
|
|
||||||
struct xkb_state *state = xkb_state_new(keymap);
|
|
||||||
if (!state) {
|
|
||||||
perror("could not create XKB state");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
state = xkb_state_ref(state);
|
|
||||||
if (!state) {
|
|
||||||
perror("could not reference XKB state");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t libinput_xkb_process_key(uint32_t scancode, bool down, void *state) {
|
|
||||||
/* Offset the evdev scancode by 8, see https://xkbcommon.org/doc/current/xkbcommon_8h.html#ac29aee92124c08d1953910ab28ee1997 */
|
|
||||||
xkb_keycode_t keycode = scancode + 8;
|
|
||||||
|
|
||||||
uint32_t result = 0;
|
|
||||||
|
|
||||||
switch (xkb_state_key_get_one_sym(state, keycode)) {
|
|
||||||
case XKB_KEY_BackSpace:
|
|
||||||
result = LV_KEY_BACKSPACE;
|
|
||||||
break;
|
|
||||||
case XKB_KEY_Return:
|
|
||||||
result = LV_KEY_ENTER;
|
|
||||||
break;
|
|
||||||
case XKB_KEY_Prior:
|
|
||||||
result = LV_KEY_PREV;
|
|
||||||
break;
|
|
||||||
case XKB_KEY_Next:
|
|
||||||
result = LV_KEY_NEXT;
|
|
||||||
break;
|
|
||||||
case XKB_KEY_Up:
|
|
||||||
result = LV_KEY_UP;
|
|
||||||
break;
|
|
||||||
case XKB_KEY_Left:
|
|
||||||
result = LV_KEY_LEFT;
|
|
||||||
break;
|
|
||||||
case XKB_KEY_Right:
|
|
||||||
result = LV_KEY_RIGHT;
|
|
||||||
break;
|
|
||||||
case XKB_KEY_Down:
|
|
||||||
result = LV_KEY_DOWN;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result == 0) {
|
|
||||||
char buffer[4] = { 0, 0, 0, 0 };
|
|
||||||
int size = xkb_state_key_get_utf8((struct xkb_state *)state, keycode, NULL, 0) + 1;
|
|
||||||
if (size > 1) {
|
|
||||||
xkb_state_key_get_utf8((struct xkb_state *)state, keycode, buffer, size);
|
|
||||||
memcpy(&result, buffer, 4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
xkb_state_update_key((struct xkb_state *)state, keycode, down ? XKB_KEY_DOWN : XKB_KEY_UP);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**********************
|
|
||||||
* STATIC FUNCTIONS
|
|
||||||
**********************/
|
|
||||||
|
|
||||||
#endif /* USE_LIBINPUT || USE_BSD_LIBINPUT */
|
|
@@ -1,58 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file libinput_xkb.h
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef LVGL_LIBINPUT_XKB_H
|
|
||||||
#define LVGL_LIBINPUT_XKB_H
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*********************
|
|
||||||
* INCLUDES
|
|
||||||
*********************/
|
|
||||||
// #ifndef LV_DRV_NO_CONF
|
|
||||||
// #ifdef LV_CONF_INCLUDE_SIMPLE
|
|
||||||
#include "lv_drv_conf.h"
|
|
||||||
// #else
|
|
||||||
// #include "../../lv_drv_conf.h"
|
|
||||||
// #endif
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
#if USE_LIBINPUT || USE_BSD_LIBINPUT
|
|
||||||
|
|
||||||
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
|
||||||
#include "lvgl.h"
|
|
||||||
#else
|
|
||||||
#include "lvgl/lvgl.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*********************
|
|
||||||
* DEFINES
|
|
||||||
*********************/
|
|
||||||
|
|
||||||
/**********************
|
|
||||||
* TYPEDEFS
|
|
||||||
**********************/
|
|
||||||
|
|
||||||
/**********************
|
|
||||||
* GLOBAL PROTOTYPES
|
|
||||||
**********************/
|
|
||||||
|
|
||||||
bool libinput_xkb_init(void);
|
|
||||||
void *libinput_xkb_create_state(void);
|
|
||||||
uint32_t libinput_xkb_process_key(uint32_t code, bool down, void *state);
|
|
||||||
|
|
||||||
/**********************
|
|
||||||
* MACROS
|
|
||||||
**********************/
|
|
||||||
|
|
||||||
#endif /* USE_LIBINPUT || USE_BSD_LIBINPUT */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
} /* extern "C" */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* LVGL_LIBINPUT_XKB_H */
|
|
Submodule lv_drivers updated: 8960d0fcd0...7a0f788733
75
main.c
75
main.c
@@ -19,20 +19,16 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "command_line.h"
|
#include "command_line.h"
|
||||||
#include "cursor.h"
|
#include "indev.h"
|
||||||
#include "libinput_multi.h"
|
|
||||||
#include "libinput_xkb.h"
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "unl0kr.h"
|
#include "unl0kr.h"
|
||||||
|
|
||||||
#include "lv_drivers/display/fbdev.h"
|
#include "lv_drivers/display/fbdev.h"
|
||||||
#include "lv_drivers/indev/libinput_drv.h"
|
|
||||||
|
|
||||||
#include "lvgl/lvgl.h"
|
#include "lvgl/lvgl.h"
|
||||||
|
|
||||||
#include "squeek2lvgl/sq2lv.h"
|
#include "squeek2lvgl/sq2lv.h"
|
||||||
|
|
||||||
#include <limits.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@@ -378,70 +374,15 @@ int main(int argc, char *argv[]) {
|
|||||||
disp_drv.ver_res = ver_res;
|
disp_drv.ver_res = ver_res;
|
||||||
lv_disp_drv_register(&disp_drv);
|
lv_disp_drv_register(&disp_drv);
|
||||||
|
|
||||||
/* Connect keyboards */
|
/* Connect input devices */
|
||||||
libinput_xkb_init();
|
ul_indev_auto_connect();
|
||||||
#define MAX_KEYBOARDS 3
|
ul_indev_set_up_mouse_cursor();
|
||||||
char *keyboard_devices[MAX_KEYBOARDS] = { NULL, NULL, NULL };
|
|
||||||
lv_indev_drv_t keyboard_indev_drvs[MAX_KEYBOARDS];
|
|
||||||
lv_indev_t *keyboard_indevs[MAX_KEYBOARDS] = { NULL, NULL, NULL };
|
|
||||||
size_t num_keyboards = libinput_find_devs(LIBINPUT_CAPABILITY_KEYBOARD, keyboard_devices, MAX_KEYBOARDS, false);
|
|
||||||
for (int i = 0; i < num_keyboards; ++i) {
|
|
||||||
ul_log(UL_LOG_LEVEL_VERBOSE, "Connecting keyboard device %s\n", keyboard_devices[i]);
|
|
||||||
lv_indev_drv_init(&keyboard_indev_drvs[i]);
|
|
||||||
keyboard_indev_drvs[i].type = LV_INDEV_TYPE_KEYPAD;
|
|
||||||
keyboard_indev_drvs[i].read_cb = libinput_multi_read;
|
|
||||||
libinput_multi_init_driver(&keyboard_indev_drvs[i]);
|
|
||||||
libinput_multi_set_file(&keyboard_indev_drvs[i], keyboard_devices[i]);
|
|
||||||
keyboard_indevs[i] = lv_indev_drv_register(&keyboard_indev_drvs[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hide the on-screen keyboard by default if a physical keyboard is connected */
|
/* Hide the on-screen keyboard by default if a physical keyboard is connected */
|
||||||
if (num_keyboards > 0) {
|
if (ul_indev_is_keyboard_connected()) {
|
||||||
is_keyboard_hidden = true;
|
is_keyboard_hidden = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Connect mice and trackpads */
|
|
||||||
#define MAX_POINTER_DEVICES 4
|
|
||||||
char *pointer_devices[MAX_POINTER_DEVICES] = { NULL, NULL, NULL, NULL };
|
|
||||||
lv_indev_drv_t pointer_indev_drvs[MAX_POINTER_DEVICES];
|
|
||||||
lv_indev_t *pointer_indevs[MAX_POINTER_DEVICES] = { NULL, NULL, NULL, NULL };
|
|
||||||
size_t num_pointer_devices = libinput_find_devs(LIBINPUT_CAPABILITY_POINTER, pointer_devices, MAX_POINTER_DEVICES, false);
|
|
||||||
for (int i = 0; i < num_pointer_devices; ++i) {
|
|
||||||
ul_log(UL_LOG_LEVEL_VERBOSE, "Connecting pointer device %s\n", pointer_devices[i]);
|
|
||||||
lv_indev_drv_init(&pointer_indev_drvs[i]);
|
|
||||||
pointer_indev_drvs[i].type = LV_INDEV_TYPE_POINTER;
|
|
||||||
pointer_indev_drvs[i].read_cb = libinput_multi_read;
|
|
||||||
pointer_indev_drvs[i].long_press_repeat_time = USHRT_MAX;
|
|
||||||
libinput_multi_init_driver(&pointer_indev_drvs[i]);
|
|
||||||
libinput_multi_set_file(&pointer_indev_drvs[i], pointer_devices[i]);
|
|
||||||
pointer_indevs[i] = lv_indev_drv_register(&pointer_indev_drvs[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set mouse cursor */
|
|
||||||
if (num_pointer_devices > 0) {
|
|
||||||
lv_obj_t *cursor_obj = lv_img_create(lv_scr_act());
|
|
||||||
lv_img_set_src(cursor_obj, &ul_cursor_img_dsc);
|
|
||||||
for (int i = 0; i < num_pointer_devices; ++i) {
|
|
||||||
lv_indev_set_cursor(pointer_indevs[i], cursor_obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Connect touchscreens */
|
|
||||||
#define MAX_TOUCHSCREENS 1
|
|
||||||
char *touchscreens[MAX_TOUCHSCREENS] = { NULL };
|
|
||||||
lv_indev_drv_t touchscreen_indev_drvs[MAX_TOUCHSCREENS];
|
|
||||||
size_t num_touchscreens = libinput_find_devs(LIBINPUT_CAPABILITY_TOUCH, touchscreens, MAX_TOUCHSCREENS, false);
|
|
||||||
for (int i = 0; i < num_touchscreens; ++i) {
|
|
||||||
ul_log(UL_LOG_LEVEL_VERBOSE, "Connecting touchscreen device %s\n", touchscreens[i]);
|
|
||||||
lv_indev_drv_init(&touchscreen_indev_drvs[i]);
|
|
||||||
touchscreen_indev_drvs[i].type = LV_INDEV_TYPE_POINTER;
|
|
||||||
touchscreen_indev_drvs[i].read_cb = libinput_multi_read;
|
|
||||||
touchscreen_indev_drvs[i].long_press_repeat_time = USHRT_MAX;
|
|
||||||
libinput_multi_init_driver(&touchscreen_indev_drvs[i]);
|
|
||||||
libinput_multi_set_file(&touchscreen_indev_drvs[i], touchscreens[i]);
|
|
||||||
lv_indev_drv_register(&touchscreen_indev_drvs[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialise theme and styles */
|
/* Initialise theme and styles */
|
||||||
set_theme(is_dark_theme);
|
set_theme(is_dark_theme);
|
||||||
lv_style_init(&style_text_normal);
|
lv_style_init(&style_text_normal);
|
||||||
@@ -510,11 +451,7 @@ int main(int argc, char *argv[]) {
|
|||||||
lv_obj_add_style(textarea, &style_text_normal, 0);
|
lv_obj_add_style(textarea, &style_text_normal, 0);
|
||||||
|
|
||||||
/* Route physical keyboard input into textarea */
|
/* Route physical keyboard input into textarea */
|
||||||
lv_group_t *group = lv_group_create();
|
ul_indev_set_up_textarea_for_keyboard_input(textarea);
|
||||||
lv_group_add_obj(group, textarea);
|
|
||||||
for (int i = 0; i < num_keyboards; ++i) {
|
|
||||||
lv_indev_set_group(keyboard_indevs[i], group);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Show / hide password button */
|
/* Show / hide password button */
|
||||||
lv_obj_t *toggle_pw_btn = lv_btn_create(lv_scr_act());
|
lv_obj_t *toggle_pw_btn = lv_btn_create(lv_scr_act());
|
||||||
|
@@ -29,9 +29,8 @@ add_project_arguments('-DUL_VERSION="@0@"'.format(meson.project_version()), lang
|
|||||||
unl0kr_sources = [
|
unl0kr_sources = [
|
||||||
'command_line.c',
|
'command_line.c',
|
||||||
'cursor.c',
|
'cursor.c',
|
||||||
|
'indev.c',
|
||||||
'log.c',
|
'log.c',
|
||||||
'libinput_multi.c',
|
|
||||||
'libinput_xkb.c',
|
|
||||||
'main.c',
|
'main.c',
|
||||||
'montserrat_extended_32.c',
|
'montserrat_extended_32.c',
|
||||||
'sq2lv_layouts.c',
|
'sq2lv_layouts.c',
|
||||||
|
Reference in New Issue
Block a user