keyboard: add haptic feedback
This commit is contained in:
parent
271cdf8534
commit
6b3477dc78
19 changed files with 211 additions and 15 deletions
|
|
@ -1,3 +1,6 @@
|
||||||
|
[keyboard]
|
||||||
|
haptic_feedback=true
|
||||||
|
|
||||||
[theme]
|
[theme]
|
||||||
default=breezy-light
|
default=breezy-light
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,13 @@ static int parsing_handler(void* user_data, const char* section, const char* key
|
||||||
static int parsing_handler(void* user_data, const char* section, const char* key, const char* value) {
|
static int parsing_handler(void* user_data, const char* section, const char* key, const char* value) {
|
||||||
bb_config_opts *opts = (bb_config_opts *)user_data;
|
bb_config_opts *opts = (bb_config_opts *)user_data;
|
||||||
|
|
||||||
if (strcmp(section, "theme") == 0) {
|
if (strcmp(section, "keyboard") == 0) {
|
||||||
|
if (strcmp(key, "haptic_feedback") == 0) {
|
||||||
|
if (bbx_config_parse_bool(value, &(opts->keyboard.haptic_feedback))) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (strcmp(section, "theme") == 0) {
|
||||||
if (strcmp(key, "default") == 0) {
|
if (strcmp(key, "default") == 0) {
|
||||||
bbx_themes_theme_id_t id = bbx_themes_find_theme_with_name(value);
|
bbx_themes_theme_id_t id = bbx_themes_find_theme_with_name(value);
|
||||||
if (id != BBX_THEMES_THEME_NONE) {
|
if (id != BBX_THEMES_THEME_NONE) {
|
||||||
|
|
@ -80,6 +86,7 @@ static int parsing_handler(void* user_data, const char* section, const char* key
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void bb_config_init_opts(bb_config_opts *opts) {
|
void bb_config_init_opts(bb_config_opts *opts) {
|
||||||
|
opts->keyboard.haptic_feedback = true;
|
||||||
opts->theme.default_id = BBX_THEMES_THEME_BREEZY_DARK;
|
opts->theme.default_id = BBX_THEMES_THEME_BREEZY_DARK;
|
||||||
opts->input.pointer = true;
|
opts->input.pointer = true;
|
||||||
opts->input.touchscreen = true;
|
opts->input.touchscreen = true;
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,14 @@
|
||||||
|
|
||||||
#include "sq2lv_layouts.h"
|
#include "sq2lv_layouts.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options related to the keyboard
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/* If true, vibrate on key presses */
|
||||||
|
bool haptic_feedback;
|
||||||
|
} bb_config_opts_keyboard;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Options related to the theme
|
* Options related to the theme
|
||||||
*/
|
*/
|
||||||
|
|
@ -43,6 +51,8 @@ typedef struct {
|
||||||
* Options parsed from config file(s)
|
* Options parsed from config file(s)
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
/* Options related to the keyboard */
|
||||||
|
bb_config_opts_keyboard keyboard;
|
||||||
/* Options related to the theme */
|
/* Options related to the theme */
|
||||||
bb_config_opts_theme theme;
|
bb_config_opts_theme theme;
|
||||||
/* Options related to input devices */
|
/* Options related to input devices */
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include "lvgl/lvgl.h"
|
#include "lvgl/lvgl.h"
|
||||||
|
|
||||||
|
#include "../shared/force_feedback.h"
|
||||||
#include "../shared/indev.h"
|
#include "../shared/indev.h"
|
||||||
#include "../shared/log.h"
|
#include "../shared/log.h"
|
||||||
#include "../shared/theme.h"
|
#include "../shared/theme.h"
|
||||||
|
|
@ -93,6 +94,8 @@ static void keyboard_value_changed_cb(lv_event_t *event) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bbx_force_feedback_play();
|
||||||
|
|
||||||
if (sq2lv_is_layer_switcher(kb, btn_id)) {
|
if (sq2lv_is_layer_switcher(kb, btn_id)) {
|
||||||
pop_checked_modifier_keys();
|
pop_checked_modifier_keys();
|
||||||
sq2lv_switch_layer(kb, btn_id);
|
sq2lv_switch_layer(kb, btn_id);
|
||||||
|
|
@ -296,7 +299,8 @@ int main(int argc, char *argv[]) {
|
||||||
/* Attach input devices and start monitoring for new ones */
|
/* Attach input devices and start monitoring for new ones */
|
||||||
struct bbx_indev_opts input_config = {
|
struct bbx_indev_opts input_config = {
|
||||||
.pointer = conf_opts.input.pointer,
|
.pointer = conf_opts.input.pointer,
|
||||||
.touchscreen = conf_opts.input.touchscreen
|
.touchscreen = conf_opts.input.touchscreen,
|
||||||
|
.force_feedback = conf_opts.keyboard.haptic_feedback
|
||||||
};
|
};
|
||||||
if (bbx_indev_init(fd_epoll, &input_config) == 0)
|
if (bbx_indev_init(fd_epoll, &input_config) == 0)
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,10 @@ static int parsing_handler(void* user_data, const char* section, const char* key
|
||||||
if (bbx_config_parse_bool(value, &(opts->keyboard.popovers))) {
|
if (bbx_config_parse_bool(value, &(opts->keyboard.popovers))) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
} else if (strcmp(key, "haptic_feedback") == 0) {
|
||||||
|
if (bbx_config_parse_bool(value, &(opts->keyboard.haptic_feedback))) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (strcmp(section, "theme") == 0) {
|
} else if (strcmp(section, "theme") == 0) {
|
||||||
if (strcmp(key, "default") == 0) {
|
if (strcmp(key, "default") == 0) {
|
||||||
|
|
@ -190,6 +194,7 @@ void f0_config_init_opts(f0_config_opts *opts) {
|
||||||
opts->keyboard.autohide = true;
|
opts->keyboard.autohide = true;
|
||||||
opts->keyboard.layout_id = SQ2LV_LAYOUT_US;
|
opts->keyboard.layout_id = SQ2LV_LAYOUT_US;
|
||||||
opts->keyboard.popovers = true;
|
opts->keyboard.popovers = true;
|
||||||
|
opts->keyboard.haptic_feedback = true;
|
||||||
opts->textarea.obscured = true;
|
opts->textarea.obscured = true;
|
||||||
opts->textarea.bullet = LV_SYMBOL_BULLET;
|
opts->textarea.bullet = LV_SYMBOL_BULLET;
|
||||||
opts->input.keyboard = true;
|
opts->input.keyboard = true;
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,8 @@ typedef struct {
|
||||||
sq2lv_layout_id_t layout_id;
|
sq2lv_layout_id_t layout_id;
|
||||||
/* If true, display key popovers on press */
|
/* If true, display key popovers on press */
|
||||||
bool popovers;
|
bool popovers;
|
||||||
|
/* If true, vibrate on key presses */
|
||||||
|
bool haptic_feedback;
|
||||||
} f0_config_opts_keyboard;
|
} f0_config_opts_keyboard;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
24
f0rmz/main.c
24
f0rmz/main.c
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include "../shared/backends.h"
|
#include "../shared/backends.h"
|
||||||
#include "../shared/display.h"
|
#include "../shared/display.h"
|
||||||
|
#include "../shared/force_feedback.h"
|
||||||
#include "../shared/header.h"
|
#include "../shared/header.h"
|
||||||
#include "../shared/indev.h"
|
#include "../shared/indev.h"
|
||||||
#include "../shared/keyboard.h"
|
#include "../shared/keyboard.h"
|
||||||
|
|
@ -37,19 +38,19 @@
|
||||||
f0_cli_opts cli_opts;
|
f0_cli_opts cli_opts;
|
||||||
f0_config_opts conf_opts;
|
f0_config_opts conf_opts;
|
||||||
|
|
||||||
bool is_alternate_theme = false;
|
static bool is_alternate_theme = false;
|
||||||
bool is_keyboard_hidden = false;
|
static bool is_keyboard_hidden = false;
|
||||||
|
|
||||||
static char **field_values = NULL;
|
static char **field_values = NULL;
|
||||||
|
|
||||||
int current_field_index = 0;
|
static int current_field_index = 0;
|
||||||
|
|
||||||
lv_obj_t *form_container = NULL;
|
static lv_obj_t *form_container = NULL;
|
||||||
lv_obj_t *form_textarea = NULL;
|
static lv_obj_t *form_textarea = NULL;
|
||||||
lv_obj_t *keyboard = NULL;
|
static lv_obj_t *keyboard = NULL;
|
||||||
|
|
||||||
int32_t content_height_with_kb;
|
static int32_t content_height_with_kb;
|
||||||
int32_t content_height_without_kb;
|
static int32_t content_height_without_kb;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Static prototypes
|
* Static prototypes
|
||||||
|
|
@ -265,7 +266,7 @@ static void exit_failure();
|
||||||
* Static functions
|
* Static functions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void intro_key_cb(lv_event_t *event) {
|
static void intro_key_cb(lv_event_t *event) {
|
||||||
uint32_t key = lv_indev_get_key(lv_indev_active());
|
uint32_t key = lv_indev_get_key(lv_indev_active());
|
||||||
if (key == LV_KEY_ENTER) {
|
if (key == LV_KEY_ENTER) {
|
||||||
get_started_btn_clicked_cb(event);
|
get_started_btn_clicked_cb(event);
|
||||||
|
|
@ -409,6 +410,8 @@ static void keyboard_value_changed_cb(lv_event_t *event) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bbx_force_feedback_play();
|
||||||
|
|
||||||
if (sq2lv_is_layer_switcher(kb, btn_id)) {
|
if (sq2lv_is_layer_switcher(kb, btn_id)) {
|
||||||
sq2lv_switch_layer(kb, btn_id);
|
sq2lv_switch_layer(kb, btn_id);
|
||||||
return;
|
return;
|
||||||
|
|
@ -889,7 +892,8 @@ int main(int argc, char *argv[]) {
|
||||||
.keymap = &conf_opts.hw_keyboard,
|
.keymap = &conf_opts.hw_keyboard,
|
||||||
.keyboard = conf_opts.input.keyboard,
|
.keyboard = conf_opts.input.keyboard,
|
||||||
.pointer = conf_opts.input.pointer,
|
.pointer = conf_opts.input.pointer,
|
||||||
.touchscreen = conf_opts.input.touchscreen
|
.touchscreen = conf_opts.input.touchscreen,
|
||||||
|
.force_feedback = conf_opts.keyboard.haptic_feedback
|
||||||
};
|
};
|
||||||
if (bbx_indev_init(fd_epoll, &input_config) == 0)
|
if (bbx_indev_init(fd_epoll, &input_config) == 0)
|
||||||
exit_failure();
|
exit_failure();
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ result.
|
||||||
|
|
||||||
# NOTES
|
# NOTES
|
||||||
|
|
||||||
Some terminal commands, like _clear_ or _setfont_, can erase the keyboard or brake the layout of the terminal. In this case you should send a signal to Buffyboard or switch to another terminal to update the screen:
|
Some terminal commands, like _clear_ or _setfont_, can erase the keyboard or break the layout of the terminal. In this case you should send a signal to Buffyboard or switch to another terminal to update the screen:
|
||||||
|
|
||||||
```
|
```
|
||||||
setfont solar24x32;/usr/bin/kill -s SIGUSR1 buffyboard
|
setfont solar24x32;/usr/bin/kill -s SIGUSR1 buffyboard
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,11 @@ for and, if found, merged in the following order:
|
||||||
|
|
||||||
# OPTIONS
|
# OPTIONS
|
||||||
|
|
||||||
|
## Keyboard
|
||||||
|
*haptic_feedback* = <true|false>
|
||||||
|
Enable or disable vibrations when pressing keys.
|
||||||
|
Default: true.
|
||||||
|
|
||||||
## Theme
|
## Theme
|
||||||
*default* = <adwaita-light|adwaita-dark|breezy-light|breezy-dark|nord-light|nord-dark|pmos-light|pmos-dark>
|
*default* = <adwaita-light|adwaita-dark|breezy-light|breezy-dark|nord-light|nord-dark|pmos-light|pmos-dark>
|
||||||
Selects the default theme on boot. Can be changed at runtime to the
|
Selects the default theme on boot. Can be changed at runtime to the
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,11 @@ for and, if found, merged in the following order:
|
||||||
|
|
||||||
*popovers* = <true|false>
|
*popovers* = <true|false>
|
||||||
Enable or disable key press popovers showing the selected key.
|
Enable or disable key press popovers showing the selected key.
|
||||||
default: true.
|
Default: true.
|
||||||
|
|
||||||
|
*haptic_feedback* = <true|false>
|
||||||
|
Enable or disable vibrations when pressing keys.
|
||||||
|
Default: true.
|
||||||
|
|
||||||
## Textarea
|
## Textarea
|
||||||
*obscured* = <true|false>
|
*obscured* = <true|false>
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ shared_sources = files(
|
||||||
'shared/fonts/font_32.c',
|
'shared/fonts/font_32.c',
|
||||||
'shared/cli_common.c',
|
'shared/cli_common.c',
|
||||||
'shared/config.c',
|
'shared/config.c',
|
||||||
|
'shared/force_feedback.c',
|
||||||
'shared/indev.c',
|
'shared/indev.c',
|
||||||
'shared/log.c',
|
'shared/log.c',
|
||||||
'shared/theme.c',
|
'shared/theme.c',
|
||||||
|
|
|
||||||
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 "indev.h"
|
||||||
|
|
||||||
#include "cursor/cursor.h"
|
#include "cursor/cursor.h"
|
||||||
|
#include "force_feedback.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
#include "lvgl/lvgl.h"
|
#include "lvgl/lvgl.h"
|
||||||
|
|
@ -93,6 +94,7 @@ static struct {
|
||||||
#endif
|
#endif
|
||||||
uint8_t pointer : 1;
|
uint8_t pointer : 1;
|
||||||
uint8_t touchscreen : 1;
|
uint8_t touchscreen : 1;
|
||||||
|
uint8_t force_feedback : 1;
|
||||||
} options;
|
} options;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -641,6 +643,12 @@ static void attach_input_device(struct udev_device* device) {
|
||||||
break;
|
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);
|
struct libinput_device* dev = libinput_path_add_device(context_libinput, node);
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
bbx_log(BBX_LOG_LEVEL_WARNING, "libinput can't use %s", node);
|
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
|
#endif
|
||||||
options.pointer = opts->pointer;
|
options.pointer = opts->pointer;
|
||||||
options.touchscreen = opts->touchscreen;
|
options.touchscreen = opts->touchscreen;
|
||||||
|
options.force_feedback = opts->force_feedback;
|
||||||
|
|
||||||
attach_input_devices();
|
attach_input_devices();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ struct bbx_indev_opts {
|
||||||
#endif
|
#endif
|
||||||
uint8_t pointer : 1;
|
uint8_t pointer : 1;
|
||||||
uint8_t touchscreen : 1;
|
uint8_t touchscreen : 1;
|
||||||
|
uint8_t force_feedback : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef BBX_APP_BUFFYBOARD
|
#ifndef BBX_APP_BUFFYBOARD
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,10 @@ static int parsing_handler(void* user_data, const char* section, const char* key
|
||||||
if (bbx_config_parse_bool(value, &(opts->keyboard.popovers))) {
|
if (bbx_config_parse_bool(value, &(opts->keyboard.popovers))) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
} else if (strcmp(key, "haptic_feedback") == 0) {
|
||||||
|
if (bbx_config_parse_bool(value, &(opts->keyboard.haptic_feedback))) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (strcmp(section, "textarea") == 0) {
|
} else if (strcmp(section, "textarea") == 0) {
|
||||||
if (strcmp(key, "obscured") == 0) {
|
if (strcmp(key, "obscured") == 0) {
|
||||||
|
|
@ -161,6 +165,7 @@ void ul_config_init_opts(ul_config_opts *opts) {
|
||||||
opts->keyboard.autohide = true;
|
opts->keyboard.autohide = true;
|
||||||
opts->keyboard.layout_id = SQ2LV_LAYOUT_US;
|
opts->keyboard.layout_id = SQ2LV_LAYOUT_US;
|
||||||
opts->keyboard.popovers = true;
|
opts->keyboard.popovers = true;
|
||||||
|
opts->keyboard.haptic_feedback = true;
|
||||||
opts->textarea.obscured = true;
|
opts->textarea.obscured = true;
|
||||||
opts->textarea.bullet = LV_SYMBOL_BULLET;
|
opts->textarea.bullet = LV_SYMBOL_BULLET;
|
||||||
opts->theme.default_id = BBX_THEMES_THEME_BREEZY_DARK;
|
opts->theme.default_id = BBX_THEMES_THEME_BREEZY_DARK;
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,8 @@ typedef struct {
|
||||||
sq2lv_layout_id_t layout_id;
|
sq2lv_layout_id_t layout_id;
|
||||||
/* If true, display key popovers on press */
|
/* If true, display key popovers on press */
|
||||||
bool popovers;
|
bool popovers;
|
||||||
|
/* If true, vibrate on key presses */
|
||||||
|
bool haptic_feedback;
|
||||||
} ul_config_opts_keyboard;
|
} ul_config_opts_keyboard;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
#include "../shared/backends.h"
|
#include "../shared/backends.h"
|
||||||
#include "../shared/display.h"
|
#include "../shared/display.h"
|
||||||
|
#include "../shared/force_feedback.h"
|
||||||
#include "../shared/header.h"
|
#include "../shared/header.h"
|
||||||
#include "../shared/indev.h"
|
#include "../shared/indev.h"
|
||||||
#include "../shared/keyboard.h"
|
#include "../shared/keyboard.h"
|
||||||
|
|
@ -334,6 +335,8 @@ static void keyboard_value_changed_cb(lv_event_t *event) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bbx_force_feedback_play();
|
||||||
|
|
||||||
if (sq2lv_is_layer_switcher(kb, btn_id)) {
|
if (sq2lv_is_layer_switcher(kb, btn_id)) {
|
||||||
sq2lv_switch_layer(kb, btn_id);
|
sq2lv_switch_layer(kb, btn_id);
|
||||||
return;
|
return;
|
||||||
|
|
@ -447,7 +450,8 @@ int main(int argc, char *argv[]) {
|
||||||
.keymap = &conf_opts.hw_keyboard,
|
.keymap = &conf_opts.hw_keyboard,
|
||||||
.keyboard = conf_opts.input.keyboard,
|
.keyboard = conf_opts.input.keyboard,
|
||||||
.pointer = conf_opts.input.pointer,
|
.pointer = conf_opts.input.pointer,
|
||||||
.touchscreen = conf_opts.input.touchscreen
|
.touchscreen = conf_opts.input.touchscreen,
|
||||||
|
.force_feedback = conf_opts.keyboard.haptic_feedback
|
||||||
};
|
};
|
||||||
if (bbx_indev_init(fd_epoll, &input_config) == 0)
|
if (bbx_indev_init(fd_epoll, &input_config) == 0)
|
||||||
exit_failure();
|
exit_failure();
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ animations=true
|
||||||
autohide=false
|
autohide=false
|
||||||
layout=us
|
layout=us
|
||||||
popovers=true
|
popovers=true
|
||||||
|
haptic_feedback=true
|
||||||
|
|
||||||
[textarea]
|
[textarea]
|
||||||
obscured=true
|
obscured=true
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue