From 2c3686882c77fe2246371e678a7b236b7cecd72f Mon Sep 17 00:00:00 2001 From: philmoz Date: Mon, 27 Nov 2023 22:52:08 +1100 Subject: [PATCH] feat(color): Shortcut keys for onscreen keyboards (#4355) --- radio/src/gui/colorlcd/LvglWrapper.cpp | 2 + .../thirdparty/libopenui/src/keyboard_base.h | 2 + .../libopenui/src/keyboard_number.cpp | 147 +++++++++++++++--- .../libopenui/src/keyboard_number.h | 4 + .../libopenui/src/keyboard_text.cpp | 145 +++++++++++++++-- 5 files changed, 272 insertions(+), 28 deletions(-) diff --git a/radio/src/gui/colorlcd/LvglWrapper.cpp b/radio/src/gui/colorlcd/LvglWrapper.cpp index cd27aa238..2e9c10c07 100644 --- a/radio/src/gui/colorlcd/LvglWrapper.cpp +++ b/radio/src/gui/colorlcd/LvglWrapper.cpp @@ -147,6 +147,8 @@ static void keyboardDriverRead(lv_indev_drv_t *drv, lv_indev_data_t *data) bool is_lvgl_evt = evt_to_indev_data(evt, data); if (!is_lvgl_evt) { auto w = (Window*)lv_obj_get_user_data(obj); + // If no window, check for keyboard window + if (!w) w = Keyboard::keyboardWindow(); dispatch_kb_event(w, evt); return; } diff --git a/radio/src/thirdparty/libopenui/src/keyboard_base.h b/radio/src/thirdparty/libopenui/src/keyboard_base.h index f70a5c7d1..74c2dcfc9 100644 --- a/radio/src/thirdparty/libopenui/src/keyboard_base.h +++ b/radio/src/thirdparty/libopenui/src/keyboard_base.h @@ -31,6 +31,8 @@ class Keyboard : public Window void clearField(bool wasCancelled); static void hide(bool wasCancelled); + static Keyboard* keyboardWindow() { return activeKeyboard; } + protected: static Keyboard *activeKeyboard; diff --git a/radio/src/thirdparty/libopenui/src/keyboard_number.cpp b/radio/src/thirdparty/libopenui/src/keyboard_number.cpp index dc7b17596..e7d7557d4 100644 --- a/radio/src/thirdparty/libopenui/src/keyboard_number.cpp +++ b/radio/src/thirdparty/libopenui/src/keyboard_number.cpp @@ -17,35 +17,34 @@ */ #include "keyboard_number.h" + #include "numberedit.h" constexpr coord_t KEYBOARD_HEIGHT = 90; -NumberKeyboard * NumberKeyboard::_instance = nullptr; +NumberKeyboard* NumberKeyboard::_instance = nullptr; -static const char* const number_kb_map[] = { - "<<", "-", "+", ">>", "\n", - "MIN", "DEF", "+/-", "MAX", "" -}; +static const char* const number_kb_map[] = {"<<", "-", "+", ">>", "\n", + "MIN", "DEF", "+/-", "MAX", ""}; #define LV_KB_BTN(width) LV_BTNMATRIX_CTRL_POPOVER | width #define LV_KB_CTRL(width) LV_KEYBOARD_CTRL_BTN_FLAGS | width static const lv_btnmatrix_ctrl_t number_kb_ctrl_map[] = { LV_KB_BTN(4), LV_KB_BTN(4), LV_KB_BTN(4), LV_KB_BTN(4), - LV_KB_BTN(4), LV_KB_BTN(4), LV_KB_CTRL(4), LV_KB_BTN(4) -}; + LV_KB_BTN(4), LV_KB_BTN(4), LV_KB_CTRL(4), LV_KB_BTN(4)}; static void on_key(lv_event_t* e) { - lv_obj_t * obj = lv_event_get_target(e); + lv_obj_t* obj = lv_event_get_target(e); NumberEdit* edit = (NumberEdit*)lv_event_get_user_data(e); if (!obj || !edit) return; uint16_t btn_id = lv_btnmatrix_get_selected_btn(obj); - if(btn_id == LV_BTNMATRIX_BTN_NONE) return; + if (btn_id == LV_BTNMATRIX_BTN_NONE) return; - const char * txt = lv_btnmatrix_get_btn_text(obj, lv_btnmatrix_get_selected_btn(obj)); - if(txt == NULL) return; + const char* txt = + lv_btnmatrix_get_btn_text(obj, lv_btnmatrix_get_selected_btn(obj)); + if (txt == NULL) return; if (strcmp(txt, "<<") == 0) { edit->onEvent(EVT_VIRTUAL_KEY_BACKWARD); @@ -66,8 +65,123 @@ static void on_key(lv_event_t* e) } } -NumberKeyboard::NumberKeyboard() : - Keyboard(KEYBOARD_HEIGHT) +#if defined(HARDWARE_KEYS) +void NumberKeyboard::onEvent(event_t event) +{ + NumberEdit* edit = (NumberEdit*)field; + +#if (defined(KEYS_GPIO_REG_PAGEUP) || defined(USE_HATS_AS_KEYS)) && !defined(PCBX12S) + // Radios with both PGUP and PGDN buttons except X12S + switch (event) { + case EVT_KEY_BREAK(KEY_SYS): + // "<<" + edit->onEvent(EVT_VIRTUAL_KEY_BACKWARD); + break; + + case EVT_KEY_LONG(KEY_SYS): + killEvents(event); + // "MIN" + edit->onEvent(EVT_VIRTUAL_KEY_MIN); + break; + + case EVT_KEY_BREAK(KEY_MODEL): + // ">>" + edit->onEvent(EVT_VIRTUAL_KEY_FORWARD); + break; + + case EVT_KEY_LONG(KEY_MODEL): + killEvents(event); + // "MAX" + edit->onEvent(EVT_VIRTUAL_KEY_MAX); + break; + + case EVT_KEY_BREAK(KEY_PAGEDN): + // "+" + edit->onEvent(EVT_VIRTUAL_KEY_PLUS); + break; + + case EVT_KEY_BREAK(KEY_PAGEUP): + // "-" + edit->onEvent(EVT_VIRTUAL_KEY_MINUS); + break; + + case EVT_KEY_BREAK(KEY_TELE): + // "+/-" + edit->onEvent(EVT_VIRTUAL_KEY_SIGN); + break; + + case EVT_KEY_LONG(KEY_TELE): + killEvents(event); + // "DEF" + edit->onEvent(EVT_VIRTUAL_KEY_DEFAULT); + break; + + default: + break; + } + +#else + // Radios witb only a single PGUP/DN button or X12S + switch (event) { + case EVT_KEY_BREAK(KEY_SYS): + // "-" + edit->onEvent(EVT_VIRTUAL_KEY_MINUS); + break; + + case EVT_KEY_LONG(KEY_SYS): + killEvents(event); + // "MIN" + edit->onEvent(EVT_VIRTUAL_KEY_MIN); + break; + + case EVT_KEY_BREAK(KEY_MODEL): + // ">>" + edit->onEvent(EVT_VIRTUAL_KEY_FORWARD); + break; + + case EVT_KEY_LONG(KEY_MODEL): + killEvents(event); + // "+/-" + edit->onEvent(EVT_VIRTUAL_KEY_SIGN); + break; + +#if defined(PCBX12S) + case EVT_KEY_BREAK(KEY_PAGEUP): +#endif + case EVT_KEY_BREAK(KEY_PAGEDN): + // "<<" + edit->onEvent(EVT_VIRTUAL_KEY_BACKWARD); + break; + +#if defined(PCBX12S) + case EVT_KEY_LONG(KEY_PAGEUP): +#endif + case EVT_KEY_LONG(KEY_PAGEDN): + killEvents(event); + // "DEF" + edit->onEvent(EVT_VIRTUAL_KEY_DEFAULT); + break; + + case EVT_KEY_BREAK(KEY_TELE): + // "+" + edit->onEvent(EVT_VIRTUAL_KEY_PLUS); + break; + + case EVT_KEY_LONG(KEY_TELE): + killEvents(event); + // "MAX" + edit->onEvent(EVT_VIRTUAL_KEY_MAX); + break; + + default: + break; + } + +#endif +} +#endif + +NumberKeyboard::NumberKeyboard() : Keyboard(KEYBOARD_HEIGHT) { // setup custom keyboard lv_keyboard_set_map(keyboard, LV_KEYBOARD_MODE_USER_1, @@ -76,15 +190,12 @@ NumberKeyboard::NumberKeyboard() : lv_keyboard_set_mode(keyboard, LV_KEYBOARD_MODE_USER_1); } -NumberKeyboard::~NumberKeyboard() -{ - _instance = nullptr; -} +NumberKeyboard::~NumberKeyboard() { _instance = nullptr; } void NumberKeyboard::show(NumberEdit* field) { if (!_instance) _instance = new NumberKeyboard(); - + lv_obj_clear_flag(_instance->lvobj, LV_OBJ_FLAG_HIDDEN); lv_obj_clear_flag(_instance->keyboard, LV_OBJ_FLAG_HIDDEN); diff --git a/radio/src/thirdparty/libopenui/src/keyboard_number.h b/radio/src/thirdparty/libopenui/src/keyboard_number.h index 2c26f446a..a7da58961 100644 --- a/radio/src/thirdparty/libopenui/src/keyboard_number.h +++ b/radio/src/thirdparty/libopenui/src/keyboard_number.h @@ -35,5 +35,9 @@ class NumberKeyboard : public Keyboard static void show(NumberEdit* field); protected: +#if defined(HARDWARE_KEYS) + void onEvent(event_t event) override; +#endif + static NumberKeyboard* _instance; }; diff --git a/radio/src/thirdparty/libopenui/src/keyboard_text.cpp b/radio/src/thirdparty/libopenui/src/keyboard_text.cpp index 685ad510a..4599367dd 100644 --- a/radio/src/thirdparty/libopenui/src/keyboard_text.cpp +++ b/radio/src/thirdparty/libopenui/src/keyboard_text.cpp @@ -17,25 +17,150 @@ */ #include "keyboard_text.h" -#include "textedit.h" + #include "font.h" +#include "textedit.h" constexpr coord_t KEYBOARD_HEIGHT = LCD_H * 2 / 5; -TextKeyboard * TextKeyboard::_instance = nullptr; +TextKeyboard* TextKeyboard::_instance = nullptr; -TextKeyboard::TextKeyboard() : - Keyboard(KEYBOARD_HEIGHT) -{ -} +TextKeyboard::TextKeyboard() : Keyboard(KEYBOARD_HEIGHT) {} -TextKeyboard::~TextKeyboard() -{ - _instance = nullptr; -} +TextKeyboard::~TextKeyboard() { _instance = nullptr; } #if defined(HARDWARE_KEYS) void TextKeyboard::onEvent(event_t event) { + lv_keyboard_t* kb = (lv_keyboard_t*)keyboard; + +#if (defined(KEYS_GPIO_REG_PAGEUP) || defined(USE_HATS_AS_KEYS)) && !defined(PCBX12S) + // Radios with both PGUP and PGDN buttons except X12S + switch (event) { + case EVT_KEY_BREAK(KEY_SYS): { + // Change keyboard mode + lv_keyboard_mode_t mode = lv_keyboard_get_mode(keyboard); + mode = (mode + 1) & 3; + lv_keyboard_set_mode(keyboard, mode); + } break; + + case EVT_KEY_LONG(KEY_MODEL): + killEvents(event); + // Backspace + lv_textarea_del_char(kb->ta); + break; + + case EVT_KEY_BREAK(KEY_PAGEDN): + // Cursor right + lv_textarea_cursor_right(kb->ta); + break; + + case EVT_KEY_BREAK(KEY_PAGEUP): + // Cursor left + lv_textarea_cursor_left(kb->ta); + break; + + case EVT_KEY_LONG(KEY_PAGEDN): { + killEvents(event); + // Cursor to end + int l = strlen(lv_textarea_get_text(kb->ta)); + while (lv_textarea_get_cursor_pos(kb->ta) < l) + lv_textarea_cursor_right(kb->ta); + } break; + + case EVT_KEY_LONG(KEY_PAGEUP): + killEvents(event); + // Cursor to start + while (lv_textarea_get_cursor_pos(kb->ta) > 0) + lv_textarea_cursor_left(kb->ta); + break; + + case EVT_KEY_BREAK(KEY_TELE): { + // Toggle case + char c = lv_textarea_get_text(kb->ta)[lv_textarea_get_cursor_pos(kb->ta)]; + if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z'))) { + c ^= 0x20; + lv_textarea_del_char_forward(kb->ta); + lv_textarea_add_char(kb->ta, c); + lv_textarea_cursor_left(kb->ta); + } + } break; + + case EVT_KEY_LONG(KEY_TELE): + killEvents(event); + // Delete + lv_textarea_del_char_forward(kb->ta); + break; + + default: + break; + } + +#else + // Radios witb only a single PGUP/DN button or X12S + switch (event) { + case EVT_KEY_BREAK(KEY_SYS): + // Cursor left + lv_textarea_cursor_left(kb->ta); + break; + + case EVT_KEY_LONG(KEY_SYS): + killEvents(event); + // Cursor to start + while (lv_textarea_get_cursor_pos(kb->ta) > 0) + lv_textarea_cursor_left(kb->ta); + break; + + case EVT_KEY_BREAK(KEY_MODEL): { + // Change keyboard mode + lv_keyboard_mode_t mode = lv_keyboard_get_mode(keyboard); + mode = (mode + 1) & 3; + lv_keyboard_set_mode(keyboard, mode); + } break; + + case EVT_KEY_LONG(KEY_MODEL): + killEvents(event); + // Backspace + lv_textarea_del_char(kb->ta); + break; + +#if defined(PCBX12S) + case EVT_KEY_BREAK(KEY_PAGEUP): +#endif + case EVT_KEY_BREAK(KEY_PAGEDN): { + // Toggle case + char c = lv_textarea_get_text(kb->ta)[lv_textarea_get_cursor_pos(kb->ta)]; + if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z'))) { + c ^= 0x20; + lv_textarea_del_char_forward(kb->ta); + lv_textarea_add_char(kb->ta, c); + lv_textarea_cursor_left(kb->ta); + } + } break; + + case EVT_KEY_LONG(KEY_PAGEDN): + killEvents(event); + // Delete + lv_textarea_del_char_forward(kb->ta); + break; + + case EVT_KEY_BREAK(KEY_TELE): { + // Cursor right + lv_textarea_cursor_right(kb->ta); + } break; + + case EVT_KEY_LONG(KEY_TELE): { + killEvents(event); + // Cursor to end + int l = strlen(lv_textarea_get_text(kb->ta)); + while (lv_textarea_get_cursor_pos(kb->ta) < l) + lv_textarea_cursor_right(kb->ta); + } break; + + default: + break; + } + +#endif } #endif