Merge branch 'alert-slider' into 'main'
fbd-alert-slider: Small service to track alert sliders See merge request Librem5/feedbackd!142
This commit is contained in:
@@ -25,4 +25,10 @@ SUBSYSTEM=="leds", DEVPATH=="*/*:indicator", ENV{FEEDBACKD_TYPE}="led", RUN{buil
|
||||
SUBSYSTEM=="leds", DEVPATH=="*/*:flash", ENV{FEEDBACKD_TYPE}="led", RUN{builtin}+="kmod load ledtrig-pattern", RUN+="/usr/libexec/fbd-ledctrl -p %S%p -t pattern -G feedbackd"
|
||||
SUBSYSTEM=="leds", DEVPATH=="*/*:torch", ENV{FEEDBACKD_TYPE}="led", RUN{builtin}+="kmod load ledtrig-pattern", RUN+="/usr/libexec/fbd-ledctrl -p %S%p -t pattern -G feedbackd"
|
||||
|
||||
#
|
||||
# Alert sliders
|
||||
#
|
||||
# OnePlus 6,6T (DT bits not yet upstream)
|
||||
SUBSYSTEM=="input", KERNEL=="event*", ENV{ID_INPUT}=="1", ENV{ID_PATH}=="platform-alert-slider", TAG+="uaccess", ENV{FEEDBACKD_TYPE}="alert-slider"
|
||||
|
||||
LABEL="feedbackd_end"
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
[Unit]
|
||||
Description=Feedbackd Alert Slider Handler
|
||||
PartOf=graphical-session.target
|
||||
|
||||
[Service]
|
||||
ExecStart=@libexecdir@/fbd-alert-slider
|
||||
Restart=on-abnormal
|
||||
RestartSec=10s
|
||||
|
||||
[Install]
|
||||
WantedBy=graphical-session.target
|
||||
@@ -72,4 +72,24 @@ if get_option('udev')
|
||||
install_data('90-feedbackd.rules', install_dir: udevdir)
|
||||
endif
|
||||
|
||||
systemd_user_unit_dir = get_option('systemd_user_unit_dir')
|
||||
systemd_dep = dependency('systemd', required: false)
|
||||
if systemd_user_unit_dir == ''
|
||||
if systemd_dep.found()
|
||||
systemd_user_unit_dir = systemd_dep.get_variable('systemd_user_unit_dir')
|
||||
else
|
||||
systemd_user_unit_dir = prefix / libdir / 'systemd' / 'user'
|
||||
endif
|
||||
endif
|
||||
|
||||
# Alert slider Systemd user service
|
||||
alert_slider_unit = 'fbd-alert-slider.service'
|
||||
configure_file(
|
||||
input : alert_slider_unit + '.in',
|
||||
output : alert_slider_unit,
|
||||
configuration : service_data,
|
||||
install : true,
|
||||
install_dir : systemd_user_unit_dir,
|
||||
)
|
||||
|
||||
endif # daemon
|
||||
|
||||
@@ -33,7 +33,8 @@
|
||||
</key>
|
||||
|
||||
<key name="allow-important" type="as">
|
||||
<default>[]</default>
|
||||
<default>['org.sigxcpu.FbdAlertSlider',
|
||||
'org.sigxcpu.FbdAlertSlider']</default>
|
||||
<summary>List of apps that can override the feedback level</summary>
|
||||
<description>
|
||||
Apps listed here can override the configured feedack level by
|
||||
|
||||
Vendored
+1
@@ -1,4 +1,5 @@
|
||||
usr/bin/
|
||||
usr/lib/systemd/user
|
||||
usr/lib/udev/
|
||||
usr/libexec/
|
||||
usr/share/dbus-1/
|
||||
|
||||
@@ -27,6 +27,7 @@ if get_option('daemon')
|
||||
gsound = dependency('gsound')
|
||||
gudev = dependency('gudev-1.0', version: '>=232')
|
||||
json_glib = dependency('json-glib-1.0')
|
||||
systemd_dep = dependency('systemd', required: false)
|
||||
endif
|
||||
|
||||
prefix = get_option('prefix')
|
||||
|
||||
@@ -16,3 +16,6 @@ option('man',
|
||||
option('tests',
|
||||
type: 'boolean', value: true,
|
||||
description: 'Whether to compile unit tests')
|
||||
option('systemd_user_unit_dir',
|
||||
type: 'string', value: '',
|
||||
description: 'Directory for systemd user units')
|
||||
|
||||
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Phosh Developers
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0+
|
||||
*
|
||||
* Heavily based on a shell script posted to the phosh matrix channel
|
||||
* by isyourbrain foss
|
||||
*
|
||||
* Author: Guido Günther <agx@sigxcpu.org>
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "fbd-alert-slider"
|
||||
|
||||
#define LIBFEEDBACK_USE_UNSTABLE_API
|
||||
#include "libfeedback.h"
|
||||
|
||||
#include "fbd.h"
|
||||
|
||||
#include <gudev/gudev.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <grp.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <linux/input.h>
|
||||
|
||||
#define BITS_PER_LONG (sizeof(long) * 8)
|
||||
#define NBITS(x) ((((x) - 1) / BITS_PER_LONG) + 1)
|
||||
#define OFF(x) ((x) % BITS_PER_LONG)
|
||||
#define BIT(x) (1UL << OFF (x))
|
||||
#define LONG(x) ((x) / BITS_PER_LONG)
|
||||
#define test_bit(bit, array) ((array[LONG (bit)] >> OFF (bit)) & 1)
|
||||
|
||||
typedef enum {
|
||||
FBD_ALERT_SLIDER_STATE_SILENT = 0,
|
||||
FBD_ALERT_SLIDER_STATE_QUIET = 1,
|
||||
FBD_ALERT_SLIDER_STATE_FULL = 2,
|
||||
} FbdAlertSliderState;
|
||||
|
||||
GSettings *settings = NULL;
|
||||
|
||||
static void
|
||||
set_level (FbdAlertSliderState state, gboolean silent)
|
||||
{
|
||||
g_autoptr (LfbEvent) event = NULL;
|
||||
const char *profile;
|
||||
|
||||
switch (state) {
|
||||
case FBD_ALERT_SLIDER_STATE_SILENT:
|
||||
profile = "silent";
|
||||
break;
|
||||
case FBD_ALERT_SLIDER_STATE_QUIET:
|
||||
profile = "quiet";
|
||||
break;
|
||||
case FBD_ALERT_SLIDER_STATE_FULL:
|
||||
profile = "full";
|
||||
break;
|
||||
default:
|
||||
g_return_if_reached ();
|
||||
}
|
||||
|
||||
g_debug ("Setting profile to %s", profile);
|
||||
lfb_set_feedback_profile (profile);
|
||||
|
||||
if (!silent) {
|
||||
event = lfb_event_new ("button-pressed");
|
||||
lfb_event_set_important (event, TRUE);
|
||||
lfb_event_set_feedback_profile (event, "quiet");
|
||||
lfb_event_trigger_feedback (event, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
get_initial_value (int fd, int axis)
|
||||
{
|
||||
int abs[6] = {0};
|
||||
|
||||
ioctl (fd, EVIOCGABS (axis), abs);
|
||||
return abs[0];
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
probe (FbdAlertSliderState *initial)
|
||||
{
|
||||
GList *l;
|
||||
g_autolist (GUdevClient) devices = NULL;
|
||||
g_autoptr (GUdevClient) client = NULL;
|
||||
unsigned int code;
|
||||
int version, fd, value = 0;
|
||||
char name[256] = "Unknown";
|
||||
unsigned long bit[EV_MAX][NBITS (KEY_MAX)];
|
||||
const char *device_file = NULL;
|
||||
const char * const subsystems[] = { "input", NULL };
|
||||
|
||||
client = g_udev_client_new (subsystems);
|
||||
devices = g_udev_client_query_by_subsystem (client, "input");
|
||||
|
||||
for (l = devices; l != NULL; l = l->next) {
|
||||
GUdevDevice *dev = l->data;
|
||||
|
||||
if (!g_strcmp0 (g_udev_device_get_property (dev, FEEDBACKD_UDEV_ATTR), "alert-slider")) {
|
||||
device_file = g_udev_device_get_device_file (dev);
|
||||
g_debug ("Found alert slider device: %s", device_file);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!device_file) {
|
||||
g_debug ("No matching device found");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if ((fd = open (device_file, O_RDONLY)) < 0) {
|
||||
g_warning ("Failed to open alert slider device: %s", strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ioctl (fd, EVIOCGVERSION, &version)) {
|
||||
g_warning ("Can't get version %s", strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
g_debug ("Input driver version: %d.%d.%d", version >> 16, (version >> 8) & 0xff, version & 0xff);
|
||||
|
||||
ioctl (fd, EVIOCGNAME (sizeof(name)), name);
|
||||
g_debug ("Input device name: '%s'", name);
|
||||
if (g_strcmp0 (name, "Alert slider")) {
|
||||
g_critical ("Not an alert slider but '%s'", name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset (bit, 0, sizeof(bit));
|
||||
ioctl (fd, EVIOCGBIT (0, EV_MAX), bit[0]);
|
||||
|
||||
if (test_bit (EV_ABS, bit[0])) {
|
||||
ioctl (fd, EVIOCGBIT (EV_ABS, KEY_MAX), bit[EV_ABS]);
|
||||
for (code = 0; code < KEY_MAX; code++) {
|
||||
if (test_bit (code, bit[EV_ABS])) {
|
||||
value = get_initial_value (fd, code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
g_critical ("Device doesn't support EV_ABS");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fd >= 0) {
|
||||
g_debug ("Initial value: %d", value);
|
||||
*initial = value;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
on_input_ready (GIOChannel *source, GIOCondition cond, gpointer unused)
|
||||
{
|
||||
GIOError status;
|
||||
struct input_event ev[64];
|
||||
gsize rd;
|
||||
|
||||
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
||||
status = g_io_channel_read (source, (char *)ev, sizeof(ev), &rd /*, &err */);
|
||||
G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
if (status != G_IO_ERROR_NONE ) {
|
||||
g_warning ("Failed to read event: %d", status);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (rd < sizeof(struct input_event)) {
|
||||
g_warning ("Expected %d bytes, got %zd", (int) sizeof(struct input_event), rd);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
for (int i = 0; i < rd / sizeof(struct input_event); i++) {
|
||||
unsigned int type, code;
|
||||
|
||||
type = ev[i].type;
|
||||
code = ev[i].code;
|
||||
|
||||
if (type == EV_SYN)
|
||||
continue;
|
||||
|
||||
if (type != EV_ABS || code != 34) {
|
||||
g_warning ("Unexpected event %d / %d", type, code);
|
||||
continue;
|
||||
}
|
||||
|
||||
g_debug ("Event: time %ld.%06ld, value: %d",
|
||||
ev[i].input_event_sec,
|
||||
ev[i].input_event_usec,
|
||||
ev[i].value);
|
||||
set_level (ev[i].value, FALSE);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
g_autoptr (GError) err = NULL;
|
||||
g_autoptr (GOptionContext) opt_context = NULL;
|
||||
g_autoptr (GIOChannel) input = NULL;
|
||||
g_autoptr (GMainLoop) loop = NULL;
|
||||
FbdAlertSliderState state = 0;
|
||||
int fd;
|
||||
const GOptionEntry options [] = {
|
||||
{ NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
opt_context = g_option_context_new ("- helper to prepare sysfs for feedbackd");
|
||||
g_option_context_add_main_entries (opt_context, options, NULL);
|
||||
if (!g_option_context_parse (opt_context, &argc, &argv, &err)) {
|
||||
g_print ("%s", err->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fd = probe (&state);
|
||||
if (fd < 0) {
|
||||
if (fd == -ENOENT)
|
||||
return EXIT_SUCCESS;
|
||||
else
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!lfb_init ("org.sigxcpu.FbdAlertSlider", &err)) {
|
||||
g_print ("Failed to init libfeedback: %s\n", err->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
set_level (state, TRUE);
|
||||
|
||||
input = g_io_channel_unix_new (fd);
|
||||
g_io_channel_set_encoding (input, NULL, NULL);
|
||||
g_io_add_watch (input, G_IO_IN | G_IO_ERR | G_IO_HUP, on_input_ready, NULL);
|
||||
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
g_main_loop_run (loop);
|
||||
|
||||
g_clear_object (&settings);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -87,6 +87,15 @@ executable(
|
||||
install_dir: libexecdir,
|
||||
)
|
||||
|
||||
executable(
|
||||
'fbd-alert-slider',
|
||||
sources : ['fbd-alert-slider.c'],
|
||||
include_directories : fbd_inc,
|
||||
dependencies : [glib, gio, gio_unix, gudev, libfeedback_dep],
|
||||
install : true,
|
||||
install_dir: libexecdir,
|
||||
)
|
||||
|
||||
executable(
|
||||
'fbd-theme-validate',
|
||||
sources : ['fbd-theme-validate.c'],
|
||||
|
||||
Reference in New Issue
Block a user