Replace layout code with squeek2lvgl

This commit is contained in:
Johannes Marbach 2021-09-19 21:06:03 +02:00
parent 48ef6651c4
commit 5bb6f52845
7 changed files with 40 additions and 337 deletions

View file

@ -23,7 +23,7 @@ CFLAGS ?= -O3 -g0 -I$(LVGL_DIR)/ -Wall -Wshadow -Wundef -Wmissing-prototypes -Wn
LDFLAGS ?= -lm -linput
BIN = buffyboard
MAINSRC = ./cursor.c ./layout.c ./libinput_multi.c ./main.c ./montserrat_extended_32.c ./sq2lv_layouts.c ./terminal.c ./uinput_device.c
MAINSRC = ./cursor.c ./libinput_multi.c ./main.c ./montserrat_extended_32.c ./sq2lv_layouts.c ./squeek2lvgl/sq2lv.c ./terminal.c ./uinput_device.c
include $(LVGL_DIR)/lvgl/lvgl.mk
include $(LVGL_DIR)/lv_drivers/lv_drivers.mk

229
layout.c
View file

@ -1,229 +0,0 @@
/**
* Copyright 2021 Johannes Marbach
*
* This file is part of buffyboard, 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 "layout.h"
/**
* Static variables
*/
static sq2lv_layout_id_t current_layout_id = -1;
/**
* Static prototypes
*/
/**
* Convert a layer index to an LVGL keyboard mode.
*
* @param layer_index layer index to convert
* @return corresponding LVGL keyboard mode
*/
static lv_keyboard_mode_t layer_index_to_keyboard_mode(int layer_index);
/**
* Convert an LVGL keyboard mode to a layer index.
*
* @param keyboard_mode LVGL keyboard mode to convert
* @return corresponding layer index
*/
static int keyboard_mode_to_layer_index(lv_keyboard_mode_t keyboard_mode);
/**
* Get the layer index corresponding to a keyboard's current mode.
*
* @param keyboard keyboard widget
* @return layer index
*/
static int get_layer_index(lv_obj_t *keyboard);
/**
* Get the index of the destination layer for a layer switcher key in the current layout.
*
* @param keyboard keyboard widget
* @param btn_id button index corresponding to the key
* @return the destination layer's index or -1 if the key is not a layer switcher
*/
static int get_destination_layer_index_for_layer_switcher(lv_obj_t *keyboard, uint16_t btn_id);
/**
* Static functions
*/
static lv_keyboard_mode_t layer_index_to_keyboard_mode(int layer_index) {
switch (layer_index) {
case 0:
return LV_KEYBOARD_MODE_TEXT_LOWER;
case 1:
return LV_KEYBOARD_MODE_TEXT_UPPER;
case 2:
return LV_KEYBOARD_MODE_SPECIAL;
case 3:
return LV_KEYBOARD_MODE_NUMBER;
default:
return -1;
}
}
static int keyboard_mode_to_layer_index(lv_keyboard_mode_t keyboard_mode) {
switch (keyboard_mode) {
case LV_KEYBOARD_MODE_TEXT_LOWER:
return 0;
case LV_KEYBOARD_MODE_TEXT_UPPER:
return 1;
case LV_KEYBOARD_MODE_SPECIAL:
return 2;
case LV_KEYBOARD_MODE_NUMBER:
return 3;
default:
return -1;
}
}
static int get_layer_index(lv_obj_t *keyboard) {
return keyboard_mode_to_layer_index(lv_keyboard_get_mode(keyboard));
}
static int get_destination_layer_index_for_layer_switcher(lv_obj_t *keyboard, uint16_t btn_id) {
if (current_layout_id < 0 || current_layout_id >= sq2lv_num_layouts) {
return -1;
}
int layer_index = get_layer_index(keyboard);
if (layer_index < 0 || layer_index >= sq2lv_layouts[current_layout_id].num_layers) {
return -1;
}
for (int i = 0; i < sq2lv_layouts[current_layout_id].layers[layer_index].num_switchers; ++i) {
if (sq2lv_layouts[current_layout_id].layers[layer_index].switcher_idxs[i] == btn_id) {
return sq2lv_layouts[current_layout_id].layers[layer_index].switcher_dests[i];
}
}
return -1;
}
/**
* Public functions
*/
void bb_layout_switch_layout(lv_obj_t *keyboard, sq2lv_layout_id_t layout_id) {
if (layout_id < 0 || layout_id >= sq2lv_num_layouts) {
return;
}
/* Assign layers */
for (int i = 0; i < sq2lv_layouts[layout_id].num_layers; ++i) {
lv_keyboard_set_map(keyboard, layer_index_to_keyboard_mode(i),
sq2lv_layouts[layout_id].layers[i].keycaps,
sq2lv_layouts[layout_id].layers[i].attributes);
}
/* Switch to default layer if current layer doesn't exist in new layout */
int layer_index = get_layer_index(keyboard);
if (layer_index < 0 || layer_index >= sq2lv_layouts[layout_id].num_layers) {
lv_keyboard_set_mode(keyboard, layer_index_to_keyboard_mode(0));
}
current_layout_id = layout_id;
}
bool bb_layout_is_layer_switcher(lv_obj_t *keyboard, uint16_t btn_id) {
return get_destination_layer_index_for_layer_switcher(keyboard, btn_id) >= 0;
}
bool bb_layout_switch_layer(lv_obj_t *keyboard, uint16_t btn_id) {
int destination_layer_index = get_destination_layer_index_for_layer_switcher(keyboard, btn_id);
if (destination_layer_index < 0 || destination_layer_index >= sq2lv_layouts[current_layout_id].num_layers) {
return false;
}
lv_keyboard_set_mode(keyboard, layer_index_to_keyboard_mode(destination_layer_index));
return true;
}
const int * const bb_layout_get_scancodes(lv_obj_t *keyboard, uint16_t btn_id, int *num_scancodes) {
if (current_layout_id < 0 || current_layout_id >= sq2lv_num_layouts) {
*num_scancodes = 0;
return NULL;
}
int layer_index = get_layer_index(keyboard);
if (layer_index < 0 || layer_index >= sq2lv_layouts[current_layout_id].num_layers) {
*num_scancodes = 0;
return NULL;
}
if (btn_id >= sq2lv_layouts[current_layout_id].layers[layer_index].num_keys) {
*num_scancodes = 0;
return NULL;
}
*num_scancodes = sq2lv_layouts[current_layout_id].layers[layer_index].scancode_nums[btn_id];
if (*num_scancodes == 0) {
return NULL;
}
const int index = sq2lv_layouts[current_layout_id].layers[layer_index].scancode_idxs[btn_id];
return &(sq2lv_layouts[current_layout_id].layers[layer_index].scancodes[index]);
}
bool bb_is_modifier(lv_obj_t *keyboard, uint16_t btn_id) {
if (current_layout_id < 0 || current_layout_id >= sq2lv_num_layouts) {
return false;
}
int layer_index = get_layer_index(keyboard);
if (layer_index < 0 || layer_index >= sq2lv_layouts[current_layout_id].num_layers) {
return false;
}
for (int i = 0; i < sq2lv_layouts[current_layout_id].layers[layer_index].num_modifiers; ++i) {
if (sq2lv_layouts[current_layout_id].layers[layer_index].modifier_idxs[i] == btn_id) {
return true;
}
}
return false;
}
const int * const bb_get_modifier_indexes(lv_obj_t *keyboard, int *num_modifiers) {
if (current_layout_id < 0 || current_layout_id >= sq2lv_num_layouts) {
*num_modifiers = 0;
return NULL;
}
int layer_index = get_layer_index(keyboard);
if (layer_index < 0 || layer_index >= sq2lv_layouts[current_layout_id].num_layers) {
*num_modifiers = 0;
return NULL;
}
*num_modifiers = sq2lv_layouts[current_layout_id].layers[layer_index].num_modifiers;
if (*num_modifiers == 0) {
return NULL;
}
return &(sq2lv_layouts[current_layout_id].layers[layer_index].modifier_idxs[0]);
}

