Merge branch 'force_feedback' into 'master'
keyboard: add haptic feedback Closes #10 See merge request postmarketOS/buffybox!76
This commit is contained in:
commit
27208ba156
19 changed files with 211 additions and 15 deletions
109
shared/force_feedback.c
Normal file
109
shared/force_feedback.c
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "force_feedback.h"
|
||||
|
||||
#include "log.h"
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <libudev.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define bit_is_set(array, bit) ((array[bit / 8] >> bit % 8) & 0x01)
|
||||
|
||||
/**
|
||||
* Static variables
|
||||
*/
|
||||
|
||||
static int fd = -1;
|
||||
static struct input_event ff_event = {
|
||||
.type = EV_FF,
|
||||
.code = 0,
|
||||
.value = 1
|
||||
};
|
||||
|
||||
/**
|
||||
* Public functions
|
||||
*/
|
||||
|
||||
void bbx_force_feedback_connect(struct udev_device* device) {
|
||||
if (fd >= 0)
|
||||
return;
|
||||
|
||||
const char* node = udev_device_get_devnode(device);
|
||||
|
||||
int fd_event = open(node, O_RDWR);
|
||||
if (fd_event < 0) {
|
||||
bbx_log(BBX_LOG_LEVEL_ERROR, "Can't open %s", node);
|
||||
return;
|
||||
}
|
||||
|
||||
int n_effects;
|
||||
if (ioctl(fd_event, EVIOCGEFFECTS, &n_effects) == -1 || n_effects == 0) {
|
||||
close(fd_event);
|
||||
return;
|
||||
}
|
||||
|
||||
bbx_log(BBX_LOG_LEVEL_VERBOSE, "Found a force feedback device: %s", node);
|
||||
|
||||
uint8_t features[(FF_CNT + 7) / 8];
|
||||
if (ioctl(fd_event, EVIOCGBIT(EV_FF, sizeof(features)), features) == -1) {
|
||||
bbx_log(BBX_LOG_LEVEL_ERROR, "Can't request features of %s", node);
|
||||
close(fd_event);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bit_is_set(features, FF_RUMBLE)) {
|
||||
bbx_log(BBX_LOG_LEVEL_VERBOSE, "%s does not support FF_RUMBLE", node);
|
||||
close(fd_event);
|
||||
return;
|
||||
}
|
||||
|
||||
struct ff_effect effect = {
|
||||
.type = FF_RUMBLE,
|
||||
.id = -1,
|
||||
.direction = 0x0000,
|
||||
.trigger.button = 0,
|
||||
.trigger.interval = 0,
|
||||
.replay.length = 50,
|
||||
.replay.delay = 0,
|
||||
.u.rumble.strong_magnitude = 0xC000,
|
||||
.u.rumble.weak_magnitude = 0xC000
|
||||
};
|
||||
|
||||
if (ioctl(fd_event, EVIOCSFF, &effect) == -1) {
|
||||
bbx_log(BBX_LOG_LEVEL_ERROR, "Can't upload the effect");
|
||||
close(fd_event);
|
||||
return;
|
||||
}
|
||||
|
||||
ff_event.code = effect.id;
|
||||
|
||||
if (bit_is_set(features, FF_GAIN)) {
|
||||
struct input_event gain = {
|
||||
.type = EV_FF,
|
||||
.code = FF_GAIN,
|
||||
.value = 0xFFFF
|
||||
};
|
||||
|
||||
if (write(fd_event, &gain, sizeof(gain)) != sizeof(gain))
|
||||
bbx_log(BBX_LOG_LEVEL_WARNING, "Can't set the gain");
|
||||
}
|
||||
|
||||
fd = fd_event;
|
||||
}
|
||||
|
||||
void bbx_force_feedback_play() {
|
||||
if (fd < 0)
|
||||
return;
|
||||
|
||||
if (write(fd, &ff_event, sizeof(ff_event)) != sizeof(ff_event)) {
|
||||
// Assume that the force feedback device was disconnected
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
}
|
||||
20
shared/force_feedback.h
Normal file
20
shared/force_feedback.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef BBX_FORCE_FEEDBACK_H
|
||||
#define BBX_FORCE_FEEDBACK_H
|
||||
|
||||
#include <libudev.h>
|
||||
|
||||
/**
|
||||
* Try to connect a force feedback device.
|
||||
*/
|
||||
void bbx_force_feedback_connect(struct udev_device* device);
|
||||
|
||||
/**
|
||||
* Play a force feedback effect.
|
||||
*/
|
||||
void bbx_force_feedback_play();
|
||||
|
||||
#endif /* BBX_FORCE_FEEDBACK_H */
|
||||
|
|
@ -6,6 +6,7 @@
|
|||
#include "indev.h"
|
||||
|
||||
#include "cursor/cursor.h"
|
||||
#include "force_feedback.h"
|
||||
#include "log.h"
|
||||
|
||||
#include "lvgl/lvgl.h"
|
||||
|
|
@ -93,6 +94,7 @@ static struct {
|
|||
#endif
|
||||
uint8_t pointer : 1;
|
||||
uint8_t touchscreen : 1;
|
||||
uint8_t force_feedback : 1;
|
||||
} options;
|
||||
|
||||
/**
|
||||
|
|
@ -641,6 +643,12 @@ static void attach_input_device(struct udev_device* device) {
|
|||
break;
|
||||
}
|
||||
|
||||
/* A device can be a force feedback device and an input device independently,
|
||||
so we check for both capabilities. */
|
||||
|
||||
if (options.force_feedback)
|
||||
bbx_force_feedback_connect(device);
|
||||
|
||||
struct libinput_device* dev = libinput_path_add_device(context_libinput, node);
|
||||
if (!dev) {
|
||||
bbx_log(BBX_LOG_LEVEL_WARNING, "libinput can't use %s", node);
|
||||
|
|
@ -795,6 +803,7 @@ uint8_t bbx_indev_init(int fd_epoll, const struct bbx_indev_opts* opts) {
|
|||
#endif
|
||||
options.pointer = opts->pointer;
|
||||
options.touchscreen = opts->touchscreen;
|
||||
options.force_feedback = opts->force_feedback;
|
||||
|
||||
attach_input_devices();
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ struct bbx_indev_opts {
|
|||
#endif
|
||||
uint8_t pointer : 1;
|
||||
uint8_t touchscreen : 1;
|
||||
uint8_t force_feedback : 1;
|
||||
};
|
||||
|
||||
#ifndef BBX_APP_BUFFYBOARD
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue