Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion Buildscripts/module.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,33 @@ macro(tactility_get_module_name NAME OUT_NAME)
endmacro()

macro(tactility_add_module NAME)
set(options)
# WHOLE_ARCHIVE: force every object file in this module into the final link unconditionally,
# instead of only the ones some other already-scanned archive currently has a pending
# undefined reference to. Needed when this module provides symbols a component it depends on
# (e.g. lvgl__lvgl's custom-allocator hooks) calls back into - a reverse reference a normal
# single-pass static-archive link can't resolve, since that component is scanned after this
# one's archive has already been passed once. POSIX builds link everything as plain OBJECT
# libraries (no archive-pruning to begin with), so this is a no-op there.
set(options WHOLE_ARCHIVE)
set(oneValueArgs)
set(multiValueArgs SRCS INCLUDE_DIRS PRIV_INCLUDE_DIRS REQUIRES PRIV_REQUIRES)
cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

if (DEFINED ENV{ESP_IDF_VERSION})
# idf_component_register's WHOLE_ARCHIVE is a presence-based flag (no value) - only pass
# the token at all when requested, rather than passing ARG_WHOLE_ARCHIVE's TRUE/FALSE as
# a value, which idf_component_register doesn't expect.
set(whole_archive_arg)
if (ARG_WHOLE_ARCHIVE)
set(whole_archive_arg WHOLE_ARCHIVE)
endif()
idf_component_register(
SRCS ${ARG_SRCS}
INCLUDE_DIRS ${ARG_INCLUDE_DIRS}
PRIV_INCLUDE_DIRS ${ARG_PRIV_INCLUDE_DIRS}
REQUIRES ${ARG_REQUIRES}
PRIV_REQUIRES ${ARG_PRIV_REQUIRES}
${whole_archive_arg}
)
else()
add_library(${NAME} OBJECT)
Expand Down
4 changes: 3 additions & 1 deletion Buildscripts/sdkconfig/default.properties
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ CONFIG_LV_FS_STDIO_PATH=""
CONFIG_LV_FS_STDIO_CACHE_SIZE=4096
CONFIG_LV_USE_LODEPNG=y
CONFIG_LV_USE_BUILTIN_MALLOC=n
CONFIG_LV_USE_CLIB_MALLOC=y
# Routes lv_malloc/realloc/free through Modules/lvgl-module/source/lv_mem_custom.c, which prefers
# PSRAM (falls back to internal RAM automatically) instead of a fixed-size pool or plain malloc.
CONFIG_LV_USE_CUSTOM_MALLOC=y
CONFIG_LV_USE_MSGBOX=n
CONFIG_LV_USE_SPINNER=n
CONFIG_LV_USE_WIN=n
Expand Down
12 changes: 6 additions & 6 deletions Devices/cl32/cl32.dts
Original file line number Diff line number Diff line change
Expand Up @@ -44,31 +44,31 @@
37 49 50 51 52 53 54 55 56 0 // % 1 2 3 4 5 6 7 8
57 48 8 91 93 43 34 39 27 0 // 9 0 BKSP [ ] + " ' EXIT
9 113 119 101 114 116 121 117 105 0 // TAB q w e r t y u i
111 112 10 40 41 45 59 58 3 0 // o p ENTER ( ) - ; : STOP
111 112 13 40 41 45 59 58 3 0 // o p ENTER ( ) - ; : STOP
0 97 115 100 102 103 104 106 107 0 // a s d f g h j k
108 17 35 123 125 42 44 46 2 0 // l UP # { } * , . MENU
122 120 99 118 98 32 32 110 109 0 // z x c v b n m
20 18 19 60 62 47 92 61 10 0 // LEFT DOWN RIGHT < > / \ = RUN
20 18 19 60 62 47 92 61 13 0 // LEFT DOWN RIGHT < > / \ = RUN
];
keymap-uc = [
37 49 50 51 52 53 54 55 56 0 // % 1 2 3 4 5 6 7 8
57 48 8 91 93 43 34 39 27 0 // 9 0 BKSP [ ] + " ' EXIT
9 81 87 69 82 84 89 85 73 0 // TAB Q W E R T Y U I
79 80 10 40 41 45 59 58 3 0 // O P ENTER ( ) - ; : STOP
79 80 13 40 41 45 59 58 3 0 // O P ENTER ( ) - ; : STOP
0 65 83 68 70 71 72 74 75 0 // A S D F G H J K
76 17 35 123 125 42 44 46 2 0 // L UP # { } * , . MENU
90 88 67 86 66 32 32 78 77 0 // Z X C V B N M
20 18 19 60 62 47 92 61 10 0 // LEFT DOWN RIGHT < > / \ = RUN
20 18 19 60 62 47 92 61 13 0 // LEFT DOWN RIGHT < > / \ = RUN
];
keymap-sy = [
37 49 50 51 52 53 54 55 56 0 // % 1 2 3 4 5 6 7 8
57 48 8 91 93 43 34 39 27 0 // 9 0 BKSP [ ] + " ' EXIT
9 113 119 101 114 116 121 117 105 0 // TAB q w e r t y u i
111 112 10 40 41 45 59 58 3 0 // o p ENTER ( ) - ; : STOP
111 112 13 40 41 45 59 58 3 0 // o p ENTER ( ) - ; : STOP
0 97 115 100 102 103 104 106 107 0 // a s d f g h j k
108 17 35 123 125 42 44 46 2 0 // l UP # { } * , . MENU
122 120 99 118 98 32 32 110 109 0 // z x c v b n m
20 18 19 60 62 47 92 61 10 0 // LEFT DOWN RIGHT < > / \ = RUN
20 18 19 60 62 47 92 61 13 0 // LEFT DOWN RIGHT < > / \ = RUN
];
shift-row = <4>;
shift-col = <0>;
Expand Down
6 changes: 3 additions & 3 deletions Devices/lilygo-tdeck-max/lilygo,tdeck-max.dts
Original file line number Diff line number Diff line change
Expand Up @@ -74,19 +74,19 @@
keymap-lc = [
113 119 101 114 116 121 117 105 111 112 // q w e r t y u i o p
97 115 100 102 103 104 106 107 108 8 // a s d f g h j k l BACKSPACE
0 122 120 99 118 98 110 109 36 10 // z x c v b n m $ ENTER
0 122 120 99 118 98 110 109 36 13 // z x c v b n m $ ENTER
0 0 0 0 0 11 48 32 0 9 // PREV 0 SPC NEXT
];
keymap-uc = [
81 87 69 82 84 89 85 73 79 80 // Q W E R T Y U I O P
65 83 68 70 71 72 74 75 76 8 // A S D F G H J K L BACKSPACE
0 90 88 67 86 66 78 77 36 10 // Z X C V B N M $ ENTER
0 90 88 67 86 66 78 77 36 13 // Z X C V B N M $ ENTER
0 0 0 0 0 11 48 32 0 9 // PREV 0 SPC NEXT
];
keymap-sy = [
49 50 51 52 53 54 55 56 57 48 // 1 2 3 4 5 6 7 8 9 0
64 35 43 45 42 47 40 41 95 8 // @ # + - * / ( ) _ BACKSPACE
0 33 63 59 58 39 34 44 46 10 // ! ? ; : ' " , . ENTER
0 33 63 59 58 39 34 44 46 13 // ! ? ; : ' " , . ENTER
0 0 0 0 0 11 48 32 0 9 // PREV 0 SPC NEXT
];
shift-row = <2>;
Expand Down
6 changes: 3 additions & 3 deletions Devices/lilygo-tdeck-pro/lilygo,tdeck-pro.dts
Original file line number Diff line number Diff line change
Expand Up @@ -61,19 +61,19 @@
keymap-lc = [
113 119 101 114 116 121 117 105 111 112 // q w e r t y u i o p
97 115 100 102 103 104 106 107 108 8 // a s d f g h j k l BACKSPACE
0 122 120 99 118 98 110 109 36 10 // z x c v b n m $ ENTER
0 122 120 99 118 98 110 109 36 13 // z x c v b n m $ ENTER
0 0 0 0 0 11 48 32 0 9 // PREV 0 SPC NEXT
];
keymap-uc = [
81 87 69 82 84 89 85 73 79 80 // Q W E R T Y U I O P
65 83 68 70 71 72 74 75 76 8 // A S D F G H J K L BACKSPACE
0 90 88 67 86 66 78 77 36 10 // Z X C V B N M $ ENTER
0 90 88 67 86 66 78 77 36 13 // Z X C V B N M $ ENTER
0 0 0 0 0 11 48 32 0 9 // PREV 0 SPC NEXT
];
keymap-sy = [
49 50 51 52 53 54 55 56 57 48 // 1 2 3 4 5 6 7 8 9 0
64 35 43 45 42 47 40 41 95 8 // @ # + - * / ( ) _ BACKSPACE
0 33 63 59 58 39 34 44 46 10 // ! ? ; : ' " , . ENTER
0 33 63 59 58 39 34 44 46 13 // ! ? ; : ' " , . ENTER
0 0 0 0 0 11 48 32 0 9 // PREV 0 SPC NEXT
];
shift-row = <2>;
Expand Down
4 changes: 2 additions & 2 deletions Devices/lilygo-tlora-pager/lilygo,tlora-pager.dts
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,13 @@
columns = <10>;
keymap-lc = [
113 119 101 114 116 121 117 105 111 112 // q w e r t y u i o p
97 115 100 102 103 104 106 107 108 10 // a s d f g h j k l ENTER
97 115 100 102 103 104 106 107 108 13 // a s d f g h j k l ENTER
0 122 120 99 118 98 110 109 0 8 // z x c v b n m BACKSPACE
32 0 0 0 0 0 0 0 0 0 // SPC
];
keymap-uc = [
81 87 69 82 84 89 85 73 79 80 // Q W E R T Y U I O P
65 83 68 70 71 72 74 75 76 10 // A S D F G H J K L ENTER
65 83 68 70 71 72 74 75 76 13 // A S D F G H J K L ENTER
0 90 88 67 86 66 78 77 0 8 // Z X C V B N M BACKSPACE
32 0 0 0 0 0 0 0 0 0 // SPC
];
Expand Down
50 changes: 25 additions & 25 deletions Devices/m5stack-tab5/Source/devices/tab5_keyboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@
#include <freertos/FreeRTOS.h>
#include <freertos/queue.h>

#include <lvgl.h>

#include <cstdlib>
#include <cstring>

Expand Down Expand Up @@ -119,36 +117,38 @@ static constexpr HidMapping KEY_MATRIX_HID_SYM[70] = {
};

// ---------------------------------------------------------------------------
// HID usage code + modifier → LVGL key
// Covers all codes present in the Tab5 matrix tables above. LV_KEY_* are plain uint32_t
// constants - matching KeyboardKeyData::key's driver-defined contract and the same convention
// m5stack-module's cardputer_keyboard.cpp kernel driver already uses.
// HID usage code + modifier → key (Unicode codepoint)
// Covers all codes present in the Tab5 matrix tables above. Every key returns a real Unicode
// codepoint per KeyboardKeyData::key's contract - never an LV_KEY_* constant. Keys with no
// ordinary character of their own (arrows, Tab/Shift+Tab and Ctrl+arrow as focus nav) use the
// CodePoint enum's standard Unicode symbols for the concept (CODEPOINT_FOCUS_PREV/NEXT reused for
// Ctrl+arrow's focus-move aliases). lvgl-module's keyboard.cpp translates all of these back to
// LVGL's own sentinels (CODEPOINT_ESCAPE/BACKSPACE/DELETE already equal their LV_KEY_* counterpart
// numerically, so no translation is needed for those).
//
// `ctrl` only selects the LVGL focus-navigation aliases for the arrow keys. Ctrl chords on
// ordinary keys are NOT folded into the returned value - the C0 control codes a terminal wants
// (Ctrl+C = 0x03, Ctrl+K = 0x0B, ...) collide with the LVGL constants returned here (LV_KEY_END = 3,
// LV_KEY_PREV = 11, ...), so Ctrl is reported out-of-band via KeyboardKeyData::ctrl instead and
// consumers that want control codes derive them themselves.
// Ctrl chords on ordinary keys are NOT folded into the returned value - the C0 control codes a
// terminal wants (Ctrl+C = 0x03, Ctrl+K = 0x0B, ...) would collide with a codepoint-based scheme,
// so Ctrl is reported out-of-band via KeyboardKeyData::ctrl instead and consumers that want
// control codes derive them themselves.
// ---------------------------------------------------------------------------
static uint32_t tab5_translate_key(uint8_t keycode, uint8_t modifier, bool ctrl) {
const bool shift = (modifier & 0x22U) != 0U;

// Navigation → LVGL key constants
// Navigation → key (Unicode codepoint)
switch (keycode) {
case 0x29: return LV_KEY_ESC;
case 0x28: return LV_KEY_ENTER;
case 0x2A: return LV_KEY_BACKSPACE;
case 0x4C: return LV_KEY_DEL;
case 0x2B: return '\t';
// Arrows: Ctrl+arrow = focus navigation, plain arrow = raw cursor movement
case 0x52: return ctrl ? (uint32_t)LV_KEY_PREV : (uint32_t)LV_KEY_UP;
case 0x51: return ctrl ? (uint32_t)LV_KEY_NEXT : (uint32_t)LV_KEY_DOWN;
case 0x50: return ctrl ? (uint32_t)LV_KEY_PREV : (uint32_t)LV_KEY_LEFT;
case 0x4F: return ctrl ? (uint32_t)LV_KEY_NEXT : (uint32_t)LV_KEY_RIGHT;
case 0x29: return CODEPOINT_ESCAPE;
case 0x28: return CODEPOINT_ENTER;
case 0x2A: return CODEPOINT_BACKSPACE;
case 0x4C: return CODEPOINT_DELETE;
case 0x2B: return CODEPOINT_TAB;
case 0x52: return CODEPOINT_ARROW_UP;
case 0x51: return CODEPOINT_ARROW_DOWN;
case 0x50: return CODEPOINT_ARROW_LEFT;
case 0x4F: return CODEPOINT_ARROW_RIGHT;
default: break;
}

// F1-F12 (Sym layer over the number row) have no LVGL/ASCII representation - callers that
// F1-F12 (Sym layer over the number row) have no Unicode/LVGL representation - callers that
// want them read KeyboardKeyData::hid_keycode instead (see drain_events()), which is
// populated for every key regardless of whether `key` itself has a meaningful value.

Expand Down Expand Up @@ -378,9 +378,9 @@ static void drain_events(Device* device, Tab5KeyboardInternal* internal) {
if (internal->ctrl_held) modifier |= 0x01U; // HID LeftCtrl
if (internal->alt_held) modifier |= 0x04U; // HID LeftAlt
const uint32_t lv_key = tab5_translate_key(m.keycode, modifier, internal->ctrl_held);
// Queue whenever there's a HID keycode, even if this key has no LVGL/ASCII
// Queue whenever there's a HID keycode, even if this key has no Unicode/LVGL
// representation (e.g. F1-F12) - lv_key stays 0 for those, callers that only
// care about LVGL/ASCII text ignore a 0 key the same way they always have.
// care about the codepoint ignore a 0 key the same way they always have.
if (pressed) {
// A real key was pressed — this hold is a chord, not a tap
internal->aa_tapped = false;
Expand Down
37 changes: 21 additions & 16 deletions Devices/simulator/Source/drivers/sdl_input.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
#include "sdl_input.h"

#include <lvgl.h>
#include <tactility/drivers/keyboard.h>

#include <SDL2/SDL.h>

Expand All @@ -27,22 +27,27 @@ void push_key(uint32_t key) {
key_queue_count++;
}

// Mirrors LVGL's own lv_sdl_keyboard.c keycode_to_ctrl_key(): maps navigation/control keys to
// LV_KEY_* constants. Printable characters arrive separately via SDL_TEXTINPUT.
uint32_t keycode_to_key(SDL_Keycode sdl_key) {
// Mirrors LVGL's own lv_sdl_keyboard.c keycode_to_ctrl_key(): every key returns a real Unicode
// codepoint per KeyboardKeyData::key's contract - never an LV_KEY_* constant, even for keys with
// no ordinary character of their own (arrows, Tab/Shift+Tab as focus nav, Home/End), which use the
// CodePoint enum's standard Unicode symbols for the concept. lvgl-module's keyboard.cpp translates
// all of these back to LVGL's own sentinels (CODEPOINT_ESCAPE/BACKSPACE/DELETE already equal their
// LV_KEY_* counterpart numerically, so no translation is needed for those). Printable characters
// arrive separately via SDL_TEXTINPUT.
uint32_t keycode_to_key(SDL_Keycode sdl_key, bool shift) {
switch (sdl_key) {
case SDLK_RIGHT: return LV_KEY_RIGHT;
case SDLK_LEFT: return LV_KEY_LEFT;
case SDLK_UP: return LV_KEY_UP;
case SDLK_DOWN: return LV_KEY_DOWN;
case SDLK_ESCAPE: return LV_KEY_ESC;
case SDLK_BACKSPACE: return LV_KEY_BACKSPACE;
case SDLK_DELETE: return LV_KEY_DEL;
case SDLK_RIGHT: return CODEPOINT_ARROW_RIGHT;
case SDLK_LEFT: return CODEPOINT_ARROW_LEFT;
case SDLK_UP: return CODEPOINT_ARROW_UP;
case SDLK_DOWN: return CODEPOINT_ARROW_DOWN;
case SDLK_ESCAPE: return CODEPOINT_ESCAPE;
case SDLK_BACKSPACE: return CODEPOINT_BACKSPACE;
case SDLK_DELETE: return CODEPOINT_DELETE;
case SDLK_RETURN:
case SDLK_KP_ENTER: return LV_KEY_ENTER;
case SDLK_TAB: return LV_KEY_NEXT;
case SDLK_HOME: return LV_KEY_HOME;
case SDLK_END: return LV_KEY_END;
case SDLK_KP_ENTER: return CODEPOINT_ENTER;
case SDLK_TAB: return CODEPOINT_TAB;
case SDLK_HOME: return CODEPOINT_HOME;
case SDLK_END: return CODEPOINT_END;
default: return 0;
}
}
Expand Down Expand Up @@ -75,7 +80,7 @@ void sdl_input_pump() {
}
break;
case SDL_KEYDOWN:
push_key(keycode_to_key(event.key.keysym.sym));
push_key(keycode_to_key(event.key.keysym.sym, (event.key.keysym.mod & KMOD_SHIFT) != 0));
break;
case SDL_TEXTINPUT:
// ASCII only (first byte of event.text.text) - sufficient for a simulator keyboard.
Expand Down
10 changes: 4 additions & 6 deletions Drivers/button-control-module/source/button_control.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
#include <tactility/log.h>
#include <tactility/time.h>

#include <lvgl.h>

#include <cstdlib>

#define TAG "ButtonControl"
Expand Down Expand Up @@ -105,16 +103,16 @@ static error_t start(Device* device) {

error_t error = acquire_button(
config->pin_primary,
two_button_mode ? LV_KEY_ENTER : LV_KEY_NEXT,
two_button_mode ? LV_KEY_ESC : LV_KEY_ENTER,
two_button_mode ? (uint32_t)CODEPOINT_ENTER : (uint32_t)CODEPOINT_ARROW_DOWN,
two_button_mode ? (uint32_t)CODEPOINT_ESCAPE : (uint32_t)CODEPOINT_ENTER,
&internal->primary
);
if (error != ERROR_NONE) {
free(internal);
return error;
}

error = acquire_button(config->pin_secondary, LV_KEY_NEXT, LV_KEY_PREV, &internal->secondary);
error = acquire_button(config->pin_secondary, CODEPOINT_ARROW_DOWN, CODEPOINT_ARROW_UP, &internal->secondary);
if (error != ERROR_NONE) {
if (internal->primary.in_use) {
gpio_descriptor_release(internal->primary.descriptor);
Expand Down Expand Up @@ -176,7 +174,7 @@ static void poll_button(const ButtonControlConfig* config, ButtonControlInternal
}

// Release: decide short vs. long press by elapsed hold duration, then queue a synthetic
// key tap (press followed by release) for the LVGL key this gesture maps to.
// key tap (press followed by release) for the key this gesture maps to.
uint32_t held_ms = now - state->press_start_time;
uint32_t key = held_ms < config->long_press_ms ? state->short_press_key : state->long_press_key;
push_pending(internal, key, true);
Expand Down
16 changes: 7 additions & 9 deletions Drivers/m5stack-module/source/cardputer_adv_keyboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
#include <tactility/error.h>
#include <tactility/log.h>

#include <lvgl.h>

#include <cstdlib>

static constexpr const char* TAG = "CardputerAdvKeyboard";
Expand Down Expand Up @@ -46,24 +44,24 @@ static constexpr int CARDPUTER_ADV_COLS = 14;
// [row][col] on the 4x14 grid, matching the base Cardputer's physical layout. 0 means the cell
// emits nothing (used for the sym/shift cells themselves, and unwired cells on this board).
static const uint32_t cardputer_adv_keymap_lc[CARDPUTER_ADV_ROWS][CARDPUTER_ADV_COLS] = {
{ '`', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', LV_KEY_BACKSPACE },
{ '`', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', CODEPOINT_BACKSPACE },
{ '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\\' },
{ 0, 0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', LV_KEY_ENTER },
{ 0, 0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', CODEPOINT_ENTER },
{ 0, 0, 0, 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', ' ' },
};

static const uint32_t cardputer_adv_keymap_uc[CARDPUTER_ADV_ROWS][CARDPUTER_ADV_COLS] = {
{ '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', LV_KEY_DEL },
{ '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', CODEPOINT_DELETE },
{ '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '|' },
{ 0, 0, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', LV_KEY_ENTER },
{ 0, 0, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', CODEPOINT_ENTER },
{ 0, 0, 0, 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', ' ' },
};

static const uint32_t cardputer_adv_keymap_sym[CARDPUTER_ADV_ROWS][CARDPUTER_ADV_COLS] = {
{ LV_KEY_ESC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ CODEPOINT_ESCAPE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ '\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, LV_KEY_PREV, 0, LV_KEY_ENTER },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, LV_KEY_LEFT, LV_KEY_NEXT, LV_KEY_RIGHT, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, CODEPOINT_ARROW_UP, 0, CODEPOINT_ENTER },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, CODEPOINT_ARROW_LEFT, CODEPOINT_ARROW_DOWN, CODEPOINT_ARROW_RIGHT, 0 },
Comment thread
KenVanHoeylandt marked this conversation as resolved.
};

struct CardputerAdvActiveKey {
Expand Down
Loading
Loading