View file

@ -1,80 +0,0 @@
/**
* Copyright 2021 Johannes Marbach
*
* This file is part of buffyboard, 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 BB_LAYOUT_H
#define BB_LAYOUT_H
#include "sq2lv_layouts.h"
/**
* Apply a layout to a keyboard.
*
* @param keyboard keyboard widget
* @param layout_id layout ID
*/
void bb_layout_switch_layout(lv_obj_t *keyboard, sq2lv_layout_id_t layout_id);
/**
* Check if a key acts as a layer switcher in the current layer.
*
* @param keyboard keyboard widget
* @param btn_id button index corresponding to the key
* @return true if a layer switch would happen if the key is pressed, false otherwise
*/
bool bb_layout_is_layer_switcher(lv_obj_t *keyboard, uint16_t btn_id);
/**
* Attempt to perform a layer switch after pressing a key in the current layer.
*
* @param keyboard keyboard widget
* @param btn_id button index corresponding to the pressed key
* @return true if a layer switch was performed, false otherwise
*/
bool bb_layout_switch_layer(lv_obj_t *keyboard, uint16_t btn_id);
/**
* Get scancodes associated with a key in the current layer.
*
* @param keyboard keyboard widget
* @param btn_id button index corresponding to the key
* @param num_scancodes pointer to an integer into which the number of scancodes will be written
* @return pointer into an array of scancodes at the appropriate index
*/
const int * const bb_layout_get_scancodes(lv_obj_t *keyboard, uint16_t btn_id, int *num_scancodes);
/**
* Check if a key is a modifier in the current layer.
*
* @param keyboard keyboard widget
* @param btn_id button index corresponding to the key
* @return true if the key is a modifier, false otherwise
*/
bool bb_is_modifier(lv_obj_t *keyboard, uint16_t btn_id);
/**
* Get the button indexes for all modifier keys in the current layer.
*
* @param keyboard keyboard widget
* @param num_modifiers pointer to an integer into which the number of modifiers will be written
* @return pointer to the array of button indexes corresponding to modifier keys
*/
const int * const bb_get_modifier_indexes(lv_obj_t *keyboard, int *num_modifiers);
#endif /* BB_LAYOUT_H */

