From 3b473093ced3e77eaa3111081bb5cffecd920991 Mon Sep 17 00:00:00 2001
From: pymuzard <pymuzard@gmail.com>
Date: Mon, 16 Sep 2024 16:31:36 +0200
Subject: [PATCH 1/3] correction centrage des textes dans une box

---
 lib/graphics/src/Surface.cpp | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/lib/graphics/src/Surface.cpp b/lib/graphics/src/Surface.cpp
index 4c15b761..b3e92490 100644
--- a/lib/graphics/src/Surface.cpp
+++ b/lib/graphics/src/Surface.cpp
@@ -530,14 +530,18 @@ namespace graphics
 
     void Surface::drawTextCentered(std::string &text, const int16_t x, const int16_t y, const uint16_t w, const uint16_t h, const bool horizontallyCentered, const bool verticallyCentered, const std::optional<color_t> color)
     {
-        const uint16_t textWidth = m_sprite.textWidth(text.c_str());
+//        const uint16_t textWidth = m_sprite.textWidth(text.c_str());
+        const uint16_t textWidth = getTextWidth(text.c_str());
+        
         int16_t textPositionX;
         if (horizontallyCentered)
         {
-            if (w == (uint16_t)-1)
+            if (w == (uint16_t)-1) {
                 textPositionX = x + (double)this->getWidth() * 0.5 - (double)textWidth * 0.5;
-            else
+            }
+            else {
                 textPositionX = x + (double)w * 0.5 - (double)textWidth * 0.5;
+            }
         }
         else
         {

From 3b80433871fece5b2aaa8d64bcc01936d4e7a01a Mon Sep 17 00:00:00 2001
From: pymuzard <pymuzard@gmail.com>
Date: Tue, 17 Sep 2024 16:58:20 +0200
Subject: [PATCH 2/3] ajout keyboard 2

---
 lib/gui/src/elements/Image.cpp                |   2 +-
 lib/gui/src/elements/Keyboard2.cpp            | 881 ++++++++++++++++++
 lib/gui/src/elements/Keyboard2.hpp            | 150 +++
 lib/gui/src/gui.hpp                           |   1 +
 lib/lua/src/lua_file.cpp                      |   1 +
 lib/lua/src/lua_gui.cpp                       |  29 +
 lib/lua/src/lua_gui.hpp                       |   1 +
 storage/system/keyboard2/backspace_icon.png   | Bin 0 -> 592 bytes
 storage/system/keyboard2/caps_icon_0.png      | Bin 0 -> 630 bytes
 storage/system/keyboard2/caps_icon_1.png      | Bin 0 -> 674 bytes
 storage/system/keyboard2/caps_icon_2.png      | Bin 0 -> 767 bytes
 storage/system/keyboard2/confirm_icon.png     | Bin 0 -> 877 bytes
 storage/system/keyboard2/exit_icon.png        | Bin 0 -> 1470 bytes
 storage/system/keyboard2/layout_icon_0.png    | Bin 0 -> 3149 bytes
 storage/system/keyboard2/layout_icon_1.png    | Bin 0 -> 1051 bytes
 .../system/keyboard2/trackpad_active_icon.png | Bin 0 -> 865 bytes
 16 files changed, 1064 insertions(+), 1 deletion(-)
 create mode 100644 lib/gui/src/elements/Keyboard2.cpp
 create mode 100644 lib/gui/src/elements/Keyboard2.hpp
 create mode 100644 storage/system/keyboard2/backspace_icon.png
 create mode 100644 storage/system/keyboard2/caps_icon_0.png
 create mode 100644 storage/system/keyboard2/caps_icon_1.png
 create mode 100644 storage/system/keyboard2/caps_icon_2.png
 create mode 100644 storage/system/keyboard2/confirm_icon.png
 create mode 100644 storage/system/keyboard2/exit_icon.png
 create mode 100644 storage/system/keyboard2/layout_icon_0.png
 create mode 100644 storage/system/keyboard2/layout_icon_1.png
 create mode 100644 storage/system/keyboard2/trackpad_active_icon.png

diff --git a/lib/gui/src/elements/Image.cpp b/lib/gui/src/elements/Image.cpp
index 1c9f4dac..e805fc42 100644
--- a/lib/gui/src/elements/Image.cpp
+++ b/lib/gui/src/elements/Image.cpp
@@ -58,7 +58,7 @@ namespace gui::ImagesList
             if (img->surface.use_count() == 1)
             {
                 img = images.erase(img);
-                std::cout << "[Image] image deleted" << std::endl;
+                //std::cout << "[Image] image deleted" << std::endl;
             }
             else
             {
diff --git a/lib/gui/src/elements/Keyboard2.cpp b/lib/gui/src/elements/Keyboard2.cpp
new file mode 100644
index 00000000..171a6290
--- /dev/null
+++ b/lib/gui/src/elements/Keyboard2.cpp
@@ -0,0 +1,881 @@
+//
+// Created by Charles on 13/03/2024.
+//
+
+#include "Keyboard2.hpp"
+
+#include <iostream>
+#include <graphics.hpp>
+#include <libsystem.hpp>
+#include <Surface.hpp>
+
+#include "Box.hpp"
+#include "Filter.hpp"
+#include "Image.hpp"
+
+// Layouts
+constexpr char LAYOUT_LOWERCASE = 0;
+constexpr char LAYOUT_UPPERCASE = 1;
+constexpr char LAYOUT_NUMBERS = 2;
+
+// 0x0_ => Control chars
+constexpr char KEY_NULL = 0x00;
+constexpr char KEY_EXIT = 0x01;
+
+// 0x1_ => Special Chars
+constexpr char KEY_SPACE = 0x10;
+constexpr char KEY_BACKSPACE = 0x11;
+
+// 0x2_ => Modifiers
+constexpr char KEY_CAPS = 0x20;
+
+// -0x1_ => Keyboard Layouts
+constexpr char KEY_LAYOUT_STANDARD = -0x10; // Lowercase or Uppercase, based on context
+constexpr char KEY_LAYOUT_LOWERCASE = -0x11;
+constexpr char KEY_LAYOUT_UPPERCASE = -0x12;
+constexpr char KEY_LAYOUT_NUMBERS = -0x13;
+
+// Caps
+constexpr uint8_t CAPS_NONE = 0;
+constexpr uint8_t CAPS_ONCE = 1;
+constexpr uint8_t CAPS_LOCK = 2;
+
+namespace gui::elements {
+    Keyboard2::Keyboard2(const std::string &defaultText) {
+        m_buffer = defaultText;
+        m_defaultText = defaultText;
+
+        // check with the graphics Orientation ... maybe add a parameter to choose ?
+        m_width = graphics::getScreenWidth();
+        m_height = graphics::getScreenHeight();
+
+        m_x = 0;
+        m_y = 0;
+
+        m_backgroundColor = graphics::packRGB565(255, 255, 255);
+        m_hasEvents = true;
+        m_caps = CAPS_NONE;
+
+        boxHeight = 40;
+        hauteurKeyboard = boxHeight * 4;
+        offsetBord = 5;
+        keyZoomRatio = 1.5;
+        hauteurRetourZoom = 10;
+
+        
+        int16_t largeur9 = (m_width - (9-1)) / static_cast<float>(9);
+        int largeurConfirmation = 40;
+
+//        m_keysCanvas = new Canvas(30, 140, 420, 160);
+        m_keysCanvas = new Canvas(offsetBord, m_height - hauteurKeyboard -offsetBord, m_width-2*offsetBord, hauteurKeyboard);
+        addChild(m_keysCanvas);
+
+        m_layoutLowercase = new char *[4];
+        m_layoutLowercase[0] = new char[10]{'a', 'z', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p'};
+        m_layoutLowercase[1] = new char[10]{'q', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm'};
+        m_layoutLowercase[2] = new char[9]{KEY_CAPS, 'w', 'x', 'c', 'v', 'b', 'n', '\'', KEY_BACKSPACE};
+        m_layoutLowercase[3] = new char[3]{KEY_LAYOUT_NUMBERS, KEY_SPACE, KEY_EXIT};
+
+        m_layoutUppercase = new char *[4];
+        m_layoutUppercase[0] = new char[10]{'A', 'Z', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P'};
+        m_layoutUppercase[1] = new char[10]{'Q', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M'};
+        m_layoutUppercase[2] = new char[9]{KEY_CAPS, 'W', 'X', 'C', 'V', 'B', 'N', '\'', KEY_BACKSPACE};
+        m_layoutUppercase[3] = new char[3]{KEY_LAYOUT_NUMBERS, KEY_SPACE, KEY_EXIT};
+
+        m_layoutNumbers = new char *[4];
+        m_layoutNumbers[0] = new char[10]{'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'};
+        m_layoutNumbers[1] = new char[10]{'+', '-', '*', '/', '(', ')', '[', ']', '<', '>'};
+        m_layoutNumbers[2] = new char[9]{KEY_CAPS, '_', ',', '.', ':', ';', '!', '?', KEY_BACKSPACE};
+        m_layoutNumbers[3] = new char[3]{KEY_LAYOUT_STANDARD, KEY_SPACE, KEY_EXIT};
+
+        m_currentLayout = LAYOUT_LOWERCASE;
+
+        // Create label for text
+          m_label = new Label(offsetBord+1, offsetBord, m_width-2*offsetBord - largeurConfirmation, m_height - hauteurKeyboard-2*offsetBord);
+        // m_label->setFont(graphics::ARIAL);
+        m_label->setFontSize(24);
+        m_label->setCursorEnabled(true);
+        m_label->setText(m_buffer);
+        m_label->setCursorIndex(static_cast<int16_t>(m_buffer.length()));
+        addChild(m_label);
+
+        // Create images box (for better performances ?)
+
+        m_capsBox = new Box(offsetBord+1, m_height-hauteurKeyboard-offsetBord +boxHeight*2+1, largeur9-2, boxHeight-2);
+        m_backspaceBox = new Box(m_width-offsetBord-largeur9+2, m_height-hauteurKeyboard-offsetBord+boxHeight*2+1, largeur9-2, boxHeight-2);
+
+        m_confirmBox = new Box(m_width-largeurConfirmation -offsetBord, offsetBord, largeurConfirmation, boxHeight);
+
+        m_layoutBox = new Box(offsetBord+1, m_height-hauteurKeyboard-offsetBord+boxHeight*3+1, 60-2, boxHeight-2);
+        m_exitBox = new Box(m_width-offsetBord-60+1, m_height-hauteurKeyboard-offsetBord+boxHeight*3+1, 60-2, boxHeight-2);
+
+        m_capsBox->setBackgroundColor(COLOR_LIGHT_GREY);
+        m_capsBox->setRadius(5);
+        m_layoutBox->setBackgroundColor(COLOR_LIGHT_GREY);
+        m_layoutBox->setRadius(5);
+        m_backspaceBox->setBackgroundColor(COLOR_LIGHT_GREY);
+        m_backspaceBox->setRadius(5);
+        m_exitBox->setBackgroundColor(COLOR_LIGHT_GREY);
+        m_exitBox->setRadius(5);
+
+
+
+        // Gestion des key Zoom 
+        const float keyWidth10 = (m_width - (10-1)) / 10 - 1;
+        const float keyWidth9 = (m_width - (9-1)) / 9 - 1;
+
+        // ZoomKey Left 10
+        m_boxdKeyPressed_Left10 = new Box (0, 0, keyWidth10*keyZoomRatio, boxHeight*keyZoomRatio);
+        m_boxdKeyPressed_Left10-> disable();
+        m_CanevasKeyPressed_Left10 = new Canvas(0,0,keyWidth10*keyZoomRatio, boxHeight*keyZoomRatio);
+        m_CanevasKeyPressed_Left10->fillRect(0,0, keyWidth10*keyZoomRatio, boxHeight*keyZoomRatio, COLOR_WHITE);
+
+        std::vector<std::pair<int16_t, int16_t>> verticesLeft10;
+        verticesLeft10.push_back( {0                         , 5} );
+        verticesLeft10.push_back( {0                         , boxHeight*keyZoomRatio} );
+        verticesLeft10.push_back( {keyWidth10-2              , boxHeight*keyZoomRatio} );
+        verticesLeft10.push_back( {keyWidth10*keyZoomRatio-1   , boxHeight*keyZoomRatio-hauteurRetourZoom });
+        verticesLeft10.push_back( {keyWidth10*keyZoomRatio-1   , 5} );
+        verticesLeft10.push_back( {keyWidth10*keyZoomRatio-5-1 , 0} );
+        verticesLeft10.push_back( {5                         , 0} );
+
+        m_CanevasKeyPressed_Left10->fillPolygon(verticesLeft10, COLOR_LIGHT_GREY);
+        m_CanevasKeyPressed_Left10->drawPolygon(verticesLeft10, COLOR_WHITE);
+        m_boxdKeyPressed_Left10->addChild(m_CanevasKeyPressed_Left10);
+        addChild(m_boxdKeyPressed_Left10);
+
+        // ZoomKey Center 10
+        m_boxdKeyPressed_Center10 = new Box (0, 0, keyWidth10*keyZoomRatio, boxHeight*keyZoomRatio);
+        m_boxdKeyPressed_Center10-> disable();
+        m_CanevasKeyPressed_Center10 = new Canvas(0,0,keyWidth10*keyZoomRatio, boxHeight*keyZoomRatio);
+        m_CanevasKeyPressed_Center10->fillRect(0,0, keyWidth10*keyZoomRatio, boxHeight*keyZoomRatio, COLOR_WHITE);
+
+        std::vector<std::pair<int16_t, int16_t>> verticesCenter10;
+        verticesCenter10.push_back( {0                         , 5} );
+        verticesCenter10.push_back( {0                         , boxHeight*keyZoomRatio-hauteurRetourZoom} );
+        verticesCenter10.push_back( {(keyWidth10*keyZoomRatio - keyWidth10 ) /2 , boxHeight*keyZoomRatio} );
+        verticesCenter10.push_back( {(keyWidth10*keyZoomRatio - keyWidth10 ) /2 +keyWidth10, boxHeight*keyZoomRatio} );
+        verticesCenter10.push_back( {keyWidth10*keyZoomRatio-1   , boxHeight*keyZoomRatio-hauteurRetourZoom });
+        verticesCenter10.push_back( {keyWidth10*keyZoomRatio-1   , 5} );
+        verticesCenter10.push_back( {keyWidth10*keyZoomRatio-5-1 , 0} );
+        verticesCenter10.push_back( {5                         , 0} );
+
+        m_CanevasKeyPressed_Center10->fillPolygon(verticesCenter10, COLOR_LIGHT_GREY);
+        m_CanevasKeyPressed_Center10->drawPolygon(verticesCenter10, COLOR_WHITE);
+        m_boxdKeyPressed_Center10->addChild(m_CanevasKeyPressed_Center10);
+        addChild(m_boxdKeyPressed_Center10);
+
+        // ZoomKey Right 10
+        m_boxdKeyPressed_Right10 = new Box (0, 0, keyWidth10*keyZoomRatio, boxHeight*keyZoomRatio);
+        m_boxdKeyPressed_Right10-> disable();
+        m_CanevasKeyPressed_Right10 = new Canvas(0,0,keyWidth10*keyZoomRatio, boxHeight*keyZoomRatio);
+        m_CanevasKeyPressed_Right10->fillRect(0,0, keyWidth10*keyZoomRatio, boxHeight*keyZoomRatio, COLOR_WHITE);
+
+        std::vector<std::pair<int16_t, int16_t>> verticesRight10;
+        verticesRight10.push_back( {0                                       , 5} );
+        verticesRight10.push_back( {0                                       , boxHeight*keyZoomRatio-hauteurRetourZoom} );
+        verticesRight10.push_back( {keyWidth10*keyZoomRatio - keyWidth10+1  , boxHeight*keyZoomRatio} );
+        verticesRight10.push_back( {keyWidth10*keyZoomRatio-1                 , boxHeight*keyZoomRatio} );
+        verticesRight10.push_back( {keyWidth10*keyZoomRatio-1                 , 5 });
+        verticesRight10.push_back( {keyWidth10*keyZoomRatio-5-1               , 0} );
+        verticesRight10.push_back( {5                                       , 0} );
+
+        m_CanevasKeyPressed_Right10->fillPolygon(verticesRight10, COLOR_LIGHT_GREY);
+        m_CanevasKeyPressed_Right10->drawPolygon(verticesRight10, COLOR_WHITE);
+        m_boxdKeyPressed_Right10->addChild(m_CanevasKeyPressed_Right10);
+        addChild(m_boxdKeyPressed_Right10);
+
+        // ZoomKey Center 9
+        m_boxdKeyPressed_Center9 = new Box (0, 0, keyWidth9*keyZoomRatio, boxHeight*keyZoomRatio);
+        m_boxdKeyPressed_Center9-> disable();
+        m_CanevasKeyPressed_Center9 = new Canvas(0,0,keyWidth9*keyZoomRatio, boxHeight*keyZoomRatio);
+        m_CanevasKeyPressed_Center9->fillRect(0,0, keyWidth9*keyZoomRatio, boxHeight*keyZoomRatio, COLOR_WHITE);
+
+        std::vector<std::pair<int16_t, int16_t>> verticesCenter9;
+        verticesCenter9.push_back( {0                         , 5} );
+        verticesCenter9.push_back( {0                         , boxHeight*keyZoomRatio-hauteurRetourZoom} );
+        verticesCenter9.push_back( {(keyWidth9*keyZoomRatio - keyWidth9 ) /2 , boxHeight*keyZoomRatio} );
+        verticesCenter9.push_back( {(keyWidth9*keyZoomRatio - keyWidth9 ) /2 +keyWidth9, boxHeight*keyZoomRatio} );
+        verticesCenter9.push_back( {keyWidth9*keyZoomRatio-1   , boxHeight*keyZoomRatio-hauteurRetourZoom });
+        verticesCenter9.push_back( {keyWidth9*keyZoomRatio-1   , 5} );
+        verticesCenter9.push_back( {keyWidth9*keyZoomRatio-1-5 , 0} );
+        verticesCenter9.push_back( {5                         , 0} );
+
+        m_CanevasKeyPressed_Center9->fillPolygon(verticesCenter9, COLOR_LIGHT_GREY);
+        m_CanevasKeyPressed_Center9->drawPolygon(verticesCenter9, COLOR_WHITE);
+        m_boxdKeyPressed_Center9->addChild(m_CanevasKeyPressed_Center9);
+        addChild(m_boxdKeyPressed_Center9);
+/*
+        m_pressedKey_Right10;
+        m_pressedKey_Left9;
+        m_pressedKey_Left9;
+        m_pressedKey_Center10;        
+        m_pressedKey_Center9;
+*/
+
+        // Create images
+        m_capsIcon0     = new Image(storage::Path("system/Keyboard2/caps_icon_0.png"), 3, 3, largeur9-7, boxHeight-7, COLOR_LIGHT_GREY);
+        m_capsIcon1     = new Image(storage::Path("system/Keyboard2/caps_icon_1.png"), 3, 3, largeur9-7, boxHeight-7, COLOR_LIGHT_GREY);
+        m_capsIcon2     = new Image(storage::Path("system/Keyboard2/caps_icon_2.png"), 3, 3, largeur9-7, boxHeight-7, COLOR_LIGHT_GREY);
+        m_backspaceIcon = new Image(storage::Path("system/Keyboard2/backspace_icon.png"), 3, 3, largeur9-7, boxHeight-7, COLOR_LIGHT_GREY);
+
+        m_layoutIcon0   = new Image(storage::Path("system/Keyboard2/layout_icon_0.png"), 10, 3, 40, boxHeight-7, COLOR_LIGHT_GREY);
+        m_layoutIcon1   = new Image(storage::Path("system/Keyboard2/layout_icon_1.png"), 10, 3, 40, boxHeight-7, COLOR_LIGHT_GREY);
+
+        m_exitIcon      = new Image(storage::Path("system/Keyboard2/exit_icon.png"), 3, 3, 60-4, boxHeight-7, COLOR_LIGHT_GREY);
+        m_confirmIcon   = new Image(storage::Path("system/Keyboard2/confirm_icon.png"), 0, 0, largeurConfirmation, boxHeight);
+
+        // Load images into RAM
+        m_capsIcon0->load();
+        m_capsIcon1->load();
+        m_capsIcon2->load();
+        m_backspaceIcon->load();
+        m_layoutIcon0->load();
+        m_layoutIcon1->load();
+        m_exitIcon->load();
+        m_confirmIcon->load();
+
+        // Add images to boxes
+        m_capsBox->addChild(m_capsIcon0);
+        m_capsBox->addChild(m_capsIcon1);
+        m_capsBox->addChild(m_capsIcon2);
+        m_backspaceBox->addChild(m_backspaceIcon);
+        m_layoutBox->addChild(m_layoutIcon0);
+        m_layoutBox->addChild(m_layoutIcon1);
+        m_exitBox->addChild(m_exitIcon);
+        m_confirmBox->addChild(m_confirmIcon);
+
+        // Add boxes
+        addChild(m_capsBox);
+        addChild(m_layoutBox);
+        addChild(m_backspaceBox);
+        addChild(m_exitBox);
+        addChild(m_confirmBox);
+
+        updateCapsIcon();
+        updateLayoutIcon();
+
+//        m_trackpadActiveBox = new Box(192, 112, 96, 96);
+        m_trackpadActiveBox = new Box((m_width-96) /2, m_height-offsetBord-hauteurKeyboard+12, 96, 96);
+        m_trackpadActiveBox->setBackgroundColor(TFT_BLACK);
+        m_trackpadActiveBox->setRadius(8);
+        addChild(m_trackpadActiveBox);
+
+        m_trackpadActiveIcon = new Image(storage::Path("system/Keyboard2/trackpad_active_icon.png"), 16, 16, 64, 64);
+        m_trackpadActiveIcon->load(TFT_BLACK);
+        m_trackpadActiveBox->addChild(m_trackpadActiveIcon);
+
+        m_trackpadActiveBox->disable();
+
+        m_trackpadTicks = 0;
+        m_trackpadLastDeltaX = 0;
+        m_zoomKeyTicks = 0;
+    }
+
+
+
+    Keyboard2::~Keyboard2() = default;
+
+
+
+    void Keyboard2::render() {
+        m_surface->fillRect(0, 0, m_width, m_height, m_backgroundColor);
+
+        // Input box
+        drawInputBox();
+
+        if (!isTrackpadActive()) {
+            // Draw keys
+            drawKeys();
+        }
+    }
+
+    void Keyboard2::widgetUpdate() {
+        if (isTouched()) {
+            // Get touch position
+            int16_t touchX, touchY;
+            getLastTouchPosRel(&touchX, &touchY);
+
+            const char pressedKey = getKey(touchX, touchY);
+            if (pressedKey == KEY_NULL) {
+                return;
+            }
+
+            //drawZoomKeyLeft10 (touchX, touchY, pressedKey, 10);
+            processKey(pressedKey);
+        }
+
+        if (m_exitBox->isTouched()) {
+            m_buffer = m_defaultText; // Reset text
+            m_exit = true;
+        }
+
+        if (m_confirmBox->isTouched()) {
+            m_exit = true;
+        }
+
+        if (m_backspaceBox->isTouched()) {
+            removeChar();
+
+            // Redraw input box
+            drawInputBox();
+        }
+
+        if (m_capsBox->isTouched()) {
+            switch (m_caps) {
+                case CAPS_NONE:
+                default:
+                    m_currentLayout = LAYOUT_UPPERCASE;
+                    m_caps = CAPS_ONCE;
+                    break;
+                case CAPS_ONCE:
+                    m_currentLayout = LAYOUT_UPPERCASE;
+                    m_caps = CAPS_LOCK;
+                    break;
+                case CAPS_LOCK:
+                    m_currentLayout = LAYOUT_LOWERCASE;
+                    m_caps = CAPS_NONE;
+                    break;
+            }
+
+            updateCapsIcon();
+        }
+
+        if (m_layoutBox->isTouched()) {
+            if (m_currentLayout == LAYOUT_LOWERCASE || m_currentLayout == LAYOUT_UPPERCASE) {
+                m_currentLayout = LAYOUT_NUMBERS;
+            } else if (m_currentLayout == LAYOUT_NUMBERS) {
+                if (m_caps == CAPS_NONE) {
+                    m_currentLayout = LAYOUT_LOWERCASE;
+                } else {
+                    m_currentLayout = LAYOUT_UPPERCASE;
+                }
+            }
+
+            drawKeys();
+            updateLayoutIcon();
+        }
+
+        trackpadUpdate();
+        zoomKeyUpdate();
+    }
+
+    std::string Keyboard2::getText() {
+        const std::string output = m_buffer;
+
+        m_buffer = "";
+
+        return output;
+    }
+
+    void Keyboard2::drawKeys() const {
+        // Reset default settings
+        m_keysCanvas->fillRect(0, 0, m_keysCanvas->getWidth(), m_keysCanvas->getHeight(),
+//                               graphics::packRGB565(125, 126, 127));
+                                graphics::packRGB565(255, 255, 255));
+
+        // Draw every keys
+        drawKeyRow(0*boxHeight, getLayoutCharMap()[0]);
+        drawKeyRow(1*boxHeight, getLayoutCharMap()[1]);
+        drawKeyRow(2*boxHeight, getLayoutCharMap()[2]);
+        drawLastRow(3*boxHeight);
+    }
+
+    void Keyboard2::drawKeyRow(const int16_t y, const char *keys) const {
+
+        uint8_t count = strlen(keys);
+        // calcul de la largeur d'une touche (on laisse 1 entre chacune touche)
+        const float keyWidth = (m_width - (count-1)) / static_cast<float>(count);
+
+        for (uint16_t i = 0; i < count; i++) {
+            drawKey(
+                static_cast<int16_t>(static_cast<float>(i) * keyWidth), // position X
+                y,                                                      // position Y
+                static_cast<int16_t>(keyWidth),                         // largeur touche
+                keys[i]                                                 // Texte de la touche
+            );
+        }
+    }
+
+    void Keyboard2::drawKey(const int16_t x, const int16_t y, const uint16_t w, const char key) const {
+        auto keyString = std::string(1, key);
+//        const float keyWidth = (m_width - (count-1)) / static_cast<float>(count);
+
+        m_keysCanvas->fillRoundRect(x+1, y+1, w-2, boxHeight-2, 5, COLOR_LIGHT_GREY);
+        m_keysCanvas->drawTextCenteredInRect(x+1, y+1, w-2, boxHeight-2, keyString, COLOR_BLACK, true, true, 28);
+    }
+
+    void Keyboard2::drawLastRow(const int16_t y) const {
+        // Draw spacebar
+        m_keysCanvas->fillRoundRect(60+1, y+1, m_width-2*60-2*offsetBord-2, boxHeight-2, 5, COLOR_LIGHT_GREY);
+        m_keysCanvas->fillRect(offsetBord+60+5, y+3*boxHeight/4, m_width-(2*60+2*offsetBord+20), 2, graphics::packRGB565(0, 0, 0));
+    }
+
+        uint8_t Keyboard2::getKeyCol(const int16_t x, const uint8_t keyCount) const {
+        float boxX = offsetBord;
+//        const float keyWidth = 420.0f / static_cast<float>(keyCount);
+        const float keyWidth = (m_width-2*offsetBord) / static_cast<float>(keyCount);
+
+        for (uint8_t i = 0; i < keyCount; i++) {
+            if (static_cast<float>(x) >=  boxX && static_cast<float>(x) <= boxX + keyWidth) {
+                return i;
+            }
+            boxX += keyWidth;
+        }
+        return -1;
+    }
+
+    char Keyboard2::getKey(const int16_t x, const int16_t y) const {
+        // Check if the position is in the Keyboard2 box
+
+
+        Keyboard2::Coord result;
+        result = getRowColumn(x, y);
+
+        if (result.row == -1 && result.column == -1) {
+            return KEY_NULL;
+        }
+
+/*
+
+        std::cout << "x = " << x << " y = " << y << std::endl;
+        if (!(x >= offsetBord && x <= m_width-offsetBord && y >= m_height - hauteurKeyboard - offsetBord && y <= m_height - offsetBord)) {
+            std::cout << "NULL KEY"<< std::endl;
+            return KEY_NULL;
+        }                                
+
+        int row;
+        int column;
+
+        row =  3 - (int) (m_height -  y - offsetBord)/boxHeight;
+        if (row <3) {
+            column = getKeyCol(x, strlen(getLayoutCharMap()[row]));
+
+        } else {
+            // Get column of last row
+            if (x <= 60 + offsetBord) {
+                column = 0;
+            } else if (x > m_width - offsetBord-60) {
+                column = 2;
+            } else {
+                column = 1;
+            }
+        }
+*/
+        return getLayoutCharMap()[result.row][result.column];
+    }
+
+
+    Keyboard2::Coord Keyboard2::getRowColumn(const int16_t x, const int16_t y) const {
+        // Check if the position is in the Keyboard2 box
+//        if (!(x >= 30 && x <= 450 && y >= 140 && y <= 300)) {
+        Coord result;
+        result.row = -1;
+        result.column = -1;
+//        std::cout << "[getRowColumn]  x=" << x << " y=" << y << std::endl;
+
+
+        if (!(x >= offsetBord && x <= m_width-offsetBord && y >= m_height - hauteurKeyboard - offsetBord && y <= m_height - offsetBord)) {
+//            std::cout << "[getRowColumn] Hors Champs x=" << x << " y=" << y <<std::endl;
+            return result;
+        }                                
+
+        uint16_t row;
+        uint16_t column;
+
+        row =  3 - (uint16_t) (m_height -  y - offsetBord)/boxHeight;
+//        std::cout << "[getRowColumn] row=" << row <<std:: endl;
+
+        if (row <3) {
+            column = getKeyCol(x, strlen(getLayoutCharMap()[row]));
+
+        } else {
+            // Get column of last row
+            if (x <= 60 + offsetBord) {
+                column = 0;
+            } else if (x > m_width - offsetBord-60) {
+                column = 2;
+            } else {
+                column = 1;
+            }
+        }
+//        std::cout << "[getRowColumn] column=" << column <<std:: endl;
+
+        result.row = row;
+        result.column = column;
+
+        return result;
+    }
+
+
+
+    /**
+     * Execute the needed action for the key
+     * @param key The key to process
+     */
+    void Keyboard2::processKey(const char key) {
+        switch (key) {
+            case KEY_NULL:
+            case KEY_EXIT:
+            case KEY_BACKSPACE:
+            case KEY_CAPS:
+            case KEY_LAYOUT_STANDARD:
+            case KEY_LAYOUT_NUMBERS:
+                // KEY_EXIT & KEY_BACKSPACE & KEY_CAPS & KEY_LAYOUT_STANDARD & KEY_LAYOUT_NUMBERS are handled directly in update function
+                return;
+            case KEY_SPACE:
+                addChar(' ');
+                break;
+            default:
+                addChar(key);
+
+            // Disable caps if not locked
+                if (m_caps == CAPS_ONCE) {
+                    m_currentLayout = LAYOUT_LOWERCASE;
+                    m_caps = CAPS_NONE;
+
+                    drawKeys();
+                    updateCapsIcon(); // Fix bug
+
+                    return;
+                }
+                break;
+        }
+        // Redraw input box
+        drawInputBox(); // <= Useless, because "markDirty" redraws it
+    }
+
+    void Keyboard2::drawInputBox() const {
+        if (m_buffer.empty()) {
+            if (m_placeholder.empty()) {
+                m_label->setText("");
+                return;
+            }
+
+            // Draw placeholder
+            m_label->setTextColor(graphics::packRGB565(200, 200, 200));
+            m_label->setText(m_placeholder);
+
+            m_label->setCursorEnabled(false);
+        } else {
+            // Draw text
+            m_label->setTextColor(graphics::packRGB565(0, 0, 0));
+            m_label->setText(m_buffer);
+
+            m_label->setCursorEnabled(true);
+        }
+    }
+
+
+    void Keyboard2::updateCapsIcon() const {
+        switch (m_caps) {
+            case CAPS_NONE:
+                m_capsIcon0->enable();
+                m_capsIcon1->disable();
+                m_capsIcon2->disable();
+                break;
+            case CAPS_ONCE:
+                m_capsIcon0->disable();
+                m_capsIcon1->enable();
+                m_capsIcon2->disable();
+                break;
+            case CAPS_LOCK:
+                m_capsIcon0->disable();
+                m_capsIcon1->disable();
+                m_capsIcon2->enable();
+                break;
+            default: ;
+        }
+    }
+
+    void Keyboard2::updateLayoutIcon() const {
+        switch (m_currentLayout) {
+            case LAYOUT_LOWERCASE:
+            case LAYOUT_UPPERCASE:
+                m_layoutIcon0->enable();
+                m_layoutIcon1->disable();
+                break;
+            case LAYOUT_NUMBERS:
+                m_layoutIcon0->disable();
+                m_layoutIcon1->enable();
+                break;
+            default: ;
+        }
+    }
+
+    bool Keyboard2::hasExitKeyBeenPressed() const {
+        return m_exit;
+    }
+
+    void Keyboard2::setPlaceholder(const std::string &placeholder) {
+        m_placeholder = placeholder;
+    }
+
+    char **Keyboard2::getLayoutCharMap() const {
+        switch (m_currentLayout) {
+            case LAYOUT_LOWERCASE:
+            default:
+                return m_layoutLowercase;
+            case LAYOUT_UPPERCASE:
+                return m_layoutUppercase;
+            case LAYOUT_NUMBERS:
+                return m_layoutNumbers;
+        }
+    }
+
+    void Keyboard2::trackpadUpdate() {
+        int16_t rawTouchX, rawTouchY;
+        graphics::getTouchPos(&rawTouchX, &rawTouchY);
+
+        const bool wasTrackpadActive = isTrackpadActive();
+
+        // Check if finger is on screen
+        if ((rawTouchX != -1 && rawTouchY != -1) && isPointInTrackpad(originTouchX, originTouchY)) {
+
+            if (m_trackpadTicks < UINT8_MAX) {
+                m_trackpadTicks++;
+            }
+
+            if (isTrackpadActive()) {
+                if (m_trackpadTicks == 10) {
+                    m_trackpadActiveBox->enable();
+                    m_trackpadLastDeltaX = 0;
+                    localGraphicalUpdate();
+                }
+
+                const int32_t deltaX = rawTouchX - originTouchX;
+                std::string deltaXString = std::to_string(deltaX);
+
+                constexpr int32_t stepsByChar = 8;
+                const int32_t toMove = (deltaX - m_trackpadLastDeltaX) / stepsByChar;
+
+                if (toMove > 0) {
+                    for (int i = 0; i < toMove; i++) {
+                        m_label->setCursorIndex(static_cast<int16_t>(m_label->getCursorIndex() + 1));
+                    }
+                } else if (toMove < 0) {
+                    for (int i = 0; i < -toMove; i++) {
+                        m_label->setCursorIndex(static_cast<int16_t>(m_label->getCursorIndex() - 1));
+                    }
+                }
+
+                if (abs(toMove) > 0) {
+                    m_label->forceUpdate();
+                    // m_trackpadActiveBox->forceUpdate();
+                }
+
+                m_trackpadLastDeltaX += toMove * stepsByChar;
+            }
+        } else {
+            m_trackpadTicks = 0;
+
+            if (wasTrackpadActive) {
+                // Do once
+                // m_trackpadFilter->disable();
+                m_trackpadActiveBox->disable();
+                localGraphicalUpdate();
+            }
+        }
+    }
+
+    bool Keyboard2::isPointInTrackpad(const int16_t x, const int16_t y) const {
+
+        if (x < 60+1 || x > 60+1 + m_width-2*60-2*offsetBord-2) return false;
+        if (y< m_height -offsetBord- boxHeight || y > m_height - offsetBord) return false;
+
+        return true;
+    }
+
+    bool Keyboard2::isTrackpadActive() const {
+        return m_trackpadTicks >= 10;
+    }
+
+    void Keyboard2::addChar(const char value) {
+        m_buffer.insert(m_label->getCursorIndex(), 1, value);
+
+        // Update cursor position
+        // TODO: Remove m_buffer and use only label ?
+        m_label->setText(m_buffer);
+        m_label->setCursorIndex(m_label->getCursorIndex() + 1);
+    }
+
+    void Keyboard2::removeChar() {
+        if (m_buffer.empty()) {
+            return;
+        }
+        if (m_label->getCursorIndex() <= 0) {
+            return;
+        }
+
+        m_buffer.erase(m_label->getCursorIndex() - 1, 1);
+        m_label->setCursorIndex(static_cast<int16_t>(m_label->getCursorIndex() - 1));
+    }
+
+
+
+    void Keyboard2::drawZoomKeyLeft10 (uint16_t x, uint16_t y,uint16_t keyWidth , char key)
+    {
+
+        // Create Box for the current pressed key
+        m_boxdKeyPressed_Left10->enable();
+        m_boxdKeyPressed_Left10->setX(x);
+        m_boxdKeyPressed_Left10->setY(y);
+        
+        auto keyString = std::string(1, key);
+        m_CanevasKeyPressed_Left10->fillRect(3,3,keyWidth*keyZoomRatio-7, boxHeight*keyZoomRatio-hauteurRetourZoom, COLOR_LIGHT_GREY);
+        m_CanevasKeyPressed_Left10->drawTextCenteredInRect(3,3,keyWidth*keyZoomRatio-7, boxHeight*keyZoomRatio-hauteurRetourZoom, keyString, COLOR_BLACK, true, true, 38);
+
+
+    }
+
+ void Keyboard2::drawZoomKeyCenter10 (uint16_t x, uint16_t y,uint16_t keyWidth , char key)
+    {
+
+        // Create Box for the current pressed key
+        m_boxdKeyPressed_Center10->enable();
+        m_boxdKeyPressed_Center10->setX(x);
+        m_boxdKeyPressed_Center10->setY(y);
+        
+        auto keyString = std::string(1, key);
+        m_CanevasKeyPressed_Center10->fillRect(3,3,keyWidth*keyZoomRatio-7, boxHeight*keyZoomRatio-hauteurRetourZoom, COLOR_LIGHT_GREY);
+        m_CanevasKeyPressed_Center10->drawTextCenteredInRect(3,3,keyWidth*keyZoomRatio-7, boxHeight*keyZoomRatio-hauteurRetourZoom, keyString, COLOR_BLACK, true, true, 38);
+
+    }
+
+    void Keyboard2::drawZoomKeyRight10 (uint16_t x, uint16_t y,uint16_t keyWidth , char key)
+    {
+
+        // Create Box for the current pressed key
+        m_boxdKeyPressed_Right10->enable();
+        m_boxdKeyPressed_Right10->setX(x);
+        m_boxdKeyPressed_Right10->setY(y);
+        
+        auto keyString = std::string(1, key);
+        m_CanevasKeyPressed_Right10->fillRect(3,3,keyWidth*keyZoomRatio-7, boxHeight*keyZoomRatio-hauteurRetourZoom, COLOR_LIGHT_GREY);
+        m_CanevasKeyPressed_Right10->drawTextCenteredInRect(3,3,keyWidth*keyZoomRatio-7, boxHeight*keyZoomRatio-hauteurRetourZoom, keyString, COLOR_BLACK, true, true, 38);
+
+    }
+    
+ void Keyboard2::drawZoomKeyCenter9 (uint16_t x, uint16_t y,uint16_t keyWidth , char key)
+    {
+
+        // Create Box for the current pressed key
+        m_boxdKeyPressed_Center9->enable();
+        m_boxdKeyPressed_Center9->setX(x);
+        m_boxdKeyPressed_Center9->setY(y);
+        
+        auto keyString = std::string(1, key);
+        m_CanevasKeyPressed_Center9->fillRect(3,3,keyWidth*keyZoomRatio-7, boxHeight*keyZoomRatio-25, COLOR_LIGHT_GREY);
+        m_CanevasKeyPressed_Center9->drawTextCenteredInRect(3,3,keyWidth*keyZoomRatio-7, boxHeight*keyZoomRatio-25, keyString, COLOR_BLACK, true, true, 38);
+
+    }
+    void Keyboard2::zoomKeyUpdate() {
+
+        int16_t rawTouchX, rawTouchY;
+        graphics::getTouchPos(&rawTouchX, &rawTouchY);
+
+        const bool wasZoomActive = isZoomdActive();
+
+        char pressedKey = KEY_NULL;
+
+        // Check if finger is on screen and on a key
+        if (rawTouchX != -1 && rawTouchY != -1) {
+            //pressedKey = getKey(rawTouchX, rawTouchY);
+
+            Keyboard2::Coord pressedKeyCoord = getRowColumn(rawTouchX, rawTouchY);
+
+             if (pressedKeyCoord.row == -1 && pressedKeyCoord.column == -1) {
+                //repressedKeyCoordturn KEY_NULL;
+                return;
+            }   
+
+            oldCoord.row = pressedKeyCoord.row;
+            oldCoord.column = pressedKeyCoord.column;
+
+            pressedKey= getLayoutCharMap()[pressedKeyCoord.row][pressedKeyCoord.column];
+
+            if (m_zoomKeyTicks < UINT8_MAX) {
+                m_zoomKeyTicks++;
+            }            
+
+            if (isZoomdActive()) {
+                if (m_zoomKeyTicks == 10) {
+                    enableKeyZoom(pressedKeyCoord.row, pressedKeyCoord.column, pressedKey);
+                    localGraphicalUpdate();
+                }
+            }
+        } else {
+            m_zoomKeyTicks = 0;
+
+            if (wasZoomActive) {
+                // Do once
+                // m_trackpadFilter->disable();
+                disableKeyZoom(oldCoord.row , oldCoord.column);
+                localGraphicalUpdate();
+            }
+        }
+    }
+
+
+    bool Keyboard2::isZoomdActive() const {
+        return m_zoomKeyTicks >= 10;
+    }
+
+
+    void Keyboard2::enableKeyZoom(uint16_t row, uint16_t column, char pressedKey) 
+    {
+
+        if (row >=0 and row <2) {
+            int count = 10;
+            const float keyWidth = (m_width - (count-1)) / static_cast<float>(count)-1;
+            int x = (keyWidth+1) * column + offsetBord +1;
+            int y = m_height - hauteurKeyboard -offsetBord - boxHeight*keyZoomRatio + row * boxHeight +1+5;
+
+            if (column ==0 ){
+                drawZoomKeyLeft10(x-1, y, keyWidth, pressedKey);
+            } else if (column <9) {
+                drawZoomKeyCenter10(x-(keyWidth*keyZoomRatio - keyWidth)/2, y, keyWidth, pressedKey);
+            } else if (column ==9) {
+                drawZoomKeyRight10(x-(keyWidth*keyZoomRatio - keyWidth)+1, y, keyWidth, pressedKey);
+            }
+        }
+        else if (row ==2 && column >0 && column<8)
+        {
+            int count = 9;
+            const float keyWidth = (m_width - (count-1)) / static_cast<float>(count)-1;
+            int x = (keyWidth+1) * column + offsetBord +1;
+            int y = m_height - hauteurKeyboard -offsetBord - boxHeight*keyZoomRatio + row * boxHeight +1+5;
+            drawZoomKeyCenter9(x-(keyWidth*keyZoomRatio - keyWidth)/2, y, keyWidth, pressedKey);
+        }
+    }
+    
+    void Keyboard2::disableKeyZoom(uint16_t row, uint16_t column)
+    {
+        if (row >=0 and row <2) {
+            if (column ==0 ){
+                m_boxdKeyPressed_Left10->disable();
+            }
+            else if (column<9)
+            {
+                m_boxdKeyPressed_Center10->disable();
+            }
+            else if (column==9)
+            {
+                m_boxdKeyPressed_Right10->disable();
+            }
+        }
+        else if (row == 2){
+            if (column == 0 || column == 8) return;
+            {
+                m_boxdKeyPressed_Center9->disable();
+            }
+        }
+    }
+
+
+
+
+
+} // gui::elements
+
+
diff --git a/lib/gui/src/elements/Keyboard2.hpp b/lib/gui/src/elements/Keyboard2.hpp
new file mode 100644
index 00000000..1cfa5ab0
--- /dev/null
+++ b/lib/gui/src/elements/Keyboard2.hpp
@@ -0,0 +1,150 @@
+//
+// Created by Charles on 13/03/2024.
+//
+
+#ifndef KEYBOARD2_HPP
+#define KEYBOARD2_HPP
+
+#include "../ElementBase.hpp"
+#include "Box.hpp"
+#include "Canvas.hpp"
+#include "Filter.hpp"
+#include "Image.hpp"
+#include "Label.hpp"
+
+namespace gui::elements {
+    class Keyboard2 final : public ElementBase {
+    public:
+
+        struct Coord {
+            int16_t row;
+            int16_t column;
+        };
+
+        explicit Keyboard2(const std::string &defaultText = "");
+
+        ~Keyboard2() override;
+
+        void render() override;
+
+        void widgetUpdate() override;
+
+        /**
+         * Returns the content of the Keyboard2's input AND CLEARS IT.
+         * @return the content of the Keyboard2's input
+         */
+        std::string getText();
+
+        /**
+         * @deprecated Please use "hasExitKeyBeenPressed()"
+         */
+        [[nodiscard]] bool quitting() const { return m_exit; }
+
+        [[nodiscard]] bool hasExitKeyBeenPressed() const;
+
+        void setPlaceholder(const std::string &placeholder);
+
+    private:
+        std::string m_buffer;
+        std::string m_placeholder;
+        std::string m_defaultText;
+
+        Label *m_label;
+
+        bool m_exit = false;
+
+        uint8_t m_currentLayout;
+
+        char **m_layoutLowercase;
+        char **m_layoutUppercase;
+        char **m_layoutNumbers;
+
+        uint8_t m_caps;
+
+        Canvas *m_keysCanvas;
+
+        Image *m_capsIcon0;
+        Image *m_capsIcon1;
+        Image *m_capsIcon2;
+        Image *m_backspaceIcon;
+        Image *m_layoutIcon0;
+        Image *m_layoutIcon1;
+        Image *m_exitIcon;
+        Image *m_confirmIcon;
+        Image* m_trackpadActiveIcon;
+
+        Box *m_capsBox;
+        Box *m_layoutBox;
+        Box *m_backspaceBox;
+        Box *m_exitBox;
+        Box *m_confirmBox;
+        Box* m_trackpadActiveBox;
+
+        Box* m_boxdKeyPressed_Left10;
+        Canvas *m_CanevasKeyPressed_Left10;
+        Box* m_boxdKeyPressed_Center10;
+        Canvas *m_CanevasKeyPressed_Center10;
+        Box* m_boxdKeyPressed_Right10;
+        Canvas *m_CanevasKeyPressed_Right10;
+        Box* m_boxdKeyPressed_Center9;
+        Canvas *m_CanevasKeyPressed_Center9;
+
+        uint8_t m_trackpadTicks;
+        int32_t m_trackpadLastDeltaX;
+
+        int32_t boxHeight;
+        int32_t hauteurKeyboard;
+        int32_t offsetBord;
+        float keyZoomRatio;
+        uint8_t hauteurRetourZoom;
+
+
+        uint8_t m_zoomKeyTicks;
+        Keyboard2::Coord oldCoord;
+        void drawZoomKeyLeft10 (uint16_t x, uint16_t y,uint16_t keyWidth , char key);
+        void drawZoomKeyCenter10 (uint16_t x, uint16_t y,uint16_t keyWidth , char key);
+        void drawZoomKeyRight10 (uint16_t x, uint16_t y,uint16_t keyWidth , char key);
+        void drawZoomKeyCenter9 (uint16_t x, uint16_t y,uint16_t keyWidth , char key);
+        Keyboard2::Coord getRowColumn(const int16_t x, const int16_t y) const;
+        void zoomKeyUpdate();
+        bool isZoomdActive() const;
+        void enableKeyZoom(uint16_t row, uint16_t column, char pressedKey);
+        void disableKeyZoom(uint16_t row, uint16_t column);
+
+        void drawKeys() const;
+
+        void drawKeyRow(int16_t y, const char *keys) const;
+
+        void drawKey(int16_t x, int16_t y, uint16_t w, char key) const;
+
+        void drawLastRow(const int16_t y) const;
+
+        [[nodiscard]] char getKey(int16_t x, int16_t y) const;
+
+        [[nodiscard]] uint8_t getKeyCol(const int16_t x, const uint8_t keyCount) const;
+
+
+        void processKey(char key);
+
+        void drawInputBox() const;
+
+        void updateCapsIcon() const;
+
+        void updateLayoutIcon() const;
+
+        [[nodiscard]] char **getLayoutCharMap() const;
+
+        void trackpadUpdate();
+
+        [[nodiscard]] bool isPointInTrackpad(int16_t x, int16_t y) const;
+
+        [[nodiscard]] bool isTrackpadActive() const;
+
+        void addChar(char value);
+
+        void removeChar();
+
+    };
+} // gui::elements
+
+#endif //Keyboard2_HPP
diff --git a/lib/gui/src/gui.hpp b/lib/gui/src/gui.hpp
index a7c1c8a1..21c829d5 100644
--- a/lib/gui/src/gui.hpp
+++ b/lib/gui/src/gui.hpp
@@ -16,6 +16,7 @@
 #include "elements/Button.hpp"
 #include "elements/Radio.hpp"
 #include "elements/Keyboard.hpp"
+#include "elements/Keyboard2.hpp"
 
 #include "GuiManager.hpp"
 
diff --git a/lib/lua/src/lua_file.cpp b/lib/lua/src/lua_file.cpp
index e3617563..f97c9abd 100755
--- a/lib/lua/src/lua_file.cpp
+++ b/lib/lua/src/lua_file.cpp
@@ -381,6 +381,7 @@ void LuaFile::load()
             "setWindow", &LuaGui::setMainWindow,
             "getWindow", &LuaGui::getMainWindow,            
             "keyboard", &LuaGui::keyboard,
+            "keyboard2", &LuaGui::keyboard2,
             "showInfoMessage", &LuaGui::showInfoMessage,
             "showWarningMessage", &LuaGui::showWarningMessage,
             "showErrorMessage", &LuaGui::showErrorMessage
diff --git a/lib/lua/src/lua_gui.cpp b/lib/lua/src/lua_gui.cpp
index bfe6d6ee..07497a2a 100644
--- a/lib/lua/src/lua_gui.cpp
+++ b/lib/lua/src/lua_gui.cpp
@@ -29,6 +29,9 @@ LuaGui::~LuaGui()
     }
 }
 
+
+
+
 LuaBox* LuaGui::box(LuaWidget* parent, int x, int y, int width, int height)
 {
     LuaBox* w = new LuaBox(parent, x, y, width, height);
@@ -176,6 +179,32 @@ std::string LuaGui::keyboard(const std::string& placeholder, const std::string&
     return o;
 }
 
+
+std::string LuaGui::keyboard2(const std::string& placeholder, const std::string& defaultText, bool rotate)
+{
+    if (rotate) {
+        graphics::setScreenOrientation(graphics::LANDSCAPE);
+    }
+
+    auto key = new Keyboard2(defaultText);
+    key->setPlaceholder(placeholder);
+
+    while (!hardware::getHomeButton() && !key->quitting())
+    {
+        eventHandlerApp.update();
+        key->updateAll();
+    }
+
+    if (rotate) {
+        graphics::setScreenOrientation(graphics::PORTRAIT);
+    }
+
+
+    std::string o = key->getText();
+
+    delete key;
+    return o;
+}
 void LuaGui::setMainWindow(LuaWindow* window) {
     this->mainWindow = window; 
     AppManager::askGui(this->lua); 
diff --git a/lib/lua/src/lua_gui.hpp b/lib/lua/src/lua_gui.hpp
index db371ee2..dbdc5375 100644
--- a/lib/lua/src/lua_gui.hpp
+++ b/lib/lua/src/lua_gui.hpp
@@ -35,6 +35,7 @@ class LuaGui
     LuaWindow* window();
 
     std::string keyboard(const std::string& placeholder, const std::string& defaultText);
+    std::string keyboard2(const std::string& placeholder, const std::string& defaultText, bool rotate = true);
 
     void del(LuaWidget* widget);
 
diff --git a/storage/system/keyboard2/backspace_icon.png b/storage/system/keyboard2/backspace_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..278085518b26105f6270c9c960980448262adb19
GIT binary patch
literal 592
zcmeAS@N?(olHy`uVBq!ia0vp^8X(NU1|)m_?Z^dEoCO|{#S9F3${@^GvDChdfq{w1
z)5S3)qV?_djjL}tFdY9F|3zwcMx}_0j8|tVuM$`31wP%T3rg#n{Fbh^D6d+7;pEwa
z^^RHXuMVGF$sze>$>s--QkHm!Eb3Ibelkx#X<fh79q~Lb3%i}W9h3sR3eU3sGk*{x
zb3%%J)3L@ig$mhVX4zMVN2P@}a*OZ3cb=A-viaun&p-eCF0iP{m0*+VJ+|3t;fJiv
zH(#87Dzq$9NnppDO5M{=R&(9-rhjH<VerySi4+T8eRX@;?$~RkvJVR+x)%LWX?eqY
z_(0xvX2ta7pQb)vb1*?*l8WQ?uXW2WSFV3;#jqf5y|P^YeLuCyy$T!?R5<JGYGjXF
z?tV4zz}vFw-Er&fOLyNDpO(tV;1bB9$TDl$UjyG_eU3v%Hw16XRi5a<aNsn1{-P;%
z7N36Fuzpyv_-0O!e)IER^R|64wBF7<FFIyz*!#52H}7Vc9Qs(n!qDQRIK^w}{Y4si
zGRG^0I9O`t+A|pV3eWU8W*;EXqQ5rm^uj6oE}Ohvn<%j%S9;Z|e_l(2<k_1K&Jth>
z6scwO*IyVuFZ#_cJ)P6Ps)~z)S6$8eelbI2O3;_8z5EkBp7<^eax|KGq;7xvV+(Qq
z>!lBOt*d{q^6<lgo})=ui+0+mw7lp(>NMYP`TWq(+BhAtg&L>sD}Puo{G;DG88a#l
Z*jIj0zGIhZ-3m-144$rjF6*2UngEaK2h;!n

literal 0
HcmV?d00001

diff --git a/storage/system/keyboard2/caps_icon_0.png b/storage/system/keyboard2/caps_icon_0.png
new file mode 100644
index 0000000000000000000000000000000000000000..47c2be866890f46e5a987f6d8dd1a46593222ee8
GIT binary patch
literal 630
zcmV-+0*U>JP)<h;3K|Lk000e1NJLTq001Ze001Zm1^@s6jQ+T700009a7bBm001r{
z001r{0eGc9b^rhZC`m*?R9J=Wm%WSHU>wK4kHlz^fP$FCPA-`Qai{@7S|~!Nw1ayF
zap*3HLhlfq{VPOT7Z1<D^@Oe&93+b`oN$GMQ;`H;;?v=J_9zDj{-8SK0}q5>UcMjl
zyyOYvoa3DFoLb;DTtO<XAeFNh6eu@WDir{L$KwI#{9CixypUxX<#PE#lB7$=aR30B
zOy=keMp*|9!vFyIe7;JtSgdwB9RPr?>$j0e<gIPnV2q(&uOFR3dV|$!6@I_pyI3qf
z^m@HRz0qhy^ZER>EX$uQ%i2&fNMkS_kNbnc;E#U4|9-pO9_s7$8m(6AQz#Vro=hhF
zlnijrk8ZlIUxmYA4&cQm%QCOkYFCsDlAs_6cK|qJjQf1PgP16ahhtS$?<g6hF5c~S
zh{a+kl}gvyZ1(=Cp3mn|C=?I~1h7~vC=ujIa+^pbzOGiQ8`Cs@0tf?uqA2(2boz^?
zX_w>i_}$3_HBI|C7z`fT?KT|8@jlfp%d!o_xJji_S~MDcL&+d@@q9ji7!HRJ1OXn;
z-$yaVz!<}5G+Hi~%U>rG>~^~_O%tLh;@<^d5CqI-GfbybN(4=CGMPXW#TU>0ndPu7
zixNQ-^m@IoUh}-`kKychGp-;NSCEP;NW~ST;tEnB?FUz@6@bU@?ek5+X0yS1y~b|0
zquGHdn9Jn=JPO*j4MkDFIftsMkR%EF{hlmH`f>jsoc$Pd1*y1#RL)-THz-AU-q>wC
Q1poj507*qoM6N<$g3B`-&j0`b

literal 0
HcmV?d00001

diff --git a/storage/system/keyboard2/caps_icon_1.png b/storage/system/keyboard2/caps_icon_1.png
new file mode 100644
index 0000000000000000000000000000000000000000..fe83bc825ae121cd2c6dff5368a73436237e1dac
GIT binary patch
literal 674
zcmV;T0$u%yP)<h;3K|Lk000e1NJLTq001Ze001Zm1^@s6jQ+T700009a7bBm001r{
z001r{0eGc9b^rhZR7pfZR9J=Wm%WP`Q540`lW{bNpde0T(%4uDq7a1z$wClPO;T%N
zAr|QcQOGWWwf}%13X3E*F0O^`3Ta%hun-$RSYZPTt0E&t<)u-xgbf<6L<<i*81B5e
z=g0e+`xxgO$1K&M0XFFbNYx3Ds-p)KC?Ch;aR7iyr2^;tOFo~!kR%DQSnNWt*IzCc
z3jl!E>)qLdQO?17y$%4-Xf*LiB$6nVN&tXhFnDh^n_o{R6EMb*N~L!8AdO%mk$_gK
zRS$>5^Gc<%j$d6}Swf-EjU-7Q6-D_;@gS{1yWOre7!2R4)#|(1Y_^V1r&AOPg%3uf
z@vGD6)KWaaIp4VjgTZT)$;1J?*d$5f$z<}H;z0rw1mOVyXN+-;MzaPJMREP?@pv96
z9;7Lr&*!jOt%ydWH$I>5aTO1RLI{V$(CKs-4u=#A@+P@=I2@nH<MC~))%p&=1OPUh
z?eXmF?2|0Zmz_@M?ZE(LS$^MWG@gpZA{L8<dKFg`Wm2!#Z{2RUY_V8gQ9MXfJQxg~
zn$0EzL4Zp2I~8LLj4`y^?a^p7`f)J8a=DCFs|8UM@#ldr2m<>3K6<?##exRd?RFuG
z;*0N=yBvz5P%LPGYPEV}pXXD*i;ljUIRR320;KBb0ZG5QmD1@n0KCcNa<yg1<@fuM
z$z;g6_X7A#u07}5{!X$S9p|2W?*O<0fxzaT+Z2u2Y_^8KRL#4#Y&KilXTiF!k^ASI
z+XCJZKu9^a-6XE%H1Bl{Zqt!;asMAW`h)reNYx3Ds-p+|1!eKYRqC7;Z2$lO07*qo
IM6N<$g72m=+5i9m

literal 0
HcmV?d00001

diff --git a/storage/system/keyboard2/caps_icon_2.png b/storage/system/keyboard2/caps_icon_2.png
new file mode 100644
index 0000000000000000000000000000000000000000..62d34e38ba7e48cbd9f6d138a5778fc3e5d5c89b
GIT binary patch
literal 767
zcmV<b0s#GqP)<h;3K|Lk000e1NJLTq001Ze001Zm1^@s6jQ+T700009a7bBm001r{
z001r{0eGc9b^rhZu}MThR9J=Wm%nQwK@`WoBkM1MpdfDJU1O6fAPT3DUAcopxN7g}
zSXfAk>&2jO2}08P52V>Z2ss;ru}GN}j=%;iQb;NT5mE#aMOM5hbH%yhfzj15i5z}m
zz@2&X-iLYnoVSEhiba;`tpO%!3COA?AgdN0kYm}L$z%WkCX)%2(jP}hN83ElBb`of
zI~<OkUatoLh(sbY#~>{KgOy4J0ARIRGs$E!TPzj<0P%SI*5mQKYq#4Vgdms8%^ZX2
z1hd&JY&M&@(P(@+J3AZ9A08fh6N$tr&+}h3P5aFfgXtYyTU)a^oz9=-a{1%a)6-zS
z)9E0e&wp{bT*rYxz{U~-l+u|;JRU!ByWJGP$ieeG-QC?iVTr*6$Z^~q07?j<R;zUY
zX0ccXzr*419ZL+R6nDE__<TNWZEc-KqtSbPK9NXZb8{0bD=TO;8Z050i{#et_kVA-
zTFUkH^)CQ!09ajJy<cBn|0YS&POVn^@MeILBz?ZRx_T%S3h4EEW_@1Mw05OZQ9_}R
z<n?;(ZwC1I`1nw*R>5%`hO3wm0zwEbE-soLkEhveHjzrD)S<1x^YinU2P~CJsMTt)
z+wIUa?O(^-U)S||9eaCws-h?XeN7MqRTM=-kW7F#H#e|YEF;(S8%maCRZ*0HAPATG
zTL0M)BvTce&F0BQjAA;$aoX6}fGCQC)DEXue-;Em1rQwP=T+OSSsIg9?+2%ae6bXd
z5+P*jJ^yz{Jx-!10zj}|2+wJ3fdF#?+~3~^fcFOn2Rh7f;E539H18A#`vXR92_rU!
zze)P16PRddOqT$Hu~=-frIDslmSq*sbj`C4S(ep#HmvhHxv6~`1-zVWGPMl(G+M>M
xewyd{4jM6J`fz^@E&NTg1Z33`kW~v0_y<Qq^+!N=1U3Kw002ovPDHLkV1k;@Qyu^S

literal 0
HcmV?d00001

diff --git a/storage/system/keyboard2/confirm_icon.png b/storage/system/keyboard2/confirm_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..bcb4b804c9579c4131eb993188d5e9732cc259fa
GIT binary patch
literal 877
zcmV-z1CsoSP)<h;3K|Lk000e1NJLTq001Ze001Zm1^@s6jQ+T700009a7bBm001r{
z001r{0eGc9b^rhaA4x<(R9J=W*gr@cVHgJRC&!6M!JsICIAv-q6pKOxV_aHlU5up7
z(k|K|h;wi-iY}HGI(2Cwnx=)e1k!(lRdAA+NQYvSu9`&&f#70PNQS3F`hAdk)%>}5
zg1&H&+;LBSdGEXAO-v+lnM*Mma9&*lYpp8@d<Gx};3t5WHK&o(bBpkF{ir2VPuvrd
z%x1H6xm@h+?PV&J63Fmn0KOr~@$qp2AOH>x4e{vcNFX0pldI<%BmkI9Cb?sIc^QE~
zKs@~j;AZ8i`gQQJxWqj@J+h06qHtkhL3A-`<Ru3G-XzInlI`v764}<)#&|p~kWnLn
zAQ>mgNF>6hrY4E(>gr-9lM%>}kw7cSEJ+3e0SN>^kH^E4lM{iwYZMS9ACP1&m*ep8
za0zm5ZcYF*BrQe(LGm3*rqgNK?RE)NRh7|bR3KwU0zvW%Np5Ux&}=qKWJgB_x3{+i
z^3z!vCQ@@?^#gDLuvPrIrCqld7Z))xF@bzO4*+mD99UUdK}$;u0DJ}D(L7T_?Pr~8
zYHF%vJq`>EFr7||!%xfYU<^S2$jAtGcXxGaAfPA;a=9FKc6LhkkByBX6bb>rX8@1N
z=^$BDU&v;$Sj0<av^uD2yxDaC{nOLaNTpI$ckJI%6a@zd2UuNQmFo}yCMPGw!<goY
z8tTD%t-<;Ec{VmS%I=Mhj<QfFh{KL@*B}54LchEC7Jxh9a2P(H4~0Sj0N`{wv9z=V
zv)K#)K>)sTJE-UOjU*F^1e=?iW#_C`D>pYcMdv=8l~GUJdy?GW-)CoMr^GchG%ym8
zzYG%R<<tvzpCk_t59xNhOYYj)*;#?hvN%{=I8aVAGcz+KIIq{sd_FIL_sYqu2T;y~
zs;Wv{cXv1U_VxrWSZ<!)xaVYXqPAEp64%<=%C)sMf%{%bW?j1HbUI5eZ7>)VxZfld
zBY_E$?Ca~3IKN-c9(j`XN;CBaz97l1tu5MYHhR5Y9v>eIpu3t(y@4RP&eQd_+PwdL
z)zwlr0K5j!58xMyL%^$Q!|DOlwXWp<gSyr=u-5tm&-&O*C|AgS00000NkvXXu0mjf
Dr^<ot

literal 0
HcmV?d00001

diff --git a/storage/system/keyboard2/exit_icon.png b/storage/system/keyboard2/exit_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..283094d57e9cefc19ffa78f92896ff940898143d
GIT binary patch
literal 1470
zcmV;v1ws0WP)<h;3K|Lk000e1NJLTq002+`001Zm1^@s6X<&T;00009a7bBm001r{
z001r{0eGc9b^rhca7jc#RA_<ina^t!XBfvnnvzNaLgT>%DTtNXV55RUS_od&ZV$yC
zdI(M}g0~hH{0|1b^w2{fl!%x0U_lb61fnhJs=-Uxprt`Z!9sBMCb||(kqL+xo*ri2
z@txV3{o#aeE%Sw!oqeBY-uL@_-*?{knRm8{2sz#!+j~vmT}LipM&tr!L@r=P<N{_y
zE?`FF0%k-mU`F&xzyaVgPzTn5>%g8Kamj>jJ$e(F1<Y98@4zQL;F1Zwn1LgJxv{aq
z@#DuS6bjVqb%1eTq6d63p%(%k18^LN+qZACwzkIV>T1OHF5$g4_5;8qeqhV^Yt}Jf
zAFvwK{i^v-1oorA2l(sTGOz?Z41D$hJbwH*t<N36%UGMA@kZRFHWf~2{FZ?qWA<}e
zEI$YLcN=3AB9d0dMC7%!$E=7P5RvOGd|r#lbkOEsA|lmlRR95`QmN>^Yk}XGh%9%|
z_dvk+M2cO-b2ougH!-SyBBk&A`SWSo&I5aI+_=H?^faTRqxARpGcz;8l`B_x^5hAH
zLV^DN{xRS?V02?+gKO8WarNp|=I7_RbLS4PUcF-f{{7p5Pk}?g=*r3p_wL=}=FOV`
zc%H|=zyO<@o9y1bdspE1J+SxLvu7+WE^_hWMHUwq!!}1oMpWM=;5Yn@Y1gGomsnU>
zV0?UB*;j$Dfp6;dI+kV8*Vm^w9qJ;+4}pblW}t{jI7=+cl5)8m{s*L3EQUi=tyaY_
zjEG$o(=?^gXh^)xq@qKgrSVcM7R7a4<$6~{#BrRYS^a~EEQv^jzvp>PeA>iVPtvJl
z0h5Yh7$PF#x^AR?YHCVs+m4ViO*152sZ_)?%}6`ta#?KK4uh)IYE6NZ%jL)*8HS;Y
z7!j~sF01OLBmo`A>1aSzj3Tn0SwJO%=Xp}CRznh&WraSv2(4@>!G<Uni;)3Q@H|hZ
zrlu0_-3kHIVibRk&n954R%;5>^Sq?d3ejjZx(zlm`}Ac(**(vT%tW<3Y=wYHF^a#j
z?Mc$9t32@V;lt|kW8hl=*L6etkt0XAfB$}@Jbn5!v|qSzp`(8E6z9~bQ|j_3{B-7*
z!NEaJo;(@)JbLt~n=o1;A;!<~H=D$~t6d%#!QkMax_n5&yX)NC9CLGXsrMI)#csL-
zVCT-A>hjOvcLn(J;K75TPm7$gYs6xV=b26DO2Bq741-dslxQ0o8sf~EGh5NkFu;o!
zFSeqs%*Y~O9bkBPIIJj@O3cj6WaXsKIvzZDz~tm4z*qP=-4_5$OG}|op-^bm-21>7
zz^z-iGIMJ}H=BqC<x>}l?wESMr%<ca#4wD=ZrW-W);A^~lB&e-H4Gz6kMw$CxnA6s
zwuvOf*s^35@UloW;WbS&B<Fda*tQ)>RMSML)oN0$R>NJeQmI7jDy4`g?D}h9TzJc}
z67Tsh33xz)cS$`rODeIXcU?qM-&~X!da|8V^yFNE_vSPn>IwKa1zZ++lRIgT*>cS9
zv@+PXohXWBS^A@WSAv6wq?w`5QZ<9)K89h4ZQHtdvx<l3d6DE@3GKRWm|yCTeTOl=
zm4N3|Yx-yf^>N?Rx`XSw;y8{tjuRm&B31Dd(s1T_o)`MY*3Vh}kMfCeQGSX?cu%9z
z5XW(v)=$@U^?t$=qz+>2T0kY@TF~fPn}#O>LhJDe#UIhLG5@q9Fx@w;&Gn#uB7w(Q
zX+8$~L;T}3{YXm<W;Zc5l}^5i?BLB|<I6U_3P*vV;CdB!-oke%@CQFNaua+M2Zc_!
ze1v}}`aIyEbNf5i&)dWZ^zNh5{|5PY;f%-y%!pjTjK~Gdh+M#o$OX)ZT)>RT1<Z(l
Y0FDWwU}1ymB>(^b07*qoM6N<$g6)joHUIzs

literal 0
HcmV?d00001

diff --git a/storage/system/keyboard2/layout_icon_0.png b/storage/system/keyboard2/layout_icon_0.png
new file mode 100644
index 0000000000000000000000000000000000000000..034cc5fcd5d8217fbd1708623a37a1ecbf7b5df7
GIT binary patch
literal 3149
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

literal 0
HcmV?d00001

diff --git a/storage/system/keyboard2/layout_icon_1.png b/storage/system/keyboard2/layout_icon_1.png
new file mode 100644
index 0000000000000000000000000000000000000000..a3aefaf545fd9709008e2f73bf6d0d4b51e61270
GIT binary patch
literal 1051
zcmV+$1mydPP)<h;3K|Lk000e1NJLTq001Ze001Zm1^@s6jQ+T700009a7bBm001r{
z001r{0eGc9b^rha%}GQ-R9J=Wm$7RjM-;|?cceJZs;)2`*EwX2598(_jg@9e8rjzb
z4z{rK4+ySKBT}eHwQvDLFsLyp3@ThG%@)@fSq>N5#fEEquufwa!jMa`f)s%-#qO*}
zyDQm2fw<5IgXNj`X1<y4&6~FmByped@c$-o8|DOO#hl=*m=l~8_nzP<6Z)S5UjR!$
z9~exqdjh<u=>G#ayJc;64Kn*a@Yk4?q+(l@bggmh7i^wM>S;PIB<)FhT=0FI^%vKW
zqz{tbxb_bUPu(NnH{i45<72L_u4ptGEG#Sld;|QH+4X>zqtS>sj!Q>VtJPRqvIoPj
zz}LVP@C-NrJ_oRC04y&rv$nQY_9^UcTauzE5+Fc95ZK-I9lMW`WQ@t}ip}#p#c^zX
zdzs%mNs8lGp68W(eBXC{LP;fwdy*6c!I)!`B-ZJ<q$iS;B*{c_wi#nw-|sBBX&W=f
zXgC~NpKX`iqe&+dhM{$Mo!LrhYzR=d+s%V0NfLFt-Kw#7lGJQA$HtN*Dfzgnxdb<h
z@^(5M0cy2cMVTiOw6GGoV{sf$^>LN6aP#0RfRmFG09vgUD=RAiwA*b)qY*$IcwV{{
z6}Y^-EcKn8-DI9dqhWv6NiQH<TU+IcoD;mL+PRgxAoJ7{bmem5DVNvxecN^FtlyWU
z!C;`lU{I2HU6O{wVQJ!4t5qfQ7{N)+*;L;p*lad!|67M(G5=mmTD20t0ysQ81i<q=
z78e%*SYKbSlKD;;3<m$k=RNS&`TrN-qa|1eI5;=}U}Iw=x2o4~<~}+)s+>6p0-`9&
zTc^{(7(=_=W_Ne@uKRfd_@mLtZt5lQBT94Io${I^^VAqD#-YuH_Lh2{XU#4giBBcT
z_x-W_iL#&%!|+yu?qU-NeyfUf6-AMXYdDwZwdLU60sEpn1ipkcUI2XGACoJJBEm4d
zRpt!e13v?tpP%QQwOS1r50{;t9sBc#tmS>i82gt0S$bEi<dSaEk1Mm?Z4d;Cq9||O
zZa1H=AZMQZ?OfK!W(zxCh8{&ZoX7gBtnIlI8)HfYr!^<l>`7^?`@TQX-uHbsjJC1b
z8)GH~@1`3cPLdrvjjDy5g!{MB%eZez77G%x{OFL|S60o0mVgtudm68D`cnFqx|igR
zxK^5k?OgkIAW4#3V)w<7Qy|;wICKU>m8;-YWz~o?!KR#7r2?l)tK+AIxoq88<=a<U
zmQ_~NpJso{CGrhk0Kb!dbNm-@ziBS2)-IO(_YU{|vvW>xR?G>`iaEhqF()`H{sAE;
V$YbC5BF6v#002ovPDHLkV1np)^yB~l

literal 0
HcmV?d00001

diff --git a/storage/system/keyboard2/trackpad_active_icon.png b/storage/system/keyboard2/trackpad_active_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..db876fbd32c5fc0939b6cca1a619c2856b720756
GIT binary patch
literal 865
zcmV-n1D^beP)<h;3K|Lk000e1NJLTq002M$002M;1^@s6s%dfF00001b5ch_0Itp)
z=>Px&8%ab#RCr$Pn_*U?Fc8OQa4)d0isjSlNo-G|J&E=t>Pf_t$bO<y`}P8s*%xa2
zC=fCMN=OMGB@N7v`A;U35n<#Pj@*850GtPmoPd+S$Q{51K_>yO1mfiDfjid7IHU-^
ze?>v?JJNZ+(gWhp%_AZ_=}c;HY(zlIz`uOqzC$el%ZxwROh5}R1Sx<x{&#~H=?9nO
zz{W+i_2wKo$N|{p`X&B^={&f)3RNFQ3jh&30n%U9q<!D_0PhIkC`fZ<AO-N5Y@SP#
zGO6|rK&(&*_?&;P1HcS~&I4rb>Lk!(4A^NH?g?qxB%8B31{9MmZt%)`uGIim$%c+)
zNa57Koa?M44uH+epz{DHfevE8dOh>VyU)js6w}vMdx5_4fG#AU6EKTojc0-!0B!Sx
zIzWR5&_$kLH2{u>oV5fv0OIv}2B~)ksrSmM0_A}XUIHorC5dR(EUX8xN;aZyd9(kj
z2=H?4PZnHRoC5&XULuo8#ks-R11N5kXzShP<HXqmC`v>Wc7yB5GAEg8wG1T_R0YAd
z_s8G?wK2j0FkKXF>%wh+e^L(+OAiu0?jaLl2wwW0Uyf7;aMyF$IMw_o15g!2i?u%i
zq<r+QUlXi@WCVcP__|lN96<Y?0^0%X`U>9i`MI8sEe9Zs{b{af2w}hg04PMjqb8&j
z=)I~PMFAn}<pIJ!h%^I0v77tZ(G3JZ)oF{&m1W0SN(i|&7O`aRE4w<|S(UsRuL8Pm
z+yw-cF-`6_29Rl4vrlMf5ULuziUkvOpJ0~Fd7}N~P<5$Y#U-5?I&x_8rK^5Zd1%Vr
z4p&Ynsw#|2b|TX^gjMqO27pKJT<jiGdH};-ts#9ukjZ!IPmXNv9RMRwU^h9+H$det
zFUA(DLE>*l05Bkk*Dd87Dpw-_;qJ0n6;1ugZE+4`0C*5oCiCyhI!BEH=nFz!+pKW_
z`)}B83oXr2L)u;}>W<3>10eH;Lj@_nH{iSZZsaa@v~G~leQej`vy&X1tHFPZ7+nQ)
rY&+%HK}q10hRWu408CIH(lh@9kD>T(xa&(b00000NkvXXu0mjf4^M&%

literal 0
HcmV?d00001


From 51dbdbd7736cdf2d9f3d55a15fd2541265dba147 Mon Sep 17 00:00:00 2001
From: pymuzard <pymuzard@gmail.com>
Date: Sat, 21 Sep 2024 18:30:42 +0200
Subject: [PATCH 3/3] keyboard2 (horizontal ou vertical)

---
 lib/gui/src/elements/Keyboard2.cpp |  1 -
 lib/lua/src/lua_file.cpp           | 34 ++++++++++++++++++++++++++++++
 lib/lua/src/lua_gui.cpp            |  8 ++++---
 lib/lua/src/lua_gui.hpp            |  2 +-
 storage/apps/alarme/app.lua        |  2 +-
 5 files changed, 41 insertions(+), 6 deletions(-)

diff --git a/lib/gui/src/elements/Keyboard2.cpp b/lib/gui/src/elements/Keyboard2.cpp
index 171a6290..078543fd 100644
--- a/lib/gui/src/elements/Keyboard2.cpp
+++ b/lib/gui/src/elements/Keyboard2.cpp
@@ -428,7 +428,6 @@ namespace gui::elements {
     char Keyboard2::getKey(const int16_t x, const int16_t y) const {
         // Check if the position is in the Keyboard2 box
 
-
         Keyboard2::Coord result;
         result = getRowColumn(x, y);
 
diff --git a/lib/lua/src/lua_file.cpp b/lib/lua/src/lua_file.cpp
index f97c9abd..1a382f93 100755
--- a/lib/lua/src/lua_file.cpp
+++ b/lib/lua/src/lua_file.cpp
@@ -1,3 +1,13 @@
+/**
+ * @file lua_file.cpp
+ * @author your name (you@domain.com)
+ * @brief 
+ * @version 0.1
+ * @date 2024-09-19
+ * 
+ * @copyright Copyright (c) 2024
+ * 
+ */
 #include "lua_file.hpp"
 
 #include <gui.hpp>
@@ -10,6 +20,7 @@
 #include <contacts.hpp>
 #include <libsystem.hpp>
 #include <standby.hpp>
+#include <graphics.hpp>
 
 #include <fstream>
 #include <iostream>
@@ -49,6 +60,12 @@ std::shared_ptr<LuaHttpClient> LuaNetwork::createHttpClient()
     return std::make_shared<LuaHttpClient>(lua);
 }*/
 
+/**
+ * @brief Construct a new Lua File:: Lua File object
+ * 
+ * @param filename 
+ * @param manifest 
+ */
 LuaFile::LuaFile(storage::Path filename, storage::Path manifest)
     :lua_gui(this),
     lua_storage(this),
@@ -103,6 +120,12 @@ int sol_exception_handler(lua_State* L, sol::optional<const std::exception&> may
     return 0;
 }
 
+/**
+ * @brief 
+ * 
+ * @param L 
+ * @return int 
+ */
 int custom_panic_handler(lua_State* L) {
     std::shared_ptr<AppManager::App> app = AppManager::get(L);
 
@@ -382,6 +405,14 @@ void LuaFile::load()
             "getWindow", &LuaGui::getMainWindow,            
             "keyboard", &LuaGui::keyboard,
             "keyboard2", &LuaGui::keyboard2,
+/*            
+            "image", sol::overload(
+                [](LuaGui* gui, LuaWidget* parent, std::string path, int x, int y, int width, int height) -> LuaImage* {
+                    return gui->image(parent, path, x, y, width, height, COLOR_WHITE);
+                },
+                &LuaGui::image
+            ),
+            */
             "showInfoMessage", &LuaGui::showInfoMessage,
             "showWarningMessage", &LuaGui::showWarningMessage,
             "showErrorMessage", &LuaGui::showErrorMessage
@@ -503,6 +534,9 @@ void LuaFile::load()
             "setSpaceLine", &LuaHorizontalList::setSpaceLine,
             sol::base_classes, sol::bases<LuaWidget>());
 
+        lua.set("LANDSCAPE",graphics::LANDSCAPE);
+        lua.set("PORTRAIT",graphics::PORTRAIT);
+
         lua.set("SELECTION_UP", VerticalList::SelectionFocus::UP);
         lua.set("SELECTION_CENTER", VerticalList::SelectionFocus::CENTER);
 
diff --git a/lib/lua/src/lua_gui.cpp b/lib/lua/src/lua_gui.cpp
index 07497a2a..7d9cd556 100644
--- a/lib/lua/src/lua_gui.cpp
+++ b/lib/lua/src/lua_gui.cpp
@@ -180,9 +180,10 @@ std::string LuaGui::keyboard(const std::string& placeholder, const std::string&
 }
 
 
-std::string LuaGui::keyboard2(const std::string& placeholder, const std::string& defaultText, bool rotate)
+std::string LuaGui::keyboard2(const std::string& placeholder, const std::string& defaultText, const int orientation)
 {
-    if (rotate) {
+    // set keyboard to LANDSCAPE mode if set 
+    if (orientation == graphics::LANDSCAPE) {
         graphics::setScreenOrientation(graphics::LANDSCAPE);
     }
 
@@ -195,7 +196,8 @@ std::string LuaGui::keyboard2(const std::string& placeholder, const std::string&
         key->updateAll();
     }
 
-    if (rotate) {
+    // set back to portrait when leaving keyboard
+    if (graphics::LANDSCAPE) {
         graphics::setScreenOrientation(graphics::PORTRAIT);
     }
 
diff --git a/lib/lua/src/lua_gui.hpp b/lib/lua/src/lua_gui.hpp
index dbdc5375..76e31a34 100644
--- a/lib/lua/src/lua_gui.hpp
+++ b/lib/lua/src/lua_gui.hpp
@@ -35,7 +35,7 @@ class LuaGui
     LuaWindow* window();
 
     std::string keyboard(const std::string& placeholder, const std::string& defaultText);
-    std::string keyboard2(const std::string& placeholder, const std::string& defaultText, bool rotate = true);
+    std::string keyboard2(const std::string& placeholder, const std::string& defaultText, const int screenOrientation);
 
     void del(LuaWidget* widget);
 
diff --git a/storage/apps/alarme/app.lua b/storage/apps/alarme/app.lua
index a39aedc7..49ad85f7 100644
--- a/storage/apps/alarme/app.lua
+++ b/storage/apps/alarme/app.lua
@@ -172,7 +172,7 @@ end
 
 function changeName(label)
     
-    local keyboard = gui:keyboard("Placeholder", label:getText())
+    local keyboard = gui:keyboard2("Placeholder", label:getText(), LANDSCAPE)
     label:setText(keyboard)
 end