diff --git a/esp32_marauder/Display.cpp b/esp32_marauder/Display.cpp index e8356fd..76bb08e 100644 --- a/esp32_marauder/Display.cpp +++ b/esp32_marauder/Display.cpp @@ -1045,9 +1045,9 @@ void Display::buildBanner(String msg, int xpos) void Display::main(uint8_t scan_mode) { - if ((scan_mode == LV_JOIN_WIFI) || + /*if ((scan_mode == LV_JOIN_WIFI) || (scan_mode == LV_ADD_SSID)) - lv_task_handler(); + lv_task_handler();*/ return; } // End SPIFFS_functions diff --git a/esp32_marauder/Display.h b/esp32_marauder/Display.h index a570b0e..5f03705 100644 --- a/esp32_marauder/Display.h +++ b/esp32_marauder/Display.h @@ -12,7 +12,7 @@ //#include #include #include -#include +//#include #include #include "SPIFFS.h" #include "Assets.h" diff --git a/esp32_marauder/MenuFunctions.cpp b/esp32_marauder/MenuFunctions.cpp index 21b9a1a..248ffd5 100644 --- a/esp32_marauder/MenuFunctions.cpp +++ b/esp32_marauder/MenuFunctions.cpp @@ -5,10 +5,10 @@ #ifdef HAS_SCREEN extern const unsigned char menu_icons[][66]; -PROGMEM lv_obj_t * slider_label; -PROGMEM lv_obj_t * ta1; -PROGMEM lv_obj_t * ta2; -PROGMEM lv_obj_t * save_name; +//PROGMEM lv_obj_t * slider_label; +//PROGMEM lv_obj_t * ta1; +//PROGMEM lv_obj_t * ta2; +//PROGMEM lv_obj_t * save_name; MenuFunctions::MenuFunctions() { @@ -18,12 +18,11 @@ MenuFunctions::MenuFunctions() /* Interrupt driven periodic handler */ #ifdef HAS_ILI9341 - void MenuFunctions::lv_tick_handler() + /*void MenuFunctions::lv_tick_handler() { lv_tick_inc(LVGL_TICK_PERIOD); } - /* Display flushing */ void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) { extern Display display_obj; @@ -103,11 +102,11 @@ MenuFunctions::MenuFunctions() void MenuFunctions::deinitLVGL() { Serial.println(F("Deinit LVGL")); //lv_deinit(); - } + }*/ // Event handler for settings drop down menus - void setting_dropdown_cb(lv_obj_t * obj, lv_event_t event) { + /*void setting_dropdown_cb(lv_obj_t * obj, lv_event_t event) { } @@ -273,17 +272,17 @@ MenuFunctions::MenuFunctions() if (wifi_scan_obj.connected_network != "") wifi_scan_obj.currentScanMode = WIFI_CONNECTED; } - } + }*/ - void ta_event_cb(lv_obj_t * ta, lv_event_t event) + /*void ta_event_cb(lv_obj_t * ta, lv_event_t event) { if(event == LV_EVENT_CLICKED) { if(kb != NULL) lv_keyboard_set_textarea(kb, ta); } - } + }*/ #endif //// END LV_ARDUINO STUFF @@ -1610,9 +1609,9 @@ void MenuFunctions::RunSetup() this->disable_touch = false; - #ifdef HAS_ILI9341 - this->initLVGL(); - #endif + //#ifdef HAS_ILI9341 + // this->initLVGL(); + //#endif #ifdef MARAUDER_CARDPUTER M5CardputerKeyboard.begin(); @@ -2240,16 +2239,33 @@ void MenuFunctions::RunSetup() clearSSIDsMenu.parentMenu = &wifiGeneralMenu; #ifdef HAS_ILI9341 - this->addNodes(&wifiGeneralMenu, text_table1[1], TFTNAVY, NULL, KEYBOARD_ICO, [this](){ + /*this->addNodes(&wifiGeneralMenu, text_table1[1], TFTNAVY, NULL, KEYBOARD_ICO, [this](){ display_obj.clearScreen(); wifi_scan_obj.StartScan(LV_ADD_SSID, TFT_YELLOW); addSSIDGFX(); + });*/ + this->addNodes(&wifiGeneralMenu, text_table1[1], TFTNAVY, NULL, KEYBOARD_ICO, [this](){ + char ssidBuf[64] = {0}; + bool keep_going = true; + while (keep_going) { + display_obj.clearScreen(); + if (keyboardInput(ssidBuf, sizeof(ssidBuf), "Enter SSID")) { + if (ssidBuf[0] != 0) + wifi_scan_obj.addSSID(String(ssidBuf)); + for (int i = 0; i < 64; i++) + ssidBuf[i] = NULL; + } + else + keep_going = false; + } + + this->changeMenu(current_menu); }); #endif #if (!defined(HAS_ILI9341) && defined(HAS_BUTTONS)) this->addNodes(&wifiGeneralMenu, text_table1[1], TFTNAVY, NULL, KEYBOARD_ICO, [this](){ this->changeMenu(&miniKbMenu, true); - #ifndef HAS_MINI_KB + #ifdef HAS_MINI_KB this->miniKeyboard(&miniKbMenu); #endif }); @@ -2473,9 +2489,17 @@ void MenuFunctions::RunSetup() // Join WiFi using touch screen keyboard #ifdef HAS_TOUCH - wifi_scan_obj.currentScanMode = LV_JOIN_WIFI; + char passwordBuf[64] = {0}; // or prefill with existing SSID + if (keyboardInput(passwordBuf, sizeof(passwordBuf), "Enter Password")) { + //wifi_scan_obj.currentScanMode = LV_JOIN_WIFI; + //wifi_scan_obj.StartScan(LV_JOIN_WIFI, TFT_YELLOW); + wifi_scan_obj.joinWiFi(access_points->get(i).essid, String(passwordBuf), true); + } + + this->changeMenu(&wifiGeneralMenu, false); + /*wifi_scan_obj.currentScanMode = LV_JOIN_WIFI; wifi_scan_obj.StartScan(LV_JOIN_WIFI, TFT_YELLOW); - joinWiFiGFX(access_points->get(i).essid); + joinWiFiGFX(access_points->get(i).essid);*/ #endif }); } @@ -2516,9 +2540,17 @@ void MenuFunctions::RunSetup() // Join WiFi using touch screen keyboard #ifdef HAS_TOUCH - wifi_scan_obj.currentScanMode = LV_JOIN_WIFI; + char passwordBuf[64] = {0}; // or prefill with existing SSID + if (keyboardInput(passwordBuf, sizeof(passwordBuf), "Enter Password")) { + //wifi_scan_obj.currentScanMode = LV_JOIN_WIFI; + //wifi_scan_obj.StartScan(LV_JOIN_WIFI, TFT_YELLOW); + wifi_scan_obj.joinWiFi(access_points->get(i).essid, String(passwordBuf), true); + } + + this->changeMenu(&wifiGeneralMenu, false); + /*wifi_scan_obj.currentScanMode = LV_JOIN_WIFI; wifi_scan_obj.StartScan(LV_JOIN_WIFI, TFT_YELLOW); - joinWiFiGFX(access_points->get(i).essid); + joinWiFiGFX(access_points->get(i).essid);*/ #endif }); } @@ -2554,73 +2586,31 @@ void MenuFunctions::RunSetup() // Join WiFi using touch screen keyboard #ifdef HAS_TOUCH - wifi_scan_obj.currentScanMode = LV_JOIN_WIFI; + /*wifi_scan_obj.currentScanMode = LV_JOIN_WIFI; wifi_scan_obj.StartScan(LV_JOIN_WIFI, TFT_YELLOW); - joinWiFiGFX(ssids->get(i).essid, true); + joinWiFiGFX(ssids->get(i).essid, true);*/ + char passwordBuf[64] = {0}; // or prefill with existing SSID + if (keyboardInput(passwordBuf, sizeof(passwordBuf), "Enter Password")) { + //wifi_scan_obj.currentScanMode = LV_JOIN_WIFI; + //wifi_scan_obj.StartScan(LV_JOIN_WIFI, TFT_YELLOW); + Serial.println("Using SSID: " + (String)ssids->get(i).essid + " Password: " + String(passwordBuf)); + wifi_scan_obj.startWiFi(ssids->get(i).essid, String(passwordBuf)); + } + + this->changeMenu(&wifiGeneralMenu, false); + /*wifi_scan_obj.currentScanMode = LV_JOIN_WIFI; + wifi_scan_obj.StartScan(LV_JOIN_WIFI, TFT_YELLOW); + joinWiFiGFX(access_points->get(i).essid);*/ #endif }); } this->changeMenu(&ssidsMenu, true); }); - /*this->addNodes(&wifiGeneralMenu, "Start Saved AP", TFTWHITE, NULL, KEYBOARD_ICO, [this](){ - String ssid = settings_obj.loadSetting("APSSID"); - String pw = settings_obj.loadSetting("APPW"); - - if ((ssid != "") && (pw != "")) { - wifi_scan_obj.startWiFi(ssid, pw, false); - this->changeMenu(&wifiGeneralMenu); - } - else { - // Add the back button - wifiAPMenu.list->clear(); - this->addNodes(&wifiAPMenu, text09, TFTLIGHTGREY, NULL, 0, [this]() { - this->changeMenu(wifiAPMenu.parentMenu); - }); - - // Populate the menu with buttons - for (int i = 0; i < ssids->size(); i++) { - // This is the menu node - this->addNodes(&wifiAPMenu, ssids->get(i).essid, TFTCYAN, NULL, 255, [this, i](){ - // Join WiFi using mini keyboard - #ifdef HAS_MINI_KB - this->changeMenu(&miniKbMenu); - String password = this->miniKeyboard(&miniKbMenu, true); - if (password != "") { - Serial.println("Using SSID: " + (String)ssids->get(i).essid + " Password: " + (String)password); - wifi_scan_obj.currentScanMode = LV_JOIN_WIFI; - wifi_scan_obj.StartScan(LV_JOIN_WIFI, TFT_YELLOW); - wifi_scan_obj.startWiFi(ssids->get(i).essid, password); - this->changeMenu(current_menu); - } - #endif - - // Join WiFi using touch screen keyboard - #ifdef HAS_TOUCH - wifi_scan_obj.currentScanMode = LV_JOIN_WIFI; - wifi_scan_obj.StartScan(LV_JOIN_WIFI, TFT_YELLOW); - joinWiFiGFX(ssids->get(i).essid, true); - #endif - }); - } - this->changeMenu(&wifiAPMenu); - } - });*/ - wifiStationMenu.parentMenu = &ssidsMenu; this->addNodes(&wifiStationMenu, text09, TFTLIGHTGREY, NULL, 0, [this]() { this->changeMenu(wifiStationMenu.parentMenu, true); }); - //#endif - - //#ifdef HAS_ILI9341 - // this->addNodes(&wifiGeneralMenu, "View AP Info", TFTLIGHTGREY, NULL, 0, [this]() { - // display_obj.clearScreen(); - // wifi_scan_obj.currentScanMode = LV_ADD_SSID; - // wifi_scan_obj.StartScan(LV_ADD_SSID, TFT_WHITE); - // addAPGFX("AP Info"); - // }); - //#endif this->addNodes(&wifiGeneralMenu, "Set MACs", TFTLIGHTGREY, NULL, 0, [this]() { this->changeMenu(&setMacMenu, true); diff --git a/esp32_marauder/MenuFunctions.h b/esp32_marauder/MenuFunctions.h index ecde975..ff47083 100644 --- a/esp32_marauder/MenuFunctions.h +++ b/esp32_marauder/MenuFunctions.h @@ -99,21 +99,21 @@ extern Settings settings_obj; #define FUNNY_BEACON 40 #define FLOCK 41 -PROGMEM void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p); -PROGMEM bool my_touchpad_read(lv_indev_drv_t * indev_driver, lv_indev_data_t * data); +//PROGMEM void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p); +//PROGMEM bool my_touchpad_read(lv_indev_drv_t * indev_driver, lv_indev_data_t * data); -PROGMEM static lv_disp_buf_t disp_buf; -PROGMEM static lv_color_t buf[LV_HOR_RES_MAX * 10]; +//PROGMEM static lv_disp_buf_t disp_buf; +//PROGMEM static lv_color_t buf[LV_HOR_RES_MAX * 10]; -PROGMEM static void ta_event_cb(lv_obj_t * ta, lv_event_t event); -PROGMEM static void join_wifi_keyboard_event_cb(lv_obj_t * keyboard, lv_event_t event); -PROGMEM static void start_ap_keyboard_event_cb(lv_obj_t * keyboard, lv_event_t event); -PROGMEM static void add_ssid_keyboard_event_cb(lv_obj_t * keyboard, lv_event_t event); -PROGMEM static void setting_dropdown_cb(lv_obj_t * btn, lv_event_t event); +//PROGMEM static void ta_event_cb(lv_obj_t * ta, lv_event_t event); +//PROGMEM static void join_wifi_keyboard_event_cb(lv_obj_t * keyboard, lv_event_t event); +//PROGMEM static void start_ap_keyboard_event_cb(lv_obj_t * keyboard, lv_event_t event); +//PROGMEM static void add_ssid_keyboard_event_cb(lv_obj_t * keyboard, lv_event_t event); +//PROGMEM static void setting_dropdown_cb(lv_obj_t * btn, lv_event_t event); // lvgl stuff -PROGMEM static lv_obj_t *kb; -PROGMEM static lv_obj_t * save_as_kb; +//PROGMEM static lv_obj_t *kb; +//PROGMEM static lv_obj_t * save_as_kb; struct Menu; @@ -287,8 +287,8 @@ class MenuFunctions void joinWiFiGFX(String essid, bool start_ap = false); void setGraphScale(float scale); - void initLVGL(); - void deinitLVGL(); + //void initLVGL(); + //void deinitLVGL(); void updateStatusBar(); void addSSIDGFX(); void buildButtons(Menu* menu, int starting_index = 0, String button_name = ""); diff --git a/esp32_marauder/TouchKeyboard.cpp b/esp32_marauder/TouchKeyboard.cpp index e6aaf07..097b191 100644 --- a/esp32_marauder/TouchKeyboard.cpp +++ b/esp32_marauder/TouchKeyboard.cpp @@ -1,277 +1,402 @@ #include "TouchKeyboard.h" -#include // for strlen, memset +#include +#include #ifdef HAS_TOUCH -// display_obj is created in your main .ino extern Display display_obj; -// ---- Layout config ---- - // Keyboard will occupy the bottom half of the screen. static inline int16_t kbHeight() { return TFT_HEIGHT / 2; } static inline int16_t kbYStart() { return TFT_HEIGHT - kbHeight(); } static inline int16_t kbWidth() { return TFT_WIDTH; } static inline int16_t kbXStart() { return 0; } -// We’ll do 4 rows of “normal” keys and 1 special row = 5 rows total static const int KEY_ROWS = 5; -// Character rows (top to bottom of the keyboard area) -static const char ROW0[] = "1234567890"; -static const char ROW1[] = "QWERTYUIOP"; -static const char ROW2[] = "ASDFGHJKL"; -static const char ROW3[] = "ZXCVBNM.-_"; +static const char ROW0_ALPHA[] = "1234567890"; +static const char ROW1_ALPHA[] = "qwertyuiop"; +static const char ROW2_ALPHA[] = "asdfghjkl"; +static const char ROW3_ALPHA[] = "zxcvbnm."; -// Special row: [SPACE] [BKSP] [OK] – handled separately +static const char ROW0_SYM[] = "!@#$%^&*()"; +static const char ROW1_SYM[] = "`~-_=+[]{}"; +static const char ROW2_SYM[] = "\\|;:'\""; +static const char ROW3_SYM[] = ",.<>/?"; -// Touch threshold (adjust if needed) static const uint16_t TOUCH_THRESHOLD = 600; -// --- Helper: draw text area (top half) --- +enum KeyboardLayout { + LAYOUT_ALPHA = 0, + LAYOUT_SYMBOLS +}; -static void drawTextArea(const char *title, const char *buffer) -{ - int16_t areaHeight = TFT_HEIGHT - kbHeight(); +static void drawTextArea(const char *title, const char *buffer) { + int16_t areaHeight = TFT_HEIGHT - kbHeight(); - // Clear text area - display_obj.tft.fillRect(0, 0, TFT_WIDTH, areaHeight, TFT_BLACK); + // Clear text area + display_obj.tft.fillRect(0, 0, TFT_WIDTH, areaHeight, TFT_BLACK); - int16_t cursorY = 2; + int16_t cursorY = 2; - // Optional title - if (title && title[0] != '\0') { - display_obj.tft.setCursor(2, cursorY); - display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK); - display_obj.tft.print(title); - cursorY += 16; - } - - // Draw current text + // Optional title + if (title && title[0] != '\0') { display_obj.tft.setCursor(2, cursorY); - display_obj.tft.setTextColor(TFT_WHITE, TFT_BLACK); - display_obj.tft.print(buffer ? buffer : ""); + display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK); + display_obj.tft.print(title); + cursorY += 16; + } + + // Draw current text + display_obj.tft.setCursor(2, cursorY); + display_obj.tft.setTextColor(TFT_WHITE, TFT_BLACK); + display_obj.tft.print(buffer ? buffer : ""); } -// --- Helper: draw entire keyboard --- +static void drawKeyboard(KeyboardLayout layout, bool caps) { + const int16_t kY = kbYStart(); + const int16_t kH = kbHeight(); + const int16_t kX = kbXStart(); + const int16_t kW = kbWidth(); -static void drawKeyboard() -{ - const int16_t kY = kbYStart(); - const int16_t kH = kbHeight(); - const int16_t kX = kbXStart(); - const int16_t kW = kbWidth(); + const int maxCols = 10; + const int rows = KEY_ROWS; - const int maxCols = 10; // base grid is 10 columns - const int rows = KEY_ROWS; // 4 char rows + 1 special row + const int16_t cellW = kW / maxCols; + const int16_t cellH = kH / rows; - const int16_t cellW = kW / maxCols; - const int16_t cellH = kH / rows; + display_obj.tft.fillRect(kX, kY, kW, kH, TFT_DARKGREY); + display_obj.tft.setTextColor(TFT_BLACK, TFT_DARKGREY); - display_obj.tft.fillRect(kX, kY, kW, kH, TFT_DARKGREY); + // Choose row strings based on layout + const char *rowStringsAlpha[4] = { + ROW0_ALPHA, ROW1_ALPHA, ROW2_ALPHA, ROW3_ALPHA + }; + const char *rowStringsSym[4] = { + ROW0_SYM, ROW1_SYM, ROW2_SYM, ROW3_SYM + }; - display_obj.tft.setTextColor(TFT_BLACK, TFT_DARKGREY); + const char **rowsPtr = (layout == LAYOUT_ALPHA) + ? (const char **)rowStringsAlpha + : (const char **)rowStringsSym; - // Draw normal character rows (0–3) - const char *rowStrings[4] = { ROW0, ROW1, ROW2, ROW3 }; + // Draw normal character rows (0–3) + for (int r = 0; r < 4; ++r) { + const char *row = rowsPtr[r]; - for (int r = 0; r < 4; ++r) { - const char *row = rowStrings[r]; - int rowLen = strlen(row); + // For alpha layout row 3, we will also draw CAPS on the rightmost 2 columns. + // The textual row only covers the first part. + int rowLen = strlen(row); - int16_t rowY = kY + r * cellH; - int16_t xOffset = (maxCols - rowLen); - if (xOffset < 0) xOffset = 0; - xOffset = (xOffset * cellW) / 2; // center row - - for (int i = 0; i < rowLen; ++i) { - int16_t keyX = kX + xOffset + i * cellW; - int16_t keyY = rowY; - - // Key border - display_obj.tft.drawRect(keyX, keyY, cellW, cellH, TFT_BLACK); - - // Label - display_obj.tft.setCursor(keyX + cellW / 2 - 3, keyY + cellH / 2 - 4); - char c[2] = { row[i], '\0' }; - display_obj.tft.print(c); - } - } - - // Special row (row index 4): SPACE | BKSP | OK - int r = 4; int16_t rowY = kY + r * cellH; - // We’ll divide width into 3 segments - int16_t spaceW = kW / 2; // left half for SPACE - int16_t bkspW = kW / 4; // next quarter for BKSP - int16_t okW = kW - spaceW - bkspW; // remaining for OK + // For alpha row 3, we want row chars towards the left, leaving space for CAPS. + int16_t xOffset; + if (layout == LAYOUT_ALPHA && r == 3) { + // Use columns 0..7 for characters, 8..9 for CAPS + xOffset = 0; + } else { + int maxColsRow = maxCols; + xOffset = (maxColsRow - rowLen); + if (xOffset < 0) xOffset = 0; + xOffset = (xOffset * cellW) / 2; // center row + } - int16_t keyX = kX; - // SPACE - display_obj.tft.drawRect(keyX, rowY, spaceW, cellH, TFT_BLACK); - display_obj.tft.setCursor(keyX + 4, rowY + cellH / 2 - 4); - display_obj.tft.print("SPACE"); + for (int i = 0; i < rowLen; ++i) { + int16_t keyX = kX + xOffset + i * cellW; + int16_t keyY = rowY; - keyX += spaceW; - // BKSP - display_obj.tft.drawRect(keyX, rowY, bkspW, cellH, TFT_BLACK); - display_obj.tft.setCursor(keyX + 4, rowY + cellH / 2 - 4); - display_obj.tft.print("BKSP"); + // Key border + display_obj.tft.drawRect(keyX, keyY, cellW, cellH, TFT_BLACK); - keyX += bkspW; - // OK - display_obj.tft.drawRect(keyX, rowY, okW, cellH, TFT_BLACK); - display_obj.tft.setCursor(keyX + okW / 2 - 6, rowY + cellH / 2 - 4); - display_obj.tft.print("OK"); + // Label + display_obj.tft.setCursor(keyX + cellW / 2 - 3, keyY + cellH / 2 - 4); + char c = row[i]; + + // Apply CAPS on alpha letters + if (layout == LAYOUT_ALPHA && r > 0) { + if (c >= 'a' && c <= 'z') { + if (caps) { + c = (char)(c - 'a' + 'A'); + } + } + } + + char s[2] = { c, '\0' }; + display_obj.tft.print(s); + } + + // Draw CAPS key for alpha layout on row 3 (rightmost two columns) + if (layout == LAYOUT_ALPHA && r == 3) { + int16_t capsX = kX + 8 * cellW; + int16_t capsW = 2 * cellW; + + display_obj.tft.drawRect(capsX, rowY, capsW, cellH, TFT_BLACK); + display_obj.tft.setCursor(capsX + 4, rowY + cellH / 2 - 4); + // Show different label based on state + if (caps) { + display_obj.tft.print("caps"); + } else { + display_obj.tft.print("CAPS"); + } + } + } + + // Special row (row index 4): CANCEL | SYMB/ABC | SPACE | BKSP | OK + int r = 4; + int16_t rowY = kY + r * cellH; + + // Divide width into 6 segments: + // [CANCEL][SYMB][SPACE (2 segments)][BKSP][OK] + int16_t segW = kW / 6; + int16_t x0 = kX; + int16_t x1 = x0 + segW; // end CANCEL + int16_t x2 = x1 + segW; // end SYMB + int16_t x3 = x2 + 2 * segW; // end SPACE + int16_t x4 = x3 + segW; // end BKSP + int16_t x5 = x4 + segW; // end OK + + // CANCEL + display_obj.tft.drawRect(x0, rowY, segW, cellH, TFT_BLACK); + display_obj.tft.setCursor(x0 + 4, rowY + cellH / 2 - 4); + display_obj.tft.print("CANCEL"); + + // SYMB / ABC + display_obj.tft.drawRect(x1, rowY, segW, cellH, TFT_BLACK); + display_obj.tft.setCursor(x1 + 4, rowY + cellH / 2 - 4); + if (layout == LAYOUT_ALPHA) { + display_obj.tft.print("SYMB"); + } else { + display_obj.tft.print("ABC"); + } + + display_obj.tft.drawRect(x2, rowY, (x3 - x2), cellH, TFT_BLACK); + display_obj.tft.setCursor(x2 + 4, rowY + cellH / 2 - 4); + display_obj.tft.print("SPACE"); + + display_obj.tft.drawRect(x3, rowY, (x4 - x3), cellH, TFT_BLACK); + display_obj.tft.setCursor(x3 + 4, rowY + cellH / 2 - 4); + display_obj.tft.print("BKSP"); + + display_obj.tft.drawRect(x4, rowY, (x5 - x4), cellH, TFT_BLACK); + display_obj.tft.setCursor(x4 + 4, rowY + cellH / 2 - 4); + display_obj.tft.print("OK"); } -// --- Helper: process a touch and update buffer --- +static bool appendChar(char *buffer, size_t bufLen, char c) { + size_t len = strlen(buffer); + if (len + 1 < bufLen) { + buffer[len] = c; + buffer[len + 1] = '\0'; + return true; + } + return false; +} static KeyboardResult handleKeyboardTouch(uint16_t tx, uint16_t ty, - char *buffer, size_t bufLen) -{ - if (!buffer || bufLen < 2) return KB_NONE; + char *buffer, size_t bufLen, + KeyboardLayout layout, + bool caps) { + if (!buffer || bufLen < 2) return KB_NONE; - const int16_t kY = kbYStart(); - const int16_t kH = kbHeight(); - const int16_t kX = kbXStart(); - const int16_t kW = kbWidth(); - - if (ty < kY || ty >= (kY + kH)) { - // Touch is outside keyboard area - return KB_NONE; - } - - const int maxCols = 10; - const int rows = KEY_ROWS; - const int16_t cellW = kW / maxCols; - const int16_t cellH = kH / rows; - - int rowIndex = (ty - kY) / cellH; - - // Normal rows (0..3) - if (rowIndex >= 0 && rowIndex <= 3) { - const char *rowStrings[4] = { ROW0, ROW1, ROW2, ROW3 }; - const char *row = rowStrings[rowIndex]; - int rowLen = strlen(row); - - int16_t rowY = kY + rowIndex * cellH; - - int16_t xOffset = (maxCols - rowLen); - if (xOffset < 0) xOffset = 0; - xOffset = (xOffset * cellW) / 2; - - // Determine which key in this row - if (tx < kX + xOffset || tx >= kX + xOffset + rowLen * cellW) { - return KB_NONE; - } - - int colIndex = (tx - (kX + xOffset)) / cellW; - if (colIndex < 0 || colIndex >= rowLen) return KB_NONE; - - char c = row[colIndex]; - - // Append char if space - size_t len = strlen(buffer); - if (len + 1 < bufLen) { - buffer[len] = c; - buffer[len + 1] = '\0'; - return KB_CHANGED; - } - return KB_NONE; - } - - // Special row (rowIndex == 4): SPACE | BKSP | OK - if (rowIndex == 4) { - int16_t rowY = kY + rowIndex * cellH; - - int16_t spaceW = kW / 2; - int16_t bkspW = kW / 4; - int16_t okW = kW - spaceW - bkspW; - - int16_t x0 = kX; - int16_t x1 = x0 + spaceW; - int16_t x2 = x1 + bkspW; - int16_t x3 = x2 + okW; - - // SPACE - if (tx >= x0 && tx < x1) { - size_t len = strlen(buffer); - if (len + 1 < bufLen) { - buffer[len] = ' '; - buffer[len + 1] = '\0'; - return KB_CHANGED; - } - return KB_NONE; - } - - // BKSP - if (tx >= x1 && tx < x2) { - size_t len = strlen(buffer); - if (len > 0) { - buffer[len - 1] = '\0'; - return KB_CHANGED; - } - return KB_NONE; - } - - // OK - if (tx >= x2 && tx < x3) { - return KB_DONE; - } - } + const int16_t kY = kbYStart(); + const int16_t kH = kbHeight(); + const int16_t kX = kbXStart(); + const int16_t kW = kbWidth(); + if (ty < kY || ty >= (kY + kH)) { + // Touch is outside keyboard area return KB_NONE; + } + + const int maxCols = 10; + const int rows = KEY_ROWS; + const int16_t cellW = kW / maxCols; + const int16_t cellH = kH / rows; + + int rowIndex = (ty - kY) / cellH; + + // Choose row strings based on layout + const char *rowStringsAlpha[4] = { + ROW0_ALPHA, ROW1_ALPHA, ROW2_ALPHA, ROW3_ALPHA + }; + const char *rowStringsSym[4] = { + ROW0_SYM, ROW1_SYM, ROW2_SYM, ROW3_SYM + }; + + const char **rowsPtr = (layout == LAYOUT_ALPHA) + ? (const char **)rowStringsAlpha + : (const char **)rowStringsSym; + + // Normal rows (0..3) + if (rowIndex >= 0 && rowIndex <= 3) { + const char *row = rowsPtr[rowIndex]; + int rowLen = strlen(row); + + int16_t rowY = kY + rowIndex * cellH; + + // Alpha row 3: characters on columns 0..7, CAPS on columns 8..9 + if (layout == LAYOUT_ALPHA && rowIndex == 3) { + int16_t capsXStart = kX + 8 * cellW; + int16_t capsXEnd = capsXStart + 2 * cellW; + + // Check CAPS region + if (tx >= capsXStart && tx < capsXEnd) { + return KB_TOGGLE_CAPS; + } + + // Characters only in the columns before CAPS + int16_t xOffset = 0; + if (tx < kX || tx >= (kX + 8 * cellW)) { + return KB_NONE; + } + + int colIndex = (tx - (kX + xOffset)) / cellW; + if (colIndex < 0 || colIndex >= rowLen) return KB_NONE; + + char c = row[colIndex]; + // Apply caps mapping + if (c >= 'a' && c <= 'z' && caps) { + c = (char)(c - 'a' + 'A'); + } + + if (appendChar(buffer, bufLen, c)) { + return KB_CHANGED; + } + return KB_NONE; + } + + // All other rows + int16_t xOffset = (maxCols - rowLen); + if (xOffset < 0) xOffset = 0; + xOffset = (xOffset * cellW) / 2; + + if (tx < kX + xOffset || tx >= kX + xOffset + rowLen * cellW) { + return KB_NONE; + } + + int colIndex = (tx - (kX + xOffset)) / cellW; + if (colIndex < 0 || colIndex >= rowLen) return KB_NONE; + + char c = row[colIndex]; + + // Apply caps on alpha letters (rows 1 and 2) + if (layout == LAYOUT_ALPHA && rowIndex > 0) { + if (c >= 'a' && c <= 'z' && caps) { + c = (char)(c - 'a' + 'A'); + } + } + + if (appendChar(buffer, bufLen, c)) { + return KB_CHANGED; + } + return KB_NONE; + } + + // Special row (rowIndex == 4): CANCEL | SYMB/ABC | SPACE | BKSP | OK + if (rowIndex == 4) { + int16_t rowY = kY + rowIndex * cellH; + + int16_t segW = kW / 6; + int16_t x0 = kX; + int16_t x1 = x0 + segW; // end CANCEL + int16_t x2 = x1 + segW; // end SYMB + int16_t x3 = x2 + 2 * segW; // end SPACE + int16_t x4 = x3 + segW; // end BKSP + int16_t x5 = x4 + segW; // end OK + + // CANCEL + if (tx >= x0 && tx < x1) { + return KB_CANCEL; + } + + // SYMB / ABC toggle + if (tx >= x1 && tx < x2) { + return KB_TOGGLE_LAYOUT; + } + + // SPACE (x2..x3) + if (tx >= x2 && tx < x3) { + if (appendChar(buffer, bufLen, ' ')) { + return KB_CHANGED; + } + return KB_NONE; + } + + // BKSP (x3..x4) + if (tx >= x3 && tx < x4) { + size_t len = strlen(buffer); + if (len > 0) { + buffer[len - 1] = '\0'; + return KB_CHANGED; + } + return KB_NONE; + } + + // OK (x4..x5) + if (tx >= x4 && tx < x5) { + return KB_DONE; + } + } + + return KB_NONE; } -// --- Public API: blocking keyboard input --- -bool keyboardInput(char *buffer, size_t bufLen, const char *title) -{ - if (!buffer || bufLen < 2) { +bool keyboardInput(char *buffer, size_t bufLen, const char *title) { + if (!buffer || bufLen < 2) { + return false; + } + + // To force clear, uncomment this: + // buffer[0] = '\0'; + + KeyboardLayout layout = LAYOUT_ALPHA; + bool caps = false; + + drawTextArea(title, buffer); + drawKeyboard(layout, caps); + + uint32_t lastTouchTime = 0; + const uint32_t debounceMs = 120; + + while (true) { + uint16_t x = 0, y = 0; + uint8_t touched = display_obj.updateTouch(&x, &y, TOUCH_THRESHOLD); + + if (touched) { + uint32_t now = millis(); + if (now - lastTouchTime < debounceMs) { + // "debounce" + continue; + } + lastTouchTime = now; + + KeyboardResult r = handleKeyboardTouch(x, y, buffer, bufLen, layout, caps); + + if (r == KB_CHANGED) { + drawTextArea(title, buffer); + } else if (r == KB_DONE) { + drawTextArea(title, buffer); + return true; + } else if (r == KB_CANCEL) { + // Optional: buffer[0] = '\0'; + drawTextArea(title, buffer); return false; + } else if (r == KB_TOGGLE_LAYOUT) { + layout = (layout == LAYOUT_ALPHA) ? LAYOUT_SYMBOLS : LAYOUT_ALPHA; + drawKeyboard(layout, caps); + } else if (r == KB_TOGGLE_CAPS) { + caps = !caps; + drawKeyboard(layout, caps); + } } - // Preserve existing buffer content (caller may prefill) or clear: - // buffer[0] = '\0'; + delay(5); + yield(); + } - drawTextArea(title, buffer); - drawKeyboard(); - - uint32_t lastTouchTime = 0; - const uint32_t debounceMs = 120; - - while (true) { - uint16_t x = 0, y = 0; - uint8_t touched = display_obj.updateTouch(&x, &y, TOUCH_THRESHOLD); - - if (touched) { - uint32_t now = millis(); - if (now - lastTouchTime < debounceMs) { - // crude debounce - continue; - } - lastTouchTime = now; - - KeyboardResult r = handleKeyboardTouch(x, y, buffer, bufLen); - - if (r == KB_CHANGED) { - drawTextArea(title, buffer); - } else if (r == KB_DONE) { - // Redraw once more to ensure final text shown (optional) - drawTextArea(title, buffer); - return true; - } - } - - // Allow other tasks / WiFi / BLE to run - delay(5); - yield(); - } - - // Unreachable - // return false; + return false; } #endif \ No newline at end of file diff --git a/esp32_marauder/TouchKeyboard.h b/esp32_marauder/TouchKeyboard.h index 7c0f0a4..ae744db 100644 --- a/esp32_marauder/TouchKeyboard.h +++ b/esp32_marauder/TouchKeyboard.h @@ -9,9 +9,12 @@ #include enum KeyboardResult { - KB_NONE = 0, - KB_CHANGED, - KB_DONE + KB_NONE = 0, + KB_CHANGED, + KB_DONE, + KB_CANCEL, + KB_TOGGLE_LAYOUT, + KB_TOGGLE_CAPS }; /** @@ -21,8 +24,7 @@ enum KeyboardResult { * @param bufLen Total size of the buffer (including space for '\0'). * @param title Optional title displayed above the text box (can be nullptr). * - * @return true if user pressed OK, false if aborted (currently: you’d have to - * add your own external abort condition – e.g. button press). + * @return true if user pressed OK, false if user pressed CANCEL (or if buffer invalid). */ bool keyboardInput(char *buffer, size_t bufLen, const char *title = nullptr); diff --git a/esp32_marauder/WiFiScan.cpp b/esp32_marauder/WiFiScan.cpp index a72f96c..c6ee69e 100644 --- a/esp32_marauder/WiFiScan.cpp +++ b/esp32_marauder/WiFiScan.cpp @@ -630,6 +630,7 @@ extern "C" { #ifdef HAS_SCREEN String display_string = ""; + display_string.concat(CYAN_KEY); display_string.concat(String(rssi)); display_string.concat(" "); if (serial.length()) { @@ -1349,6 +1350,7 @@ extern "C" { #ifdef HAS_SCREEN String display_string = ""; + display_string.concat(CYAN_KEY); display_string.concat(String(rssi)); display_string.concat(" "); if (serial.length()) { @@ -1879,7 +1881,7 @@ bool WiFiScan::joinWiFi(String ssid, String password, bool gui) int count = 0; if ((WiFi.status() == WL_CONNECTED) && (ssid == connected_network) && (ssid != "")) { - #ifdef HAS_TOUCH + /*#ifdef HAS_TOUCH if (gui) { lv_obj_t * mbox1 = lv_msgbox_create(lv_scr_act(), NULL); lv_msgbox_set_text(mbox1, text_table4[2]); @@ -1887,7 +1889,7 @@ bool WiFiScan::joinWiFi(String ssid, String password, bool gui) lv_obj_set_width(mbox1, 200); lv_obj_align(mbox1, NULL, LV_ALIGN_CENTER, 0, 0); //Align to the corner } - #endif + #endif*/ this->wifi_initialized = true; this->currentScanMode = WIFI_CONNECTED; return true; @@ -1908,7 +1910,7 @@ bool WiFiScan::joinWiFi(String ssid, String password, bool gui) WiFi.begin(ssid.c_str(), password.c_str()); #ifdef HAS_SCREEN - #ifdef HAS_MINI_KB + //#ifdef HAS_MINI_KB if (gui) { display_obj.clearScreen(); display_obj.tft.setCursor(0, TFT_HEIGHT / 2); @@ -1916,7 +1918,7 @@ bool WiFiScan::joinWiFi(String ssid, String password, bool gui) display_obj.tft.print("Connecting"); display_obj.tft.setTextWrap(true, false); } - #endif + //#endif #endif Serial.print(F("Connecting to WiFi")); @@ -1924,25 +1926,25 @@ bool WiFiScan::joinWiFi(String ssid, String password, bool gui) delay(500); Serial.print("."); #ifdef HAS_SCREEN - #ifdef HAS_MINI_KB + //#ifdef HAS_MINI_KB if (gui) { display_obj.tft.print("."); } - #endif + //#endif #endif count++; if (count == 20) { Serial.println(F("\nCould not connect to WiFi network")); #ifdef HAS_SCREEN - #ifdef HAS_MINI_KB + //#ifdef HAS_MINI_KB if (gui) { display_obj.tft.println("\nFailed to connect"); delay(1000); } - #endif + //#endif #endif - #ifdef HAS_TOUCH + /*#ifdef HAS_TOUCH if (gui) { lv_obj_t * mbox1 = lv_msgbox_create(lv_scr_act(), NULL); lv_msgbox_set_text(mbox1, text_table4[3]); @@ -1951,7 +1953,7 @@ bool WiFiScan::joinWiFi(String ssid, String password, bool gui) //lv_obj_set_event_cb(mbox1, event_handler); lv_obj_align(mbox1, NULL, LV_ALIGN_CENTER, 0, 0); //Align to the corner } - #endif + #endif*/ this->wifi_initialized = true; this->StartScan(WIFI_SCAN_OFF, TFT_BLACK); #ifdef HAS_SCREEN @@ -1961,19 +1963,19 @@ bool WiFiScan::joinWiFi(String ssid, String password, bool gui) } } - #ifdef HAS_TOUCH + /*#ifdef HAS_TOUCH lv_obj_t * mbox1 = lv_msgbox_create(lv_scr_act(), NULL); lv_msgbox_set_text(mbox1, text_table4[4]); lv_msgbox_add_btns(mbox1, btns); lv_obj_set_width(mbox1, 200); lv_obj_align(mbox1, NULL, LV_ALIGN_CENTER, 0, 0); //Align to the corner - #endif + #endif*/ this->connected_network = ssid; this->setNetworkInfo(); this->showNetworkInfo(); #ifdef HAS_SCREEN - #ifdef HAS_MINI_KB + //#ifdef HAS_MINI_KB display_obj.tft.println("\nConnected!"); display_obj.tft.print("IP address: "); display_obj.tft.println(this->ip_addr); @@ -1985,7 +1987,7 @@ bool WiFiScan::joinWiFi(String ssid, String password, bool gui) display_obj.tft.println(WiFi.macAddress()); display_obj.tft.println("Returning..."); delay(2000); - #endif + //#endif #endif this->wifi_initialized = true; #ifndef HAS_TOUCH @@ -2007,7 +2009,7 @@ bool WiFiScan::startWiFi(String ssid, String password, bool gui) int count = 0; if ((WiFi.status() == WL_CONNECTED) && (ssid == connected_network) && (ssid != "")) { - #ifdef HAS_TOUCH + /*#ifdef HAS_TOUCH if (gui) { lv_obj_t * mbox1 = lv_msgbox_create(lv_scr_act(), NULL); lv_msgbox_set_text(mbox1, text_table4[2]); @@ -2015,7 +2017,7 @@ bool WiFiScan::startWiFi(String ssid, String password, bool gui) lv_obj_set_width(mbox1, 200); lv_obj_align(mbox1, NULL, LV_ALIGN_CENTER, 0, 0); //Align to the corner } - #endif + #endif*/ this->wifi_initialized = true; this->currentScanMode = WIFI_CONNECTED; return true; @@ -2039,7 +2041,7 @@ bool WiFiScan::startWiFi(String ssid, String password, bool gui) WiFi.softAP(ssid.c_str()); #ifdef HAS_SCREEN - #ifdef HAS_MINI_KB + //#ifdef HAS_MINI_KB if (gui) { display_obj.clearScreen(); display_obj.tft.setCursor(0, TFT_HEIGHT / 2); @@ -2047,25 +2049,25 @@ bool WiFiScan::startWiFi(String ssid, String password, bool gui) display_obj.tft.print("Starting"); display_obj.tft.setTextWrap(true, false); } - #endif + //#endif #endif Serial.print(F("Started WiFi")); - #ifdef HAS_TOUCH + /*#ifdef HAS_TOUCH lv_obj_t * mbox1 = lv_msgbox_create(lv_scr_act(), NULL); lv_msgbox_set_text(mbox1, text_table4[4]); lv_msgbox_add_btns(mbox1, btns); lv_obj_set_width(mbox1, 200); lv_obj_align(mbox1, NULL, LV_ALIGN_CENTER, 0, 0); //Align to the corner - #endif + #endif*/ this->connected_network = ssid; this->setNetworkInfo(); this->showNetworkInfo(); #ifdef HAS_SCREEN - #ifdef HAS_MINI_KB + //#ifdef HAS_MINI_KB display_obj.tft.println(F("\nStarted AP")); display_obj.tft.print(F("IP address: ")); display_obj.tft.println(this->ip_addr); @@ -2077,15 +2079,15 @@ bool WiFiScan::startWiFi(String ssid, String password, bool gui) display_obj.tft.println(WiFi.macAddress()); display_obj.tft.println(F("Returning...")); delay(2000); - #endif + //#endif #endif this->wifi_initialized = true; - #ifndef HAS_TOUCH + //#ifndef HAS_TOUCH this->currentScanMode = WIFI_CONNECTED; #ifdef HAS_SCREEN display_obj.tft.setTextWrap(false, false); #endif - #endif + //#endif //settings_obj.saveSetting("APSSID", ssid); //settings_obj.saveSetting("APPW", password); @@ -3364,7 +3366,7 @@ void WiFiScan::RunAPScan(uint8_t scan_mode, uint16_t color) #ifdef HAS_SCREEN void WiFiScan::RunLvJoinWiFi(uint8_t scan_mode, uint16_t color) { - #ifdef HAS_TOUCH + /*#ifdef HAS_TOUCH display_obj.init(); display_obj.tft.setRotation(1); #endif @@ -3378,7 +3380,7 @@ void WiFiScan::RunAPScan(uint8_t scan_mode, uint16_t color) #ifdef HAS_TOUCH lv_obj_t * scr = lv_cont_create(NULL, NULL); lv_disp_load_scr(scr); - #endif + #endif*/ } #endif @@ -7160,7 +7162,7 @@ void WiFiScan::beaconSnifferCallback(void* buf, wifi_promiscuous_pkt_type_t type getMAC(addr, snifferPacket->payload, 10); display_string.concat(MAGENTA_KEY); display_string.concat((String)snifferPacket->rx_ctrl.rssi); - display_string.concat("PRBE "); + display_string.concat(" "); display_string.concat(addr); display_string.concat(" -> "); display_string.concat(probe_req_essid); @@ -7198,7 +7200,7 @@ void WiFiScan::beaconSnifferCallback(void* buf, wifi_promiscuous_pkt_type_t type getMAC(addr, snifferPacket->payload, 10); display_string.concat(GREEN_KEY); display_string.concat((String)snifferPacket->rx_ctrl.rssi); - display_string.concat("BECN "); + display_string.concat(" "); display_string.concat(addr); display_string.concat(" -> "); display_string.concat(essid); @@ -10120,7 +10122,8 @@ void WiFiScan::main(uint32_t currentTime) (currentScanMode == WIFI_SCAN_MULTISSID) || (currentScanMode == WIFI_SCAN_DEAUTH) || (currentScanMode == WIFI_SCAN_STATION_WAR_DRIVE) || - (currentScanMode == WIFI_SCAN_ALL)) + (currentScanMode == WIFI_SCAN_ALL) || + (currentScanMode == BT_SCAN_FLOCK)) { if (currentTime - initTime >= this->channel_hop_delay * HOP_DELAY) {