View file

@ -416,7 +416,7 @@
*------------------------------------------------*/
#if USE_LIBINPUT || USE_BSD_LIBINPUT || USE_EVDEV || USE_BSD_EVDEV
# ifndef USE_XKB
# define USE_XKB 1
# define USE_XKB 0
# endif
# if USE_XKB

43
main.c
View file

@ -19,16 +19,18 @@
#include "cursor.h"
#include "layout.h"
#include "libinput_multi.h"
#include "sq2lv_layouts.h"
#include "terminal.h"
#include "uinput_device.h"
#include "lvgl/lvgl.h"
#include "lv_drivers/display/fbdev.h"
#include "lv_drivers/indev/libinput_drv.h"
#include "lvgl/lvgl.h"
#include "squeek2lvgl/sq2lv.h"
#include <limits.h>
#include <signal.h>
#include <stdio.h>
@ -89,19 +91,16 @@ static void keyboard_value_changed_cb(lv_event_t *event);
/**
* Emit key down and up events for a key.
*
* @param keyboard keyboard widget
* @param btn_id button index corresponding to the key
* @param key_down true if a key down event should be emitted
* @param key_up true if a key up event should be emitted
*/
static void emit_key_events(lv_obj_t *keyboard, uint16_t btn_id, bool key_down, bool key_up);
static void emit_key_events(uint16_t btn_id, bool key_down, bool key_up);
/**
* Release any previously pressed modifier keys.
*
* @param keyboard keyboard widget
*/
static void pop_checked_modifier_keys(lv_obj_t *keyboard);
static void pop_checked_modifier_keys(void);
/**
@ -126,16 +125,16 @@ static void set_theme(bool is_dark) {
}
static void keyboard_value_changed_cb(lv_event_t *event) {
lv_obj_t *obj = lv_event_get_target(event);
lv_obj_t *kb = lv_event_get_target(event);
uint16_t btn_id = lv_btnmatrix_get_selected_btn(obj);
uint16_t btn_id = lv_btnmatrix_get_selected_btn(kb);
if (btn_id == LV_BTNMATRIX_BTN_NONE) {
return;
}
if (bb_layout_is_layer_switcher(obj, btn_id)) {
pop_checked_modifier_keys(keyboard);
bb_layout_switch_layer(obj, btn_id);
if (sq2lv_is_layer_switcher(kb, btn_id)) {
pop_checked_modifier_keys();
sq2lv_switch_layer(kb, btn_id);
return;
}
@ -143,22 +142,22 @@ static void keyboard_value_changed_cb(lv_event_t *event) {
* contains LV_BTNMATRIX_CTRL_CHECKED. As a result, pressing e.g. CTRL will _un_check the key. To account
* for this, we invert the meaning of "checked" here and elsewhere in the code. */
bool is_modifier = bb_is_modifier(keyboard, btn_id);
bool is_modifier = sq2lv_is_modifier(keyboard, btn_id);
bool is_checked = !lv_btnmatrix_has_btn_ctrl(keyboard, btn_id, LV_BTNMATRIX_CTRL_CHECKED);
/* Emit key events. Suppress key up events for modifiers unless they were unchecked. For checked modifiers
* the key up events are sent with the next non-modifier key press. */
emit_key_events(keyboard, btn_id, true, !is_modifier || !is_checked);
emit_key_events(btn_id, true, !is_modifier || !is_checked);
/* Pop any previously checked modifiers when a non-modifier key was pressed */
if (!is_modifier) {
pop_checked_modifier_keys(keyboard);
pop_checked_modifier_keys();
}
}
static void emit_key_events(lv_obj_t *keyboard, uint16_t btn_id, bool key_down, bool key_up) {
static void emit_key_events(uint16_t btn_id, bool key_down, bool key_up) {
int num_scancodes = 0;
int *scancodes = bb_layout_get_scancodes(keyboard, btn_id, &num_scancodes);
int *scancodes = sq2lv_get_scancodes(keyboard, btn_id, &num_scancodes);
if (key_down) {
/* Emit key down events in forward order */
@ -175,13 +174,13 @@ static void emit_key_events(lv_obj_t *keyboard, uint16_t btn_id, bool key_down,
}
}
static void pop_checked_modifier_keys(lv_obj_t *keyboard) {
static void pop_checked_modifier_keys(void) {
int num_modifiers = 0;
int *modifier_idxs = bb_get_modifier_indexes(keyboard, &num_modifiers);
int *modifier_idxs = sq2lv_get_modifier_indexes(keyboard, &num_modifiers);
for (int i = 0; i < num_modifiers; ++i) {
if (!lv_btnmatrix_has_btn_ctrl(keyboard, modifier_idxs[i], LV_BTNMATRIX_CTRL_CHECKED)) {
emit_key_events(keyboard, modifier_idxs[i], false, true);
emit_key_events(modifier_idxs[i], false, true);
lv_btnmatrix_set_btn_ctrl(keyboard, modifier_idxs[i], LV_BTNMATRIX_CTRL_CHECKED);
}
}
@ -316,7 +315,7 @@ int main(void) {
touchscreen_indevs[i] = lv_indev_drv_register(&touchscreen_indev_drvs[i]);
}
/* Initialise theme and styles */
/* Initialise theme and styles */
set_theme(true);
lv_style_init(&style_text_normal);
lv_style_set_text_font(&style_text_normal, &montserrat_extended_32);
@ -334,7 +333,7 @@ int main(void) {
lv_obj_add_event_cb(keyboard, keyboard_draw_part_begin_cb, LV_EVENT_DRAW_PART_BEGIN, NULL);
/* Apply default keyboard layout */
bb_layout_switch_layout(keyboard, SQ2LV_LAYOUT_TERMINAL_US);
sq2lv_switch_layout(keyboard, SQ2LV_LAYOUT_TERMINAL_US);
/* Start timer for periodically resizing terminals */
lv_timer_create(terminal_resize_timer_cb, 1000, NULL);

View file

@ -1,5 +1,5 @@
/**
* Auto-generated with unsqu33kr
* Auto-generated with squeek2lvgl
**/
#include "sq2lv_layouts.h"
@ -9,7 +9,8 @@
* Layout: US English (Terminal) - generated from terminal/us
**/
static const char * const name_terminal_us = "terminal/us";
static const char * const name_terminal_us = "US English (Terminal)";
static const char * const short_name_terminal_us = "terminal/us";
/* Layer: Lowercase letters - generated from base */
@ -255,14 +256,19 @@ const int sq2lv_num_layouts = 1;
const sq2lv_layout_t sq2lv_layouts[] = {
/* US English (Terminal) */
{
.name = name_terminal_us,
.short_name = short_name_terminal_us,
.num_layers = num_layers_terminal_us,
.layers = layers_terminal_us
}
};
const char * const sq2lv_layout_names =
const char * const sq2lv_layout_names =
"US English (Terminal)";
const char * const sq2lv_layout_short_names =
"terminal/us";
const int sq2lv_num_unique_scancodes = 57;
const int sq2lv_unique_scancodes[] = {

View file

@ -1,5 +1,5 @@
/**
* Auto-generated with unsqu33kr
* Auto-generated with squeek2lvgl
**/
#ifndef SQ2LV_LAYOUTS_H
@ -7,6 +7,8 @@
#include "lvgl/lvgl.h"
#define SQ2LV_SCANCODES_ENABLED 1
/* Layout IDs, values can be used as indexes into the sq2lv_layouts array */
typedef enum {
SQ2LV_LAYOUT_TERMINAL_US = 0
@ -42,6 +44,10 @@ typedef struct {
/* Layout type */
typedef struct {
/* Layout name */
const char * const name;
/* Layout short name */
const char * const short_name;
/* Total number of layers */
const int num_layers;
/* Layers array */
@ -54,6 +60,7 @@ extern const sq2lv_layout_t sq2lv_layouts[];
/* Layout names (suitable for use in lv_dropdown_t) */
extern const char * const sq2lv_layout_names;
extern const char * const sq2lv_layout_short_names;
/* Unique scancodes from all layout (suitable for setting up uinput devices) */
extern const int sq2lv_num_unique_scancodes;