├── .gitignore ├── BADCARD.png ├── src ├── Unicode │ ├── unicode.h │ └── unicode.cpp ├── BLE-Keyboard │ ├── library.properties │ ├── keywords.txt │ ├── examples │ │ └── SendKeyStrokes │ │ │ └── SendKeyStrokes.ino │ ├── BleKeyboard.h │ ├── README.md │ └── BleKeyboard.cpp ├── USBHID-Keyboard │ ├── README.md │ ├── USBHID.h │ ├── USBHIDKeyboard.h │ ├── USBHIDKeyboard.cpp │ └── USBHID.cpp └── Keyboard-Layouts │ ├── KeyboardLayout.h │ ├── KeyboardLayout_US.h │ ├── KeyboardLayout_GB.h │ ├── KeyboardLayout_JP.h │ ├── KeyboardLayout_IT.h │ ├── KeyboardLayout_FR.h │ ├── KeyboardLayout_SE.h │ ├── KeyboardLayout_NO.h │ ├── KeyboardLayout_BR.h │ ├── KeyboardLayout_DE.h │ ├── KeyboardLayout_ES.h │ ├── KeyboardLayout_PT.h │ ├── KeyboardLayout_BE.h │ ├── KeyboardLayout_DK.h │ └── KeyboardLayout_HU.h ├── keys.h ├── README.md └── icons.h /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | .dir-locals.el 3 | -------------------------------------------------------------------------------- /BADCARD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VoidNoi/BadCard/HEAD/BADCARD.png -------------------------------------------------------------------------------- /src/Unicode/unicode.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void utf8_to_utf16(unsigned char* const utf8_str, int utf8_str_size, char16_t* utf16_str_output, int utf16_str_output_size); 4 | -------------------------------------------------------------------------------- /src/BLE-Keyboard/library.properties: -------------------------------------------------------------------------------- 1 | name=ESP32 BLE Keyboard 2 | version=0.3.2 3 | author=T-vK 4 | maintainer=T-vK 5 | sentence=Bluetooth LE Keyboard library for the ESP32. 6 | paragraph=Bluetooth LE Keyboard library for the ESP32. 7 | category=Communication 8 | url=https://github.com/T-vK/ESP32-BLE-Keyboard 9 | architectures=esp32 10 | -------------------------------------------------------------------------------- /src/BLE-Keyboard/keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For ESP32 BLE Keyboard 3 | ####################################### 4 | # Class 5 | ####################################### 6 | 7 | BleKeyboard KEYWORD1 8 | 9 | ####################################### 10 | # Methods and Functions 11 | ####################################### 12 | 13 | begin KEYWORD2 14 | end KEYWORD2 15 | write KEYWORD2 16 | press KEYWORD2 17 | release KEYWORD2 18 | releaseAll KEYWORD2 19 | setBatteryLevel KEYWORD2 20 | isConnected KEYWORD2 21 | 22 | ####################################### 23 | # Constants 24 | ####################################### 25 | -------------------------------------------------------------------------------- /src/USBHID-Keyboard/README.md: -------------------------------------------------------------------------------- 1 | # Advanced Keyboard Support Arduino 2 | 3 | ## Description 4 | This modification of the keyboard lib allows to write special chars and use different keyboardlayouts 5 | 6 | 7 | ## Installation 8 | Put the files in the lib folder (if you use platformIO) of replace the Normal keybord version with the modifiered 9 | 10 | 11 | ## Contributing 12 | The current code is more a proof of concept and is not finished so far. I am happy if other people like to help out. 13 | (E.g the differnet Keyboard layouts with the special characters still need to get added with the correct kedcodes) 14 | 15 | ## Authors and acknowledgment 16 | This modification is based on the arduino USBHIDKeyboard file. 17 | 18 | ## License 19 | For open source projects, say how it is licensed. 20 | -------------------------------------------------------------------------------- /src/BLE-Keyboard/examples/SendKeyStrokes/SendKeyStrokes.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * This example turns the ESP32 into a Bluetooth LE keyboard that writes the words, presses Enter, presses a media key and then Ctrl+Alt+Delete 3 | */ 4 | #include 5 | 6 | BleKeyboard bleKeyboard; 7 | 8 | void setup() { 9 | Serial.begin(115200); 10 | Serial.println("Starting BLE work!"); 11 | bleKeyboard.begin(); 12 | } 13 | 14 | void loop() { 15 | if(bleKeyboard.isConnected()) { 16 | Serial.println("Sending 'Hello world'..."); 17 | bleKeyboard.print("Hello world"); 18 | 19 | delay(1000); 20 | 21 | Serial.println("Sending Enter key..."); 22 | bleKeyboard.write(KEY_RETURN); 23 | 24 | delay(1000); 25 | 26 | Serial.println("Sending Play/Pause media key..."); 27 | bleKeyboard.write(KEY_MEDIA_PLAY_PAUSE); 28 | 29 | delay(1000); 30 | 31 | // 32 | // Below is an example of pressing multiple keyboard modifiers 33 | // which by default is commented out. 34 | /* 35 | Serial.println("Sending Ctrl+Alt+Delete..."); 36 | bleKeyboard.press(KEY_LEFT_CTRL); 37 | bleKeyboard.press(KEY_LEFT_ALT); 38 | bleKeyboard.press(KEY_DELETE); 39 | delay(100); 40 | bleKeyboard.releaseAll(); 41 | */ 42 | } 43 | 44 | Serial.println("Waiting 5 seconds..."); 45 | delay(5000); 46 | } 47 | -------------------------------------------------------------------------------- /keys.h: -------------------------------------------------------------------------------- 1 | #define KEY_LEFT_CTRL 0x80 2 | #define KEY_LEFT_SHIFT 0x81 3 | #define KEY_LEFT_ALT 0x82 4 | #define KEY_LEFT_GUI 0x83 5 | #define KEY_RIGHT_CTRL 0x84 6 | #define KEY_RIGHT_SHIFT 0x85 7 | #define KEY_RIGHT_ALT 0x86 8 | #define KEY_RIGHT_GUI 0x87 9 | 10 | #define KEY_UP_ARROW 0xDA 11 | #define KEY_DOWN_ARROW 0xD9 12 | #define KEY_LEFT_ARROW 0xD8 13 | #define KEY_RIGHT_ARROW 0xD7 14 | #define KEY_BACKSPACE 0xB2 15 | #define KEY_TAB 0xB3 16 | #define KEY_RETURN 0xB0 17 | #define KEY_ESC 0xB1 18 | #define KEY_INSERT 0xD1 19 | #define KEY_DELETE 0xD4 20 | #define KEY_PAGE_UP 0xD3 21 | #define KEY_PAGE_DOWN 0xD6 22 | #define KEY_HOME 0xD2 23 | #define KEY_END 0xD5 24 | #define KEY_CAPS_LOCK 0xC1 25 | #define KEY_F1 0xC2 26 | #define KEY_F2 0xC3 27 | #define KEY_F3 0xC4 28 | #define KEY_F4 0xC5 29 | #define KEY_F5 0xC6 30 | #define KEY_F6 0xC7 31 | #define KEY_F7 0xC8 32 | #define KEY_F8 0xC9 33 | #define KEY_F9 0xCA 34 | #define KEY_F10 0xCB 35 | #define KEY_F11 0xCC 36 | #define KEY_F12 0xCD 37 | #define KEY_F13 0xF0 38 | #define KEY_F14 0xF1 39 | #define KEY_F15 0xF2 40 | #define KEY_F16 0xF3 41 | #define KEY_F17 0xF4 42 | #define KEY_F18 0xF5 43 | #define KEY_F19 0xF6 44 | #define KEY_F20 0xF7 45 | #define KEY_F21 0xF8 46 | #define KEY_F22 0xF9 47 | #define KEY_F23 0xFA 48 | #define KEY_F24 0xFB 49 | 50 | #define KEY_MENU 0xED 51 | #define KEY_PAUSE 0xD0 52 | #define KEY_NUMLOCK 0xDB 53 | #define KEY_PRINTSCREEN 0xCE 54 | #define KEY_SCROLLLOCK 0xCF 55 | #define KEY_SPACE 0xB4 56 | #define KEY_BACKSPACE 0xB2 57 | #define KEY_DOWN_ARROW 0xD9 58 | #define KEY_MENU 0xED 59 | #define KEY_PAUSE 0xD0 60 | #define KEY_NUMLOCK 0xDB 61 | #define KEY_PRINTSCREEN 0xCE 62 | #define KEY_SCROLLLOCK 0xCF 63 | #define KEY_SPACE 0xB4 64 | #define KEY_BACKSPACE 0xB2 65 | #define KEY_DOWN_ARROW 0xD9 66 | -------------------------------------------------------------------------------- /src/USBHID-Keyboard/USBHID.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | #include 17 | #include 18 | #include "sdkconfig.h" 19 | 20 | #if CONFIG_TINYUSB_HID_ENABLED 21 | #include "esp_event.h" 22 | #include "class/hid/hid.h" 23 | #include "class/hid/hid_device.h" 24 | 25 | // Used by the included TinyUSB drivers 26 | enum { 27 | HID_REPORT_ID_NONE, 28 | HID_REPORT_ID_KEYBOARD, 29 | HID_REPORT_ID_MOUSE, 30 | HID_REPORT_ID_GAMEPAD, 31 | HID_REPORT_ID_CONSUMER_CONTROL, 32 | HID_REPORT_ID_SYSTEM_CONTROL, 33 | HID_REPORT_ID_VENDOR 34 | }; 35 | 36 | ESP_EVENT_DECLARE_BASE(ARDUINO_USB_HID_EVENTS); 37 | 38 | typedef enum { 39 | ARDUINO_USB_HID_ANY_EVENT = ESP_EVENT_ANY_ID, 40 | ARDUINO_USB_HID_SET_PROTOCOL_EVENT = 0, 41 | ARDUINO_USB_HID_SET_IDLE_EVENT, 42 | ARDUINO_USB_HID_MAX_EVENT, 43 | } arduino_usb_hid_event_t; 44 | 45 | typedef struct { 46 | uint8_t instance; 47 | union { 48 | struct { 49 | uint8_t protocol; 50 | } set_protocol; 51 | struct { 52 | uint8_t idle_rate; 53 | } set_idle; 54 | }; 55 | } arduino_usb_hid_event_data_t; 56 | 57 | class USBHIDDevice 58 | { 59 | public: 60 | virtual uint16_t _onGetDescriptor(uint8_t* buffer){return 0;} 61 | virtual uint16_t _onGetFeature(uint8_t report_id, uint8_t* buffer, uint16_t len){return 0;} 62 | virtual void _onSetFeature(uint8_t report_id, const uint8_t* buffer, uint16_t len){} 63 | virtual void _onOutput(uint8_t report_id, const uint8_t* buffer, uint16_t len){} 64 | }; 65 | 66 | class USBHID 67 | { 68 | public: 69 | USBHID(void); 70 | void begin(void); 71 | void end(void); 72 | bool ready(void); 73 | bool SendReport(uint8_t report_id, const void* data, size_t len, uint32_t timeout_ms = 100); 74 | void onEvent(esp_event_handler_t callback); 75 | void onEvent(arduino_usb_hid_event_t event, esp_event_handler_t callback); 76 | static bool addDevice(USBHIDDevice * device, uint16_t descriptor_len); 77 | }; 78 | 79 | #endif /* CONFIG_TINYUSB_HID_ENABLED */ 80 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BadCard 2 | 3 | BadUSB for the Cardputer with ducky script support and extra functionality 4 | 5 | Ducky Script processing and executing ported from [arducky](https://github.com/Creased/arducky) 6 | 7 | ## FEATURES 8 | * Bluetooth connection 9 | * File editing (Thanks to [@guidoaguiar](https://github.com/guidoaguiar)) 10 | * Horizontal file navigation 11 | * Multiple Keyboard layouts (en_US, es_ES, de_DE, pt_PT, fr_FR, sv_SE, it_IT, hu_HU, da_DK, pt_BR, en_GB, nb_NO, ja_JP). 12 | * You can navigate, create and delete folders 13 | 14 | You can contribute to BadCard by creating your own keyboard layouts following this guide: [How to create a keyboard layout for BadCard](https://gist.github.com/VoidNoi/4087bab5d67458a52fe22a574a5f7394) 15 | 16 | If you're having trouble executing your payloads on Windows 11 try adding a DELAY 500 at the end of your payload https://github.com/VoidNoi/BadCard/issues/1#issuecomment-2000571655 17 | 18 | ## How to use 19 | You can place your payloads inside the `/BadCard` folder on your SD card (It will be created automatically after installing BadCard) 20 |
21 | Your files should use the `.txt` extension. 22 | 23 | OR 24 | 25 | You can make your own payloads in your cardputer with the "NEW FILE" option 26 |
27 | 28 | Available commands 29 | 30 | 31 | (1) Commands without payload: 32 | - ENTER 33 | - MENU <=> APP 34 | - DOWNARROW <=> DOWN 35 | - LEFTARROW <=> LEFT 36 | - RIGHTARROW <=> RIGHT 37 | - UPARROW <=> UP 38 | - BREAK <=> PAUSE 39 | - CAPSLOCK 40 | - DELETE 41 | - END 42 | - ESC <=> ESCAPE 43 | - HOME 44 | - INSERT 45 | - NUMLOCK 46 | - PAGEUP 47 | - PAGEDOWN 48 | - PRINTSCREEN 49 | - SCROLLLOCK 50 | - SPACE 51 | - TAB 52 | - REPLAY (global commands aren't implemented) 53 | 54 | (2) Commands with payload: 55 | - DEFAULT_DELAY <=> DEFAULTDELAY (global commands aren't implemented.) 56 | - DELAY (+int) 57 | - STRING (+string) 58 | - GUI <=> WINDOWS (+char) 59 | - SHIFT (+char or key) 60 | - ALT (+char or key) 61 | - CTRL <=> CONTROL (+char or key) 62 | - REM (+string) 63 | 64 |
65 | 66 | ## File creating/editing controls 67 | 68 | * You can navigate your file pressing fn and the up, down, left or right keys (aka ;, ., , or /) 69 | * When you're finished creating your file press fn and esc, add the name of your file and press enter (you don't need to add the .txt extension) 70 | * Delete folders by pressing the G0 button and enter for the selected folder 71 | 72 | ## About BLE 73 | * Doesn't support special keys (ñ, ß, etc) like USB does 74 | * It may skip some characters, especially characters that require modifier keys (SHIFT, ALTGR) 75 | -------------------------------------------------------------------------------- /src/USBHID-Keyboard/USBHIDKeyboard.h: -------------------------------------------------------------------------------- 1 | /* 2 | Keyboard.h 3 | 4 | Copyright (c) 2015, Arduino LLC 5 | Original code (pre-library): Copyright (c) 2011, Peter Barrett 6 | 7 | This library is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU Lesser General Public 9 | License as published by the Free Software Foundation; either 10 | version 2.1 of the License, or (at your option) any later version. 11 | 12 | This library is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public 18 | License along with this library; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | 22 | #pragma once 23 | #include "Print.h" 24 | #include "./USBHID.h" 25 | #if CONFIG_TINYUSB_HID_ENABLED 26 | 27 | #include "esp_event.h" 28 | // Default keyboardlayout 29 | #include "../Keyboard-Layouts/KeyboardLayout.h" 30 | #include "../Keyboard-Layouts/KeyboardLayout_US.h" 31 | 32 | ESP_EVENT_DECLARE_BASE(ARDUINO_USB_HID_KEYBOARD_EVENTS); 33 | 34 | typedef enum { 35 | ARDUINO_USB_HID_KEYBOARD_ANY_EVENT = ESP_EVENT_ANY_ID, 36 | ARDUINO_USB_HID_KEYBOARD_LED_EVENT = 0, 37 | ARDUINO_USB_HID_KEYBOARD_MAX_EVENT, 38 | } arduino_usb_hid_keyboard_event_t; 39 | 40 | typedef union { 41 | struct { 42 | uint8_t numlock:1; 43 | uint8_t capslock:1; 44 | uint8_t scrolllock:1; 45 | uint8_t compose:1; 46 | uint8_t kana:1; 47 | uint8_t reserved:3; 48 | }; 49 | uint8_t leds; 50 | } arduino_usb_hid_keyboard_event_data_t; 51 | 52 | #define LED_NUMLOCK 0x01 53 | #define LED_CAPSLOCK 0x02 54 | #define LED_SCROLLLOCK 0x04 55 | #define LED_COMPOSE 0x08 56 | #define LED_KANA 0x10 57 | 58 | // Low level key report: up to 6 keys and shift, ctrl etc at once 59 | typedef struct 60 | { 61 | uint8_t modifiers; 62 | uint8_t reserved; 63 | uint8_t keys[6]; 64 | } KeyReport; 65 | 66 | class USBHIDKeyboard: public USBHIDDevice, public Print 67 | { 68 | private: 69 | USBHID hid; 70 | KeyReport _keyReport; 71 | // contains the used keymap 72 | const uint8_t *_asciimap; 73 | KeyboardLayout *keyboardlayout; 74 | public: 75 | USBHIDKeyboard(void); 76 | void begin(KeyboardLayout* layout=nullptr); 77 | void end(void); 78 | void setModifier(uint8_t modifier); 79 | void unsetModifier(uint8_t modifier); 80 | size_t write(uint8_t k); 81 | size_t write(const uint8_t *buffer, size_t size); 82 | size_t write(uint16_t k); 83 | size_t write(const uint16_t *buffer, size_t size); 84 | size_t write(std::u16string text); 85 | size_t press(uint8_t k); 86 | size_t release(uint8_t k); 87 | size_t press(uint16_t k); 88 | size_t release(uint16_t k); 89 | void releaseAll(void); 90 | void sendReport(KeyReport* keys); 91 | 92 | //raw functions work with TinyUSB's HID_KEY_* macros 93 | size_t pressRaw(uint8_t k); 94 | size_t releaseRaw(uint8_t k); 95 | 96 | void onEvent(esp_event_handler_t callback); 97 | void onEvent(arduino_usb_hid_keyboard_event_t event, esp_event_handler_t callback); 98 | 99 | // internal use 100 | uint16_t _onGetDescriptor(uint8_t* buffer); 101 | void _onOutput(uint8_t report_id, const uint8_t* buffer, uint16_t len); 102 | }; 103 | 104 | 105 | 106 | #endif 107 | -------------------------------------------------------------------------------- /src/Keyboard-Layouts/KeyboardLayout.h: -------------------------------------------------------------------------------- 1 | /* 2 | KeyboardLayout.h 3 | 4 | This file is not part of the public API. It is meant to be included 5 | only in Keyboard.cpp and the keyboard layout files. Layout files map 6 | ASCII character codes to keyboard scan codes (technically, to USB HID 7 | Usage codes), possibly altered by the SHIFT or ALT_GR modifiers. 8 | Non-ACSII characters (anything outside the 7-bit range NUL..DEL) are 9 | not supported. 10 | 11 | == Creating your own layout == 12 | 13 | In order to create your own layout file, copy an existing layout that 14 | is similar to yours, then modify it to use the correct keys. The 15 | layout is an array in ASCII order. Each entry contains a scan code, 16 | possibly modified by "|SHIFT" or "|ALT_GR", as in this excerpt from 17 | the Italian layout: 18 | 19 | 0x35, // bslash 20 | 0x30|ALT_GR, // ] 21 | 0x2e|SHIFT, // ^ 22 | 23 | Do not change the control characters (those before scan code 0x2c, 24 | corresponding to space). Do not attempt to grow the table past DEL. Do 25 | not use both SHIFT and ALT_GR on the same character: this is not 26 | supported. Unsupported characters should have 0x00 as scan code. 27 | 28 | For a keyboard with an ISO physical layout, use the scan codes below: 29 | 30 | +---+---+---+---+---+---+---+---+---+---+---+---+---+-------+ 31 | |35 |1e |1f |20 |21 |22 |23 |24 |25 |26 |27 |2d |2e |BackSp | 32 | +---+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-----+ 33 | | Tab |14 |1a |08 |15 |17 |1c |18 |0c |12 |13 |2f |30 | Ret | 34 | +-----++--++--++--++--++--++--++--++--++--++--++--++--++ | 35 | |CapsL |04 |16 |07 |09 |0a |0b |0d |0e |0f |33 |34 |31 | | 36 | +----+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+---+----+ 37 | |Shi.|32 |1d |1b |06 |19 |05 |11 |10 |36 |37 |38 | Shift | 38 | +----+---++--+-+-+---+---+---+---+---+--++---+---++----+----+ 39 | |Ctrl|Win |Alt | |AlGr|Win |Menu|Ctrl| 40 | +----+----+----+------------------------+----+----+----+----+ 41 | 42 | The ANSI layout is identical except that key 0x31 is above (rather 43 | than next to) Return, and there is not key 0x32. 44 | 45 | Give a unique name to the layout array, then declare it in Keyboard.h 46 | with a line of the form: 47 | 48 | extern const uint8_t KeyboardLayout_xx_YY[]; 49 | 50 | == Encoding details == 51 | 52 | All scan codes are less than 0x80, which makes bit 7 available to 53 | signal that a modifier (Shift or AltGr) is needed to generate the 54 | character. With only one exception, keys that are used with modifiers 55 | have scan codes that are less than 0x40. This makes bit 6 available 56 | to signal whether the modifier is Shift or AltGr. The exception is 57 | 0x64, the key next next to Left Shift on the ISO layout (and absent 58 | from the ANSI layout). We handle it by replacing its value by 0x32 in 59 | the layout arrays. 60 | */ 61 | 62 | #include 63 | #pragma once 64 | 65 | #define SHIFT 0x80 66 | #define ALT_GR 0xc0 67 | #define ISO_KEY 0x64 68 | #define ISO_REPLACEMENT 0x32 69 | #define U16SHIFT 0x8000 70 | 71 | class KeyboardLayout 72 | { 73 | public: 74 | KeyboardLayout(){}; 75 | ~KeyboardLayout(){}; 76 | virtual const uint8_t* getKeymap()=0; 77 | /** 78 | * @brief Returns the keycode for the given key 79 | * 80 | * @param key Key value literal 81 | * @return Key code if possible 82 | */ 83 | virtual uint16_t getKeycode(char16_t key)=0; 84 | /** 85 | * @brief Returns if the key is a keyboardlayout specific key 86 | * 87 | * @param key Key to check (represents a character) 88 | * @return the keycode or 0 if it is not a special key 89 | */ 90 | virtual uint16_t isSpecialKey(char16_t key)=0; 91 | 92 | }; 93 | -------------------------------------------------------------------------------- /src/Keyboard-Layouts/KeyboardLayout_US.h: -------------------------------------------------------------------------------- 1 | #include "KeyboardLayout.h" 2 | #pragma once 3 | 4 | const uint8_t KeyboardLayout_en_US[128] PROGMEM{ 5 | 0x00, // NUL 6 | 0x00, // SOH 7 | 0x00, // STX 8 | 0x00, // ETX 9 | 0x00, // EOT 10 | 0x00, // ENQ 11 | 0x00, // ACK 12 | 0x00, // BEL 13 | 0x2a, // BS Backspace 14 | 0x2b, // TAB Tab 15 | 0x28, // LF Enter 16 | 0x00, // VT 17 | 0x00, // FF 18 | 0x00, // CR 19 | 0x00, // SO 20 | 0x00, // SI 21 | 0x00, // DEL 22 | 0x00, // DC1 23 | 0x00, // DC2 24 | 0x00, // DC3 25 | 0x00, // DC4 26 | 0x00, // NAK 27 | 0x00, // SYN 28 | 0x00, // ETB 29 | 0x00, // CAN 30 | 0x00, // EM 31 | 0x00, // SUB 32 | 0x00, // ESC 33 | 0x00, // FS 34 | 0x00, // GS 35 | 0x00, // RS 36 | 0x00, // US 37 | 38 | 0x2c, // ' ' 39 | 0x1e | SHIFT, // ! 40 | 0x34 | SHIFT, // " 41 | 0x20 | SHIFT, // # 42 | 0x21 | SHIFT, // $ 43 | 0x22 | SHIFT, // % 44 | 0x24 | SHIFT, // & 45 | 0x34, // ' 46 | 0x26 | SHIFT, // ( 47 | 0x27 | SHIFT, // ) 48 | 0x25 | SHIFT, // * 49 | 0x2e | SHIFT, // + 50 | 0x36, // , 51 | 0x2d, // - 52 | 0x37, // . 53 | 0x38, // / 54 | 0x27, // 0 55 | 0x1e, // 1 56 | 0x1f, // 2 57 | 0x20, // 3 58 | 0x21, // 4 59 | 0x22, // 5 60 | 0x23, // 6 61 | 0x24, // 7 62 | 0x25, // 8 63 | 0x26, // 9 64 | 0x33 | SHIFT, // : 65 | 0x33, // ; 66 | 0x36 | SHIFT, // < 67 | 0x2e, // = 68 | 0x37 | SHIFT, // > 69 | 0x38 | SHIFT, // ? 70 | 0x1f | SHIFT, // @ 71 | 0x04 | SHIFT, // A 72 | 0x05 | SHIFT, // B 73 | 0x06 | SHIFT, // C 74 | 0x07 | SHIFT, // D 75 | 0x08 | SHIFT, // E 76 | 0x09 | SHIFT, // F 77 | 0x0a | SHIFT, // G 78 | 0x0b | SHIFT, // H 79 | 0x0c | SHIFT, // I 80 | 0x0d | SHIFT, // J 81 | 0x0e | SHIFT, // K 82 | 0x0f | SHIFT, // L 83 | 0x10 | SHIFT, // M 84 | 0x11 | SHIFT, // N 85 | 0x12 | SHIFT, // O 86 | 0x13 | SHIFT, // P 87 | 0x14 | SHIFT, // Q 88 | 0x15 | SHIFT, // R 89 | 0x16 | SHIFT, // S 90 | 0x17 | SHIFT, // T 91 | 0x18 | SHIFT, // U 92 | 0x19 | SHIFT, // V 93 | 0x1a | SHIFT, // W 94 | 0x1b | SHIFT, // X 95 | 0x1c | SHIFT, // Y 96 | 0x1d | SHIFT, // Z 97 | 0x2f, // [ 98 | 0x31, // bslash 99 | 0x30, // ] 100 | 0x23 | SHIFT, // ^ 101 | 0x2d | SHIFT, // _ 102 | 0x35, // ` 103 | 0x04, // a 104 | 0x05, // b 105 | 0x06, // c 106 | 0x07, // d 107 | 0x08, // e 108 | 0x09, // f 109 | 0x0a, // g 110 | 0x0b, // h 111 | 0x0c, // i 112 | 0x0d, // j 113 | 0x0e, // k 114 | 0x0f, // l 115 | 0x10, // m 116 | 0x11, // n 117 | 0x12, // o 118 | 0x13, // p 119 | 0x14, // q 120 | 0x15, // r 121 | 0x16, // s 122 | 0x17, // t 123 | 0x18, // u 124 | 0x19, // v 125 | 0x1a, // w 126 | 0x1b, // x 127 | 0x1c, // y 128 | 0x1d, // z 129 | 0x2f | SHIFT, // { 130 | 0x31 | SHIFT, // | 131 | 0x30 | SHIFT, // } 132 | 0x35 | SHIFT, // ~ 133 | 0 // DEL 134 | }; 135 | 136 | class KeyboardLayout_US : public KeyboardLayout 137 | { 138 | public: 139 | KeyboardLayout_US(){}; 140 | ~KeyboardLayout_US(){}; 141 | const uint8_t *getKeymap() 142 | { 143 | return KeyboardLayout_en_US; 144 | } 145 | /** 146 | * @brief Returns the keycode for the given key 147 | * 148 | * @param key Key value as string 149 | * @return Key code if possible 150 | */ 151 | uint16_t getKeycode(char16_t key) 152 | { 153 | 154 | if (key < 128) 155 | { 156 | return KeyboardLayout_en_US[key]; 157 | } 158 | // Could not match code 159 | return 0; 160 | } 161 | uint16_t isSpecialKey(char16_t key) 162 | { 163 | // TODO implement methode 164 | return 0; 165 | } 166 | }; 167 | -------------------------------------------------------------------------------- /src/Keyboard-Layouts/KeyboardLayout_GB.h: -------------------------------------------------------------------------------- 1 | /* 2 | * United Kingdom keyboard layout. 3 | */ 4 | 5 | #include "KeyboardLayout.h" 6 | 7 | #pragma once 8 | 9 | const uint8_t KeyboardLayout_en_GB[128] PROGMEM{ 10 | 0x00, // NUL 11 | 0x00, // SOH 12 | 0x00, // STX 13 | 0x00, // ETX 14 | 0x00, // EOT 15 | 0x00, // ENQ 16 | 0x00, // ACK 17 | 0x00, // BEL 18 | 0x2a, // BS Backspace 19 | 0x2b, // TAB Tab 20 | 0x28, // LF Enter 21 | 0x00, // VT 22 | 0x00, // FF 23 | 0x00, // CR 24 | 0x00, // SO 25 | 0x00, // SI 26 | 0x00, // DEL 27 | 0x00, // DC1 28 | 0x00, // DC2 29 | 0x00, // DC3 30 | 0x00, // DC4 31 | 0x00, // NAK 32 | 0x00, // SYN 33 | 0x00, // ETB 34 | 0x00, // CAN 35 | 0x00, // EM 36 | 0x00, // SUB 37 | 0x00, // ESC 38 | 0x00, // FS 39 | 0x00, // GS 40 | 0x00, // RS 41 | 0x00, // US 42 | 43 | 0x2c, // ' ' 44 | 0x1e | SHIFT, // ! 45 | 0x1f | SHIFT, // " 46 | 0x31, // # 47 | 0x21 | SHIFT, // $ 48 | 0x22 | SHIFT, // % 49 | 0x24 | SHIFT, // & 50 | 0x34, // ' 51 | 0x26 | SHIFT, // ( 52 | 0x27 | SHIFT, // ) 53 | 0x25 | SHIFT, // * 54 | 0x2e | SHIFT, // + 55 | 0x36, // , 56 | 0x2d, // - 57 | 0x37, // . 58 | 0x38, // / 59 | 0x27, // 0 60 | 0x1e, // 1 61 | 0x1f, // 2 62 | 0x20, // 3 63 | 0x21, // 4 64 | 0x22, // 5 65 | 0x23, // 6 66 | 0x24, // 7 67 | 0x25, // 8 68 | 0x26, // 9 69 | 0x33 | SHIFT, // : 70 | 0x33, // ; 71 | 0x36 | SHIFT, // < 72 | 0x2e, // = 73 | 0x37 | SHIFT, // > 74 | 0x38 | SHIFT, // ? 75 | 0x34 | SHIFT, // @ 76 | 0x04 | SHIFT, // A 77 | 0x05 | SHIFT, // B 78 | 0x06 | SHIFT, // C 79 | 0x07 | SHIFT, // D 80 | 0x08 | SHIFT, // E 81 | 0x09 | SHIFT, // F 82 | 0x0a | SHIFT, // G 83 | 0x0b | SHIFT, // H 84 | 0x0c | SHIFT, // I 85 | 0x0d | SHIFT, // J 86 | 0x0e | SHIFT, // K 87 | 0x0f | SHIFT, // L 88 | 0x10 | SHIFT, // M 89 | 0x11 | SHIFT, // N 90 | 0x12 | SHIFT, // O 91 | 0x13 | SHIFT, // P 92 | 0x14 | SHIFT, // Q 93 | 0x15 | SHIFT, // R 94 | 0x16 | SHIFT, // S 95 | 0x17 | SHIFT, // T 96 | 0x18 | SHIFT, // U 97 | 0x19 | SHIFT, // V 98 | 0x1a | SHIFT, // W 99 | 0x1b | SHIFT, // X 100 | 0x1c | SHIFT, // Y 101 | 0x1d | SHIFT, // Z 102 | 0x2f, // [ 103 | 0x32, // bslash 104 | 0x30, // ] 105 | 0x23 | SHIFT, // ^ 106 | 0x2d | SHIFT, // _ 107 | 0x35, // ` 108 | 0x04, // a 109 | 0x05, // b 110 | 0x06, // c 111 | 0x07, // d 112 | 0x08, // e 113 | 0x09, // f 114 | 0x0a, // g 115 | 0x0b, // h 116 | 0x0c, // i 117 | 0x0d, // j 118 | 0x0e, // k 119 | 0x0f, // l 120 | 0x10, // m 121 | 0x11, // n 122 | 0x12, // o 123 | 0x13, // p 124 | 0x14, // q 125 | 0x15, // r 126 | 0x16, // s 127 | 0x17, // t 128 | 0x18, // u 129 | 0x19, // v 130 | 0x1a, // w 131 | 0x1b, // x 132 | 0x1c, // y 133 | 0x1d, // z 134 | 0x2f | SHIFT, // { 135 | 0x32 | SHIFT, // | 136 | 0x30 | SHIFT, // } 137 | 0x31 | SHIFT, // ~ 138 | 0 // DEL 139 | }; 140 | 141 | class KeyboardLayout_GB : public KeyboardLayout 142 | { 143 | public: 144 | KeyboardLayout_GB(){}; 145 | ~KeyboardLayout_GB(){}; 146 | const uint8_t *getKeymap() 147 | { 148 | return KeyboardLayout_en_GB; 149 | } 150 | /** 151 | * @brief Returns the keycode for the given key 152 | * 153 | * @param key Key value as string 154 | * @return Key code if possible 155 | */ 156 | uint16_t getKeycode(char16_t key) 157 | { 158 | 159 | if (key < 128) 160 | { 161 | return KeyboardLayout_en_GB[key]; 162 | } 163 | // Could not match code 164 | return 0; 165 | } 166 | uint16_t isSpecialKey(char16_t key) 167 | { 168 | // TODO implement methode 169 | return 0; 170 | } 171 | }; 172 | -------------------------------------------------------------------------------- /src/BLE-Keyboard/BleKeyboard.h: -------------------------------------------------------------------------------- 1 | // uncomment the following line to use NimBLE library 2 | #define USE_NIMBLE 3 | 4 | #ifndef ESP32_BLE_KEYBOARD_H 5 | #define ESP32_BLE_KEYBOARD_H 6 | #include "sdkconfig.h" 7 | #if defined(CONFIG_BT_ENABLED) 8 | 9 | #if defined(USE_NIMBLE) 10 | 11 | #include "NimBLECharacteristic.h" 12 | #include "NimBLEHIDDevice.h" 13 | #include "../Keyboard-Layouts/KeyboardLayout.h" 14 | #include "../Keyboard-Layouts/KeyboardLayout_US.h" 15 | 16 | #define BLEDevice NimBLEDevice 17 | #define BLEServerCallbacks NimBLEServerCallbacks 18 | #define BLECharacteristicCallbacks NimBLECharacteristicCallbacks 19 | #define BLEHIDDevice NimBLEHIDDevice 20 | #define BLECharacteristic NimBLECharacteristic 21 | #define BLEAdvertising NimBLEAdvertising 22 | #define BLEServer NimBLEServer 23 | 24 | #else 25 | 26 | #include "BLEHIDDevice.h" 27 | #include "BLECharacteristic.h" 28 | 29 | #endif // USE_NIMBLE 30 | 31 | #include "Print.h" 32 | 33 | #define BLE_KEYBOARD_VERSION "0.0.4" 34 | #define BLE_KEYBOARD_VERSION_MAJOR 0 35 | #define BLE_KEYBOARD_VERSION_MINOR 0 36 | #define BLE_KEYBOARD_VERSION_REVISION 4 37 | 38 | const uint8_t KEY_NUM_0 = 0xEA; 39 | const uint8_t KEY_NUM_1 = 0xE1; 40 | const uint8_t KEY_NUM_2 = 0xE2; 41 | const uint8_t KEY_NUM_3 = 0xE3; 42 | const uint8_t KEY_NUM_4 = 0xE4; 43 | const uint8_t KEY_NUM_5 = 0xE5; 44 | const uint8_t KEY_NUM_6 = 0xE6; 45 | const uint8_t KEY_NUM_7 = 0xE7; 46 | const uint8_t KEY_NUM_8 = 0xE8; 47 | const uint8_t KEY_NUM_9 = 0xE9; 48 | const uint8_t KEY_NUM_SLASH = 0xDC; 49 | const uint8_t KEY_NUM_ASTERISK = 0xDD; 50 | const uint8_t KEY_NUM_MINUS = 0xDE; 51 | const uint8_t KEY_NUM_PLUS = 0xDF; 52 | const uint8_t KEY_NUM_ENTER = 0xE0; 53 | const uint8_t KEY_NUM_PERIOD = 0xEB; 54 | 55 | typedef uint8_t MediaKeyReport[2]; 56 | 57 | const MediaKeyReport KEY_MEDIA_NEXT_TRACK = {1, 0}; 58 | const MediaKeyReport KEY_MEDIA_PREVIOUS_TRACK = {2, 0}; 59 | const MediaKeyReport KEY_MEDIA_STOP = {4, 0}; 60 | const MediaKeyReport KEY_MEDIA_PLAY_PAUSE = {8, 0}; 61 | const MediaKeyReport KEY_MEDIA_MUTE = {16, 0}; 62 | const MediaKeyReport KEY_MEDIA_VOLUME_UP = {32, 0}; 63 | const MediaKeyReport KEY_MEDIA_VOLUME_DOWN = {64, 0}; 64 | const MediaKeyReport KEY_MEDIA_WWW_HOME = {128, 0}; 65 | const MediaKeyReport KEY_MEDIA_LOCAL_MACHINE_BROWSER = {0, 1}; // Opens "My Computer" on Windows 66 | const MediaKeyReport KEY_MEDIA_CALCULATOR = {0, 2}; 67 | const MediaKeyReport KEY_MEDIA_WWW_BOOKMARKS = {0, 4}; 68 | const MediaKeyReport KEY_MEDIA_WWW_SEARCH = {0, 8}; 69 | const MediaKeyReport KEY_MEDIA_WWW_STOP = {0, 16}; 70 | const MediaKeyReport KEY_MEDIA_WWW_BACK = {0, 32}; 71 | const MediaKeyReport KEY_MEDIA_CONSUMER_CONTROL_CONFIGURATION = {0, 64}; // Media Selection 72 | const MediaKeyReport KEY_MEDIA_EMAIL_READER = {0, 128}; 73 | 74 | 75 | // Low level key report: up to 6 keys and shift, ctrl etc at once 76 | typedef struct 77 | { 78 | uint8_t modifiers; 79 | uint8_t reserved; 80 | uint8_t keys[6]; 81 | } BLEKeyReport; 82 | 83 | class BleKeyboard : public Print, public BLEServerCallbacks, public BLECharacteristicCallbacks 84 | { 85 | private: 86 | BLEHIDDevice* hid; 87 | BLECharacteristic* inputKeyboard; 88 | BLECharacteristic* outputKeyboard; 89 | BLECharacteristic* inputMediaKeys; 90 | BLEAdvertising* advertising; 91 | BLEKeyReport _keyReport; 92 | MediaKeyReport _mediaKeyReport; 93 | std::string deviceName; 94 | std::string deviceManufacturer; 95 | uint8_t batteryLevel; 96 | bool connected = false; 97 | uint32_t _delay_ms = 7; 98 | void delay_ms(uint64_t ms); 99 | const uint8_t *_asciimap; 100 | KeyboardLayout *keyboardLayout; 101 | 102 | uint16_t vid = 0x05ac; 103 | uint16_t pid = 0x820a; 104 | uint16_t version = 0x0210; 105 | 106 | public: 107 | BleKeyboard(std::string deviceName = "ESP32 Keyboard", std::string deviceManufacturer = "Espressif", uint8_t batteryLevel = 100); 108 | void begin(void); 109 | void end(void); 110 | void setLayout(KeyboardLayout* layout=nullptr); 111 | void sendReport(BLEKeyReport* keys); 112 | void sendReport(MediaKeyReport* keys); 113 | size_t press(uint8_t k); 114 | size_t press(const MediaKeyReport k); 115 | size_t release(uint8_t k); 116 | size_t release(const MediaKeyReport k); 117 | size_t write(uint8_t c); 118 | size_t write(const MediaKeyReport c); 119 | size_t write(const uint8_t *buffer, size_t size); 120 | void releaseAll(void); 121 | bool isConnected(void); 122 | void setBatteryLevel(uint8_t level); 123 | void setName(std::string deviceName); 124 | void setDelay(uint32_t ms); 125 | 126 | void set_vendor_id(uint16_t vid); 127 | void set_product_id(uint16_t pid); 128 | void set_version(uint16_t version); 129 | protected: 130 | virtual void onStarted(BLEServer *pServer) { }; 131 | virtual void onConnect(BLEServer* pServer) override; 132 | virtual void onDisconnect(BLEServer* pServer) override; 133 | virtual void onWrite(BLECharacteristic* me) override; 134 | 135 | }; 136 | 137 | #endif // CONFIG_BT_ENABLED 138 | #endif // ESP32_BLE_KEYBOARD_H 139 | -------------------------------------------------------------------------------- /src/Keyboard-Layouts/KeyboardLayout_JP.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Japanese 106 keyboard layout. 3 | */ 4 | 5 | #include "KeyboardLayout.h" 6 | 7 | #pragma once 8 | 9 | //Additional keys 10 | #define KEY_J_YEN (136+0x89) 11 | 12 | #define AMOUNT_OF_SPECIAL_CHARS 1 13 | 14 | extern const char16_t KeyboardLayout_ja_JP_special_characters[AMOUNT_OF_SPECIAL_CHARS] PROGMEM = { 15 | u'¥', 16 | }; 17 | 18 | extern const uint16_t KeyboardLayout_ja_JP_special_keycodes[AMOUNT_OF_SPECIAL_CHARS] PROGMEM = { 19 | KEY_J_YEN 20 | }; 21 | 22 | extern const uint8_t KeyboardLayout_ja_JP[128] PROGMEM{ 23 | 0x00, // NUL 24 | 0x00, // SOH 25 | 0x00, // STX 26 | 0x00, // ETX 27 | 0x00, // EOT 28 | 0x00, // ENQ 29 | 0x00, // ACK 30 | 0x00, // BEL 31 | 0x2a, // BS Backspace 32 | 0x2b, // TAB Tab 33 | 0x28, // LF Enter 34 | 0x00, // VT 35 | 0x00, // FF 36 | 0x00, // CR 37 | 0x00, // SO 38 | 0x00, // SI 39 | 0x00, // DEL 40 | 0x00, // DC1 41 | 0x00, // DC2 42 | 0x00, // DC3 43 | 0x00, // DC4 44 | 0x00, // NAK 45 | 0x00, // SYN 46 | 0x00, // ETB 47 | 0x00, // CAN 48 | 0x00, // EM 49 | 0x00, // SUB 50 | 0x00, // ESC 51 | 0x00, // FS 52 | 0x00, // GS 53 | 0x00, // RS 54 | 0x00, // US 55 | 56 | 0x2c, // ' ' 57 | 0x1e | SHIFT, // ! 58 | 0x1f | SHIFT, // " 59 | 0x20 | SHIFT, // # 60 | 0x21 | SHIFT, // $ 61 | 0x22 | SHIFT, // % 62 | 0x23 | SHIFT, // & 63 | 0x24 | SHIFT, // ' 64 | 0x25 | SHIFT, // ( 65 | 0x26 | SHIFT, // ) 66 | 0x34 | SHIFT, // * 67 | 0x33 | SHIFT, // + 68 | 0x10, // , 69 | 0x2d, // - 70 | 0x36, // . 71 | 0x37, // / 72 | 0x27, // 0 73 | 0x1e, // 1 74 | 0x1f, // 2 75 | 0x20, // 3 76 | 0x21, // 4 77 | 0x22, // 5 78 | 0x23, // 6 79 | 0x24, // 7 80 | 0x25, // 8 81 | 0x26, // 9 82 | 0x34, // : 83 | 0x33, // ; 84 | 0x36 | SHIFT, // < 85 | 0x2d | SHIFT, // = 86 | 0x37 | SHIFT, // > 87 | 0x38 | SHIFT, // ? 88 | 0x2f, // @ 89 | 0x04 | SHIFT, // A 90 | 0x05 | SHIFT, // B 91 | 0x06 | SHIFT, // C 92 | 0x07 | SHIFT, // D 93 | 0x08 | SHIFT, // E 94 | 0x09 | SHIFT, // F 95 | 0x0a | SHIFT, // G 96 | 0x0b | SHIFT, // H 97 | 0x0c | SHIFT, // I 98 | 0x0d | SHIFT, // J 99 | 0x0e | SHIFT, // K 100 | 0x0f | SHIFT, // L 101 | 0x10 | SHIFT, // M 102 | 0x11 | SHIFT, // N 103 | 0x12 | SHIFT, // O 104 | 0x13 | SHIFT, // P 105 | 0x14 | SHIFT, // Q 106 | 0x15 | SHIFT, // R 107 | 0x16 | SHIFT, // S 108 | 0x17 | SHIFT, // T 109 | 0x18 | SHIFT, // U 110 | 0x19 | SHIFT, // V 111 | 0x1a | SHIFT, // W 112 | 0x1b | SHIFT, // X 113 | 0x1c | SHIFT, // Y 114 | 0x1d | SHIFT, // Z 115 | 0x30, // [ 116 | 0x38, // bslash 117 | 0x31, // ] 118 | 0x2e, // ^ 119 | 0x38 | SHIFT, // _ 120 | 0x2f | SHIFT, // ` 121 | 0x04, // a 122 | 0x05, // b 123 | 0x06, // c 124 | 0x07, // d 125 | 0x08, // e 126 | 0x09, // f 127 | 0x0a, // g 128 | 0x0b, // h 129 | 0x0c, // i 130 | 0x0d, // j 131 | 0x0e, // k 132 | 0x0f, // l 133 | 0x10, // m 134 | 0x11, // n 135 | 0x12, // o 136 | 0x13, // p 137 | 0x14, // q 138 | 0x15, // r 139 | 0x16, // s 140 | 0x17, // t 141 | 0x18, // u 142 | 0x19, // v 143 | 0x1a, // w 144 | 0x1b, // x 145 | 0x1c, // y 146 | 0x1d, // z 147 | 0x30 | SHIFT, // { 148 | 0x89 | SHIFT, // | 149 | 0x31 | SHIFT, // } 150 | 0x2e | SHIFT, // ~ 151 | 0 // DEL 152 | }; 153 | 154 | class KeyboardLayout_JP : public KeyboardLayout 155 | { 156 | public: 157 | KeyboardLayout_JP(){}; 158 | ~KeyboardLayout_JP(){}; 159 | const uint8_t *getKeymap() 160 | { 161 | return KeyboardLayout_ja_JP; 162 | } 163 | /** 164 | * @brief Returns the keycode for the given key 165 | * 166 | * @param key Key value as string 167 | * @return Key code if possible 168 | */ 169 | uint16_t getKeycode(char16_t key) 170 | { 171 | Serial.print("Keycode"); 172 | uint16_t specialKeyCode = isSpecialKey(key); 173 | 174 | Serial.println(specialKeyCode); 175 | 176 | if (specialKeyCode != 0) 177 | { 178 | return specialKeyCode; 179 | } 180 | 181 | if (key < 128) 182 | { 183 | return KeyboardLayout_ja_JP[key]; 184 | } 185 | // Could not match code 186 | return 0; 187 | } 188 | uint16_t isSpecialKey(char16_t key) 189 | { 190 | uint16_t keycode = 0; 191 | 192 | if (key == KeyboardLayout_ja_JP_special_characters[0]) 193 | { 194 | keycode = KeyboardLayout_ja_JP_special_keycodes[0]; 195 | } 196 | 197 | return keycode; 198 | } 199 | }; 200 | -------------------------------------------------------------------------------- /src/BLE-Keyboard/README.md: -------------------------------------------------------------------------------- 1 | # ESP32 BLE Keyboard library 2 | 3 | This library allows you to make the ESP32 act as a Bluetooth Keyboard and control what it does. 4 | You might also be interested in: 5 | - [ESP32-BLE-Mouse](https://github.com/T-vK/ESP32-BLE-Mouse) 6 | - [ESP32-BLE-Gamepad](https://github.com/lemmingDev/ESP32-BLE-Gamepad) 7 | 8 | 9 | ## Features 10 | 11 | - [x] Send key strokes 12 | - [x] Send text 13 | - [x] Press/release individual keys 14 | - [x] Media keys are supported 15 | - [ ] Read Numlock/Capslock/Scrolllock state 16 | - [x] Set battery level (basically works, but doesn't show up in Android's status bar) 17 | - [x] Compatible with Android 18 | - [x] Compatible with Windows 19 | - [x] Compatible with Linux 20 | - [x] Compatible with MacOS X (not stable, some people have issues, doesn't work with old devices) 21 | - [x] Compatible with iOS (not stable, some people have issues, doesn't work with old devices) 22 | 23 | ## Installation 24 | - (Make sure you can use the ESP32 with the Arduino IDE. [Instructions can be found here.](https://github.com/espressif/arduino-esp32#installation-instructions)) 25 | - [Download the latest release of this library from the release page.](https://github.com/T-vK/ESP32-BLE-Keyboard/releases) 26 | - In the Arduino IDE go to "Sketch" -> "Include Library" -> "Add .ZIP Library..." and select the file you just downloaded. 27 | - You can now go to "File" -> "Examples" -> "ESP32 BLE Keyboard" and select any of the examples to get started. 28 | 29 | ## Example 30 | 31 | ``` C++ 32 | /** 33 | * This example turns the ESP32 into a Bluetooth LE keyboard that writes the words, presses Enter, presses a media key and then Ctrl+Alt+Delete 34 | */ 35 | #include 36 | 37 | BleKeyboard bleKeyboard; 38 | 39 | void setup() { 40 | Serial.begin(115200); 41 | Serial.println("Starting BLE work!"); 42 | bleKeyboard.begin(); 43 | } 44 | 45 | void loop() { 46 | if(bleKeyboard.isConnected()) { 47 | Serial.println("Sending 'Hello world'..."); 48 | bleKeyboard.print("Hello world"); 49 | 50 | delay(1000); 51 | 52 | Serial.println("Sending Enter key..."); 53 | bleKeyboard.write(KEY_RETURN); 54 | 55 | delay(1000); 56 | 57 | Serial.println("Sending Play/Pause media key..."); 58 | bleKeyboard.write(KEY_MEDIA_PLAY_PAUSE); 59 | 60 | delay(1000); 61 | 62 | // 63 | // Below is an example of pressing multiple keyboard modifiers 64 | // which by default is commented out. 65 | // 66 | /* Serial.println("Sending Ctrl+Alt+Delete..."); 67 | bleKeyboard.press(KEY_LEFT_CTRL); 68 | bleKeyboard.press(KEY_LEFT_ALT); 69 | bleKeyboard.press(KEY_DELETE); 70 | delay(100); 71 | bleKeyboard.releaseAll(); 72 | */ 73 | 74 | } 75 | Serial.println("Waiting 5 seconds..."); 76 | delay(5000); 77 | } 78 | ``` 79 | 80 | ## API docs 81 | The BleKeyboard interface is almost identical to the Keyboard Interface, so you can use documentation right here: 82 | https://www.arduino.cc/reference/en/language/functions/usb/keyboard/ 83 | 84 | Just remember that you have to use `bleKeyboard` instead of just `Keyboard` and you need these two lines at the top of your script: 85 | ``` 86 | #include 87 | BleKeyboard bleKeyboard; 88 | ``` 89 | 90 | In addition to that you can send media keys (which is not possible with the USB keyboard library). Supported are the following: 91 | - KEY_MEDIA_NEXT_TRACK 92 | - KEY_MEDIA_PREVIOUS_TRACK 93 | - KEY_MEDIA_STOP 94 | - KEY_MEDIA_PLAY_PAUSE 95 | - KEY_MEDIA_MUTE 96 | - KEY_MEDIA_VOLUME_UP 97 | - KEY_MEDIA_VOLUME_DOWN 98 | - KEY_MEDIA_WWW_HOME 99 | - KEY_MEDIA_LOCAL_MACHINE_BROWSER // Opens "My Computer" on Windows 100 | - KEY_MEDIA_CALCULATOR 101 | - KEY_MEDIA_WWW_BOOKMARKS 102 | - KEY_MEDIA_WWW_SEARCH 103 | - KEY_MEDIA_WWW_STOP 104 | - KEY_MEDIA_WWW_BACK 105 | - KEY_MEDIA_CONSUMER_CONTROL_CONFIGURATION // Media Selection 106 | - KEY_MEDIA_EMAIL_READER 107 | 108 | There is also Bluetooth specific information that you can set (optional): 109 | Instead of `BleKeyboard bleKeyboard;` you can do `BleKeyboard bleKeyboard("Bluetooth Device Name", "Bluetooth Device Manufacturer", 100);`. (Max lenght is 15 characters, anything beyond that will be truncated.) 110 | The third parameter is the initial battery level of your device. To adjust the battery level later on you can simply call e.g. `bleKeyboard.setBatteryLevel(50)` (set battery level to 50%). 111 | By default the battery level will be set to 100%, the device name will be `ESP32 Bluetooth Keyboard` and the manufacturer will be `Espressif`. 112 | There is also a `setDelay` method to set a delay between each key event. E.g. `bleKeyboard.setDelay(10)` (10 milliseconds). The default is `8`. 113 | This feature is meant to compensate for some applications and devices that can't handle fast input and will skip letters if too many keys are sent in a small time frame. 114 | 115 | ## NimBLE-Mode 116 | The NimBLE mode enables a significant saving of RAM and FLASH memory. 117 | 118 | ### Comparison (SendKeyStrokes.ino at compile-time) 119 | 120 | **Standard** 121 | ``` 122 | RAM: [= ] 9.3% (used 30548 bytes from 327680 bytes) 123 | Flash: [======== ] 75.8% (used 994120 bytes from 1310720 bytes) 124 | ``` 125 | 126 | **NimBLE mode** 127 | ``` 128 | RAM: [= ] 8.3% (used 27180 bytes from 327680 bytes) 129 | Flash: [==== ] 44.2% (used 579158 bytes from 1310720 bytes) 130 | ``` 131 | 132 | ### Comparison (SendKeyStrokes.ino at run-time) 133 | 134 | | | Standard | NimBLE mode | difference 135 | |---|--:|--:|--:| 136 | | `ESP.getHeapSize()` | 296.804 | 321.252 | **+ 24.448** | 137 | | `ESP.getFreeHeap()` | 143.572 | 260.764 | **+ 117.192** | 138 | | `ESP.getSketchSize()` | 994.224 | 579.264 | **- 414.960** | 139 | 140 | ## How to activate NimBLE mode? 141 | 142 | ### ArduinoIDE: 143 | Uncomment the first line in BleKeyboard.h 144 | ```C++ 145 | #define USE_NIMBLE 146 | ``` 147 | 148 | ### PlatformIO: 149 | Change your `platformio.ini` to the following settings 150 | ```ini 151 | lib_deps = 152 | NimBLE-Arduino 153 | 154 | build_flags = 155 | -D USE_NIMBLE 156 | ``` 157 | 158 | ## Credits 159 | 160 | Credits to [chegewara](https://github.com/chegewara) and [the authors of the USB keyboard library](https://github.com/arduino-libraries/Keyboard/) as this project is heavily based on their work! 161 | Also, credits to [duke2421](https://github.com/T-vK/ESP32-BLE-Keyboard/issues/1) who helped a lot with testing, debugging and fixing the device descriptor! 162 | And credits to [sivar2311](https://github.com/sivar2311) for adding NimBLE support, greatly reducing the memory footprint, fixing advertising issues and for adding the `setDelay` method. 163 | -------------------------------------------------------------------------------- /src/Keyboard-Layouts/KeyboardLayout_IT.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Italian keyboard layout. 3 | */ 4 | 5 | #include "KeyboardLayout.h" 6 | 7 | #pragma once 8 | 9 | //================================================================================ 10 | //================================================================================ 11 | // Keyboard 12 | 13 | // it_IT keys 14 | #define KEY_I_GRAVE (136+0x2e) 15 | #define KEY_E_GRAVE (136+0x2f) 16 | #define KEY_O_GRAVE (136+0x33) 17 | #define KEY_A_GRAVE (136+0x34) 18 | #define KEY_U_GRAVE (136+0x31) 19 | 20 | #define AMOUNT_OF_SPECIAL_CHARS 9 21 | 22 | extern const char16_t KeyboardLayout_it_IT_special_characters[AMOUNT_OF_SPECIAL_CHARS] PROGMEM = { 23 | u'ì', 24 | u'è', 25 | u'ò', 26 | u'à', 27 | u'ù', 28 | u'é', 29 | u'ç', 30 | u'º', 31 | u'§' 32 | }; 33 | 34 | extern const uint16_t KeyboardLayout_it_IT_special_keycodes[AMOUNT_OF_SPECIAL_CHARS] PROGMEM = { 35 | KEY_I_GRAVE, 36 | KEY_E_GRAVE, 37 | KEY_O_GRAVE, 38 | KEY_A_GRAVE, 39 | KEY_U_GRAVE, 40 | KEY_E_GRAVE | U16SHIFT, 41 | KEY_O_GRAVE | U16SHIFT, 42 | KEY_A_GRAVE | U16SHIFT, 43 | KEY_U_GRAVE | U16SHIFT 44 | }; 45 | 46 | extern const uint8_t KeyboardLayout_it_IT[128] PROGMEM = 47 | { 48 | 0x00, // NUL 49 | 0x00, // SOH 50 | 0x00, // STX 51 | 0x00, // ETX 52 | 0x00, // EOT 53 | 0x00, // ENQ 54 | 0x00, // ACK 55 | 0x00, // BEL 56 | 0x2a, // BS Backspace 57 | 0x2b, // TAB Tab 58 | 0x28, // LF Enter 59 | 0x00, // VT 60 | 0x00, // FF 61 | 0x00, // CR 62 | 0x00, // SO 63 | 0x00, // SI 64 | 0x00, // DEL 65 | 0x00, // DC1 66 | 0x00, // DC2 67 | 0x00, // DC3 68 | 0x00, // DC4 69 | 0x00, // NAK 70 | 0x00, // SYN 71 | 0x00, // ETB 72 | 0x00, // CAN 73 | 0x00, // EM 74 | 0x00, // SUB 75 | 0x00, // ESC 76 | 0x00, // FS 77 | 0x00, // GS 78 | 0x00, // RS 79 | 0x00, // US 80 | 81 | 0x2c, // ' ' 82 | 0x1e|SHIFT, // ! 83 | 0x1f|SHIFT, // " 84 | 0x34|ALT_GR, // # 85 | 0x21|SHIFT, // $ 86 | 0x22|SHIFT, // % 87 | 0x23|SHIFT, // & 88 | 0x2d, // ' 89 | 0x25|SHIFT, // ( 90 | 0x26|SHIFT, // ) 91 | 0x30|SHIFT, // * 92 | 0x30, // + 93 | 0x36, // , 94 | 0x38, // - 95 | 0x37, // . 96 | 0x24|SHIFT, // / 97 | 0x27, // 0 98 | 0x1e, // 1 99 | 0x1f, // 2 100 | 0x20, // 3 101 | 0x21, // 4 102 | 0x22, // 5 103 | 0x23, // 6 104 | 0x24, // 7 105 | 0x25, // 8 106 | 0x26, // 9 107 | 0x37|SHIFT, // : 108 | 0x36|SHIFT, // ; 109 | 0x32, // < 110 | 0x27|SHIFT, // = 111 | 0x32|SHIFT, // > 112 | 0x2d|SHIFT, // ? 113 | 0x33|ALT_GR, // @ 114 | 0x04|SHIFT, // A 115 | 0x05|SHIFT, // B 116 | 0x06|SHIFT, // C 117 | 0x07|SHIFT, // D 118 | 0x08|SHIFT, // E 119 | 0x09|SHIFT, // F 120 | 0x0a|SHIFT, // G 121 | 0x0b|SHIFT, // H 122 | 0x0c|SHIFT, // I 123 | 0x0d|SHIFT, // J 124 | 0x0e|SHIFT, // K 125 | 0x0f|SHIFT, // L 126 | 0x10|SHIFT, // M 127 | 0x11|SHIFT, // N 128 | 0x12|SHIFT, // O 129 | 0x13|SHIFT, // P 130 | 0x14|SHIFT, // Q 131 | 0x15|SHIFT, // R 132 | 0x16|SHIFT, // S 133 | 0x17|SHIFT, // T 134 | 0x18|SHIFT, // U 135 | 0x19|SHIFT, // V 136 | 0x1a|SHIFT, // W 137 | 0x1b|SHIFT, // X 138 | 0x1c|SHIFT, // Y 139 | 0x1d|SHIFT, // Z 140 | 0x2f|ALT_GR, // [ 141 | 0x35, // bslash 142 | 0x30|ALT_GR, // ] 143 | 0x2e|SHIFT, // ^ 144 | 0x38|SHIFT, // _ 145 | 0x00, // ` not in this layout 146 | 0x04, // a 147 | 0x05, // b 148 | 0x06, // c 149 | 0x07, // d 150 | 0x08, // e 151 | 0x09, // f 152 | 0x0a, // g 153 | 0x0b, // h 154 | 0x0c, // i 155 | 0x0d, // j 156 | 0x0e, // k 157 | 0x0f, // l 158 | 0x10, // m 159 | 0x11, // n 160 | 0x12, // o 161 | 0x13, // p 162 | 0x14, // q 163 | 0x15, // r 164 | 0x16, // s 165 | 0x17, // t 166 | 0x18, // u 167 | 0x19, // v 168 | 0x1a, // w 169 | 0x1b, // x 170 | 0x1c, // y 171 | 0x1d, // z 172 | 0x00, // { not supported (requires AltGr+Shift) 173 | 0x35|SHIFT, // | 174 | 0x00, // } not supported (requires AltGr+Shift) 175 | 0x00, // ~ not in this layout 176 | 0x00 // DEL 177 | }; 178 | 179 | class KeyboardLayout_IT : public KeyboardLayout 180 | { 181 | public: 182 | KeyboardLayout_IT() 183 | { 184 | } 185 | ~KeyboardLayout_IT(){}; 186 | const uint8_t *getKeymap() 187 | { 188 | return KeyboardLayout_it_IT; 189 | } 190 | /** 191 | * @brief Returns the keycode for the given key 192 | * 193 | * @param key Key value as string 194 | * @return Key code if possible 195 | */ 196 | uint16_t getKeycode(char16_t key) 197 | { 198 | Serial.print("Keycode"); 199 | uint16_t specialKeyCode = isSpecialKey(key); 200 | 201 | Serial.println(specialKeyCode); 202 | // Check if special key is in the map 203 | if (specialKeyCode != 0) 204 | { 205 | return specialKeyCode; 206 | } 207 | // No special key use the normal layout 208 | else 209 | { 210 | if (key < 128) 211 | { 212 | return KeyboardLayout_it_IT[key]; 213 | } 214 | // Could not match code 215 | return 0; 216 | } 217 | } 218 | 219 | uint16_t isSpecialKey(char16_t key) 220 | { 221 | uint16_t keycode = 0; 222 | for (int i = 0; i < AMOUNT_OF_SPECIAL_CHARS; i++) 223 | { 224 | Serial.print("Searching key: "); 225 | Serial.println(key); 226 | Serial.print("Comparing with list: "); 227 | Serial.println((char16_t)KeyboardLayout_it_IT_special_characters[i]); 228 | 229 | if (key == KeyboardLayout_it_IT_special_characters[i]) 230 | { 231 | Serial.println("Compare keys"); 232 | Serial.println(key); 233 | Serial.println((char16_t)KeyboardLayout_it_IT_special_characters[i]); 234 | Serial.println((char)key); 235 | Serial.println((char)KeyboardLayout_it_IT_special_characters[i]); 236 | 237 | 238 | keycode = KeyboardLayout_it_IT_special_keycodes[i]; 239 | Serial.println(keycode); 240 | break; 241 | } 242 | } 243 | return keycode; 244 | } 245 | 246 | protected: 247 | }; 248 | -------------------------------------------------------------------------------- /src/Keyboard-Layouts/KeyboardLayout_FR.h: -------------------------------------------------------------------------------- 1 | /* 2 | * French keyboard layout. 3 | */ 4 | 5 | #include "KeyboardLayout.h" 6 | 7 | #pragma once 8 | 9 | //================================================================================ 10 | //================================================================================ 11 | // Keyboard 12 | 13 | // fr_FR keys 14 | #define KEY_SUPERSCRIPT_TWO (136+0x35) 15 | #define KEY_E_ACUTE (136+0x1f) 16 | #define KEY_E_GRAVE (136+0x24) 17 | #define KEY_C_CEDILLA (136+0x26) 18 | #define KEY_A_GRAVE (136+0x27) 19 | #define KEY_CIRCUMFLEX (136+0x2f) 20 | #define KEY_U_GRAVE (136+0x34) 21 | 22 | #define AMOUNT_OF_SPECIAL_CHARS 11 23 | 24 | extern const char16_t KeyboardLayout_fr_FR_special_characters[AMOUNT_OF_SPECIAL_CHARS] PROGMEM = { 25 | u'²', 26 | u'é', 27 | u'è', 28 | u'ç', 29 | u'à', 30 | u'^', 31 | u'ù', 32 | u'¨' 33 | }; 34 | 35 | extern const uint16_t KeyboardLayout_fr_FR_special_keycodes[AMOUNT_OF_SPECIAL_CHARS] PROGMEM = { 36 | KEY_SUPERSCRIPT_TWO, 37 | KEY_E_ACUTE, 38 | KEY_E_GRAVE, 39 | KEY_C_CEDILLA, 40 | KEY_A_GRAVE, 41 | KEY_CIRCUMFLEX, 42 | KEY_U_GRAVE, 43 | KEY_U_GRAVE | U16SHIFT 44 | }; 45 | 46 | extern const uint8_t KeyboardLayout_fr_FR[128] PROGMEM = 47 | { 48 | 0x00, // NUL 49 | 0x00, // SOH 50 | 0x00, // STX 51 | 0x00, // ETX 52 | 0x00, // EOT 53 | 0x00, // ENQ 54 | 0x00, // ACK 55 | 0x00, // BEL 56 | 0x2a, // BS Backspace 57 | 0x2b, // TAB Tab 58 | 0x28, // LF Enter 59 | 0x00, // VT 60 | 0x00, // FF 61 | 0x00, // CR 62 | 0x00, // SO 63 | 0x00, // SI 64 | 0x00, // DEL 65 | 0x00, // DC1 66 | 0x00, // DC2 67 | 0x00, // DC3 68 | 0x00, // DC4 69 | 0x00, // NAK 70 | 0x00, // SYN 71 | 0x00, // ETB 72 | 0x00, // CAN 73 | 0x00, // EM 74 | 0x00, // SUB 75 | 0x00, // ESC 76 | 0x00, // FS 77 | 0x00, // GS 78 | 0x00, // RS 79 | 0x00, // US 80 | 81 | 0x2c, // ' ' 82 | 0x38, // ! 83 | 0x20, // " 84 | 0x20|ALT_GR, // # 85 | 0x30, // $ 86 | 0x34|SHIFT, // % 87 | 0x1E, // & 88 | 0x21, // ' 89 | 0x22, // ( 90 | 0x2d, // ) 91 | 0x31, // * 92 | 0x2e|SHIFT, // + 93 | 0x10, // , 94 | 0x23, // - 95 | 0x36|SHIFT, // . 96 | 0x37|SHIFT, // / 97 | 0x27|SHIFT, // 0 98 | 0x1e|SHIFT, // 1 99 | 0x1f|SHIFT, // 2 100 | 0x20|SHIFT, // 3 101 | 0x21|SHIFT, // 4 102 | 0x22|SHIFT, // 5 103 | 0x23|SHIFT, // 6 104 | 0x24|SHIFT, // 7 105 | 0x25|SHIFT, // 8 106 | 0x26|SHIFT, // 9 107 | 0x37, // : 108 | 0x36, // ; 109 | 0x32, // < 110 | 0x2e, // = 111 | 0x32|SHIFT, // > 112 | 0x10|SHIFT, // ? 113 | 0x27|ALT_GR, // @ 114 | 0x14|SHIFT, // A 115 | 0x05|SHIFT, // B 116 | 0x06|SHIFT, // C 117 | 0x07|SHIFT, // D 118 | 0x08|SHIFT, // E 119 | 0x09|SHIFT, // F 120 | 0x0a|SHIFT, // G 121 | 0x0b|SHIFT, // H 122 | 0x0c|SHIFT, // I 123 | 0x0d|SHIFT, // J 124 | 0x0e|SHIFT, // K 125 | 0x0f|SHIFT, // L 126 | 0x33|SHIFT, // M 127 | 0x11|SHIFT, // N 128 | 0x12|SHIFT, // O 129 | 0x13|SHIFT, // P 130 | 0x04|SHIFT, // Q 131 | 0x15|SHIFT, // R 132 | 0x16|SHIFT, // S 133 | 0x17|SHIFT, // T 134 | 0x18|SHIFT, // U 135 | 0x19|SHIFT, // V 136 | 0x1d|SHIFT, // W 137 | 0x1b|SHIFT, // X 138 | 0x1c|SHIFT, // Y 139 | 0x1a|SHIFT, // Z 140 | 0x22|ALT_GR, // [ 141 | 0x25|ALT_GR, // bslash 142 | 0x2d|ALT_GR, // ] 143 | 0x26|ALT_GR, // ^ 144 | 0x25, // _ 145 | 0x24|ALT_GR, // ` 146 | 0x14, // a 147 | 0x05, // b 148 | 0x06, // c 149 | 0x07, // d 150 | 0x08, // e 151 | 0x09, // f 152 | 0x0a, // g 153 | 0x0b, // h 154 | 0x0c, // i 155 | 0x0d, // j 156 | 0x0e, // k 157 | 0x0f, // l 158 | 0x33, // m 159 | 0x11, // n 160 | 0x12, // o 161 | 0x13, // p 162 | 0x04, // q 163 | 0x15, // r 164 | 0x16, // s 165 | 0x17, // t 166 | 0x18, // u 167 | 0x19, // v 168 | 0x1d, // w 169 | 0x1b, // x 170 | 0x1c, // y 171 | 0x1a, // z 172 | 0x21|ALT_GR, // { 173 | 0x23|ALT_GR, // | 174 | 0x2e|ALT_GR, // } 175 | 0x1f|ALT_GR, // ~ 176 | 0x00 // DEL 177 | }; 178 | 179 | class KeyboardLayout_FR : public KeyboardLayout 180 | { 181 | public: 182 | KeyboardLayout_FR() 183 | { 184 | } 185 | ~KeyboardLayout_FR(){}; 186 | const uint8_t *getKeymap() 187 | { 188 | return KeyboardLayout_fr_FR; 189 | } 190 | /** 191 | * @brief Returns the keycode for the given key 192 | * 193 | * @param key Key value as string 194 | * @return Key code if possible 195 | */ 196 | uint16_t getKeycode(char16_t key) 197 | { 198 | Serial.print("Keycode"); 199 | uint16_t specialKeyCode = isSpecialKey(key); 200 | 201 | Serial.println(specialKeyCode); 202 | // Check if special key is in the map 203 | if (specialKeyCode != 0) 204 | { 205 | return specialKeyCode; 206 | } 207 | // No special key use the normal layout 208 | else 209 | { 210 | if (key < 128) 211 | { 212 | return KeyboardLayout_fr_FR[key]; 213 | } 214 | // Could not match code 215 | return 0; 216 | } 217 | } 218 | 219 | uint16_t isSpecialKey(char16_t key) 220 | { 221 | uint16_t keycode = 0; 222 | for (int i = 0; i < AMOUNT_OF_SPECIAL_CHARS; i++) 223 | { 224 | Serial.print("Searching key: "); 225 | Serial.println(key); 226 | Serial.print("Comparing with list: "); 227 | Serial.println((char16_t)KeyboardLayout_fr_FR_special_characters[i]); 228 | 229 | if (key == KeyboardLayout_fr_FR_special_characters[i]) 230 | { 231 | Serial.println("Compare keys"); 232 | Serial.println(key); 233 | Serial.println((char16_t)KeyboardLayout_fr_FR_special_characters[i]); 234 | Serial.println((char)key); 235 | Serial.println((char)KeyboardLayout_fr_FR_special_characters[i]); 236 | 237 | 238 | keycode = KeyboardLayout_fr_FR_special_keycodes[i]; 239 | Serial.println(keycode); 240 | break; 241 | } 242 | } 243 | return keycode; 244 | } 245 | 246 | protected: 247 | }; 248 | 249 | //#endif 250 | //#endif 251 | -------------------------------------------------------------------------------- /src/Keyboard-Layouts/KeyboardLayout_SE.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Swedish keyboard layout. 3 | */ 4 | 5 | #include "KeyboardLayout.h" 6 | 7 | #pragma once 8 | 9 | //================================================================================ 10 | //================================================================================ 11 | // Keyboard 12 | 13 | // SV_SE keys 14 | #define KEY_A_RING (136+0x2f) 15 | #define KEY_A_UMLAUT (136+0x34) 16 | #define KEY_O_UMLAUT (136+0x33) 17 | #define KEY_UMLAUT (136+0x30) 18 | #define KEY_ACUTE_ACC (136+0x2e) 19 | 20 | #define AMOUNT_OF_SPECIAL_CHARS 11 21 | 22 | extern const char16_t KeyboardLayout_sv_SE_special_characters[AMOUNT_OF_SPECIAL_CHARS] PROGMEM = { 23 | u'å', 24 | u'ä', 25 | u'ö', 26 | u'¨', 27 | u'´', 28 | u'Å', 29 | u'Ä', 30 | u'Ö', 31 | u'^', 32 | u'~', 33 | u'`' 34 | }; 35 | 36 | extern const uint16_t KeyboardLayout_sv_SE_special_keycodes[AMOUNT_OF_SPECIAL_CHARS] PROGMEM = { 37 | KEY_A_RING, 38 | KEY_A_UMLAUT, 39 | KEY_O_UMLAUT, 40 | KEY_UMLAUT, 41 | KEY_ACUTE_ACC, 42 | KEY_A_RING | U16SHIFT, 43 | KEY_A_UMLAUT | U16SHIFT, 44 | KEY_O_UMLAUT | U16SHIFT, 45 | KEY_UMLAUT | U16SHIFT, 46 | KEY_UMLAUT | ALT_GR, 47 | KEY_ACUTE_ACC | U16SHIFT 48 | }; 49 | 50 | extern const uint8_t KeyboardLayout_sv_SE[128] PROGMEM = 51 | { 52 | 0x00, // NUL 53 | 0x00, // SOH 54 | 0x00, // STX 55 | 0x00, // ETX 56 | 0x00, // EOT 57 | 0x00, // ENQ 58 | 0x00, // ACK 59 | 0x00, // BEL 60 | 0x2a, // BS Backspace 61 | 0x2b, // TAB Tab 62 | 0x28, // LF Enter 63 | 0x00, // VT 64 | 0x00, // FF 65 | 0x00, // CR 66 | 0x00, // SO 67 | 0x00, // SI 68 | 0x00, // DEL 69 | 0x00, // DC1 70 | 0x00, // DC2 71 | 0x00, // DC3 72 | 0x00, // DC4 73 | 0x00, // NAK 74 | 0x00, // SYN 75 | 0x00, // ETB 76 | 0x00, // CAN 77 | 0x00, // EM 78 | 0x00, // SUB 79 | 0x00, // ESC 80 | 0x00, // FS 81 | 0x00, // GS 82 | 0x00, // RS 83 | 0x00, // US 84 | 85 | 0x2c, // ' ' 86 | 0x1e|SHIFT, // ! 87 | 0x1f|SHIFT, // " 88 | 0x20|SHIFT, // # 89 | 0x21|ALT_GR, // $ 90 | 0x22|SHIFT, // % 91 | 0x23|SHIFT, // & 92 | 0x31, // ' 93 | 0x25|SHIFT, // ( 94 | 0x26|SHIFT, // ) 95 | 0x31|SHIFT, // * 96 | 0x2d, // + 97 | 0x36, // , 98 | 0x38, // - 99 | 0x37, // . 100 | 0x24|SHIFT, // / 101 | 0x27, // 0 102 | 0x1e, // 1 103 | 0x1f, // 2 104 | 0x20, // 3 105 | 0x21, // 4 106 | 0x22, // 5 107 | 0x23, // 6 108 | 0x24, // 7 109 | 0x25, // 8 110 | 0x26, // 9 111 | 0x37|SHIFT, // : 112 | 0x36|SHIFT, // ; 113 | 0x32, // < 114 | 0x27|SHIFT, // = 115 | 0x32|SHIFT, // > 116 | 0x2d|SHIFT, // ? 117 | 0x1f|ALT_GR, // @ 118 | 0x04|SHIFT, // A 119 | 0x05|SHIFT, // B 120 | 0x06|SHIFT, // C 121 | 0x07|SHIFT, // D 122 | 0x08|SHIFT, // E 123 | 0x09|SHIFT, // F 124 | 0x0a|SHIFT, // G 125 | 0x0b|SHIFT, // H 126 | 0x0c|SHIFT, // I 127 | 0x0d|SHIFT, // J 128 | 0x0e|SHIFT, // K 129 | 0x0f|SHIFT, // L 130 | 0x10|SHIFT, // M 131 | 0x11|SHIFT, // N 132 | 0x12|SHIFT, // O 133 | 0x13|SHIFT, // P 134 | 0x14|SHIFT, // Q 135 | 0x15|SHIFT, // R 136 | 0x16|SHIFT, // S 137 | 0x17|SHIFT, // T 138 | 0x18|SHIFT, // U 139 | 0x19|SHIFT, // V 140 | 0x1a|SHIFT, // W 141 | 0x1b|SHIFT, // X 142 | 0x1c|SHIFT, // Y 143 | 0x1d|SHIFT, // Z 144 | 0x25|ALT_GR, // [ 145 | 0x2d|ALT_GR, // bslash 146 | 0x26|ALT_GR, // ] 147 | 0x00, // ^ not supported (requires dead key + space) 148 | 0x38|SHIFT, // _ 149 | 0x00, // ` not supported (requires dead key + space) 150 | 0x04, // a 151 | 0x05, // b 152 | 0x06, // c 153 | 0x07, // d 154 | 0x08, // e 155 | 0x09, // f 156 | 0x0a, // g 157 | 0x0b, // h 158 | 0x0c, // i 159 | 0x0d, // j 160 | 0x0e, // k 161 | 0x0f, // l 162 | 0x10, // m 163 | 0x11, // n 164 | 0x12, // o 165 | 0x13, // p 166 | 0x14, // q 167 | 0x15, // r 168 | 0x16, // s 169 | 0x17, // t 170 | 0x18, // u 171 | 0x19, // v 172 | 0x1a, // w 173 | 0x1b, // x 174 | 0x1c, // y 175 | 0x1d, // z 176 | 0x24|ALT_GR, // { 177 | 0x32|ALT_GR, // | 178 | 0x27|ALT_GR, // } 179 | 0x00, // ~ not supported (requires dead key + space) 180 | 0x00 // DEL 181 | }; 182 | 183 | class KeyboardLayout_SE : public KeyboardLayout 184 | { 185 | public: 186 | KeyboardLayout_SE() 187 | { 188 | } 189 | ~KeyboardLayout_SE(){}; 190 | const uint8_t *getKeymap() 191 | { 192 | return KeyboardLayout_sv_SE; 193 | } 194 | /** 195 | * @brief Returns the keycode for the given key 196 | * 197 | * @param key Key value as string 198 | * @return Key code if possible 199 | */ 200 | uint16_t getKeycode(char16_t key) 201 | { 202 | Serial.print("Keycode"); 203 | uint16_t specialKeyCode = isSpecialKey(key); 204 | 205 | Serial.println(specialKeyCode); 206 | // Check if special key is in the map 207 | if (specialKeyCode != 0) 208 | { 209 | return specialKeyCode; 210 | } 211 | // No special key use the normal layout 212 | else 213 | { 214 | if (key < 128) 215 | { 216 | return KeyboardLayout_sv_SE[key]; 217 | } 218 | // Could not match code 219 | return 0; 220 | } 221 | } 222 | 223 | uint16_t isSpecialKey(char16_t key) 224 | { 225 | uint16_t keycode = 0; 226 | for (int i = 0; i < AMOUNT_OF_SPECIAL_CHARS; i++) 227 | { 228 | Serial.print("Searching key: "); 229 | Serial.println(key); 230 | Serial.print("Comparing with list: "); 231 | Serial.println((char16_t)KeyboardLayout_sv_SE_special_characters[i]); 232 | 233 | if (key == KeyboardLayout_sv_SE_special_characters[i]) 234 | { 235 | Serial.println("Compare keys"); 236 | Serial.println(key); 237 | Serial.println((char16_t)KeyboardLayout_sv_SE_special_characters[i]); 238 | Serial.println((char)key); 239 | Serial.println((char)KeyboardLayout_sv_SE_special_characters[i]); 240 | 241 | 242 | keycode = KeyboardLayout_sv_SE_special_keycodes[i]; 243 | Serial.println(keycode); 244 | break; 245 | } 246 | } 247 | return keycode; 248 | } 249 | 250 | protected: 251 | }; 252 | -------------------------------------------------------------------------------- /src/Keyboard-Layouts/KeyboardLayout_NO.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Norwegian keyboard layout. 4 | */ 5 | 6 | #include "KeyboardLayout.h" 7 | 8 | #pragma once 9 | 10 | //================================================================================ 11 | //================================================================================ 12 | // Keyboard 13 | 14 | // nb_NO keys 15 | #define KEY_A_RING (136+0x2f) 16 | #define KEY_UMLAUT (136+0x30) 17 | #define KEY_ACUTE_ACC (136+0x2e) 18 | #define KEY_O_STROKE (136+0x33) 19 | #define KEY_ASH (136+0x34) 20 | 21 | #define AMOUNT_OF_SPECIAL_CHARS 11 22 | 23 | extern const char16_t KeyboardLayout_nb_NO_special_characters[AMOUNT_OF_SPECIAL_CHARS] PROGMEM = { 24 | u'å', 25 | u'¨', 26 | u'´', 27 | u'ø', 28 | u'æ', 29 | u'Å', 30 | u'^', 31 | u'~', 32 | u'`', 33 | u'Ø', 34 | u'Æ' 35 | }; 36 | 37 | extern const uint16_t KeyboardLayout_nb_NO_special_keycodes[AMOUNT_OF_SPECIAL_CHARS] PROGMEM = { 38 | KEY_A_RING, 39 | KEY_UMLAUT, 40 | KEY_ACUTE_ACC | ALT_GR, 41 | KEY_O_STROKE, 42 | KEY_ASH, 43 | KEY_A_RING | U16SHIFT, 44 | KEY_UMLAUT | U16SHIFT, 45 | KEY_UMLAUT | ALT_GR, 46 | KEY_ACUTE_ACC | U16SHIFT, 47 | KEY_O_STROKE | U16SHIFT, 48 | KEY_ASH | U16SHIFT 49 | }; 50 | 51 | extern const uint8_t KeyboardLayout_nb_NO[128] PROGMEM = 52 | { 53 | 0x00, // NUL 54 | 0x00, // SOH 55 | 0x00, // STX 56 | 0x00, // ETX 57 | 0x00, // EOT 58 | 0x00, // ENQ 59 | 0x00, // ACK 60 | 0x00, // BEL 61 | 0x2a, // BS Backspace 62 | 0x2b, // TAB Tab 63 | 0x28, // LF Enter 64 | 0x00, // VT 65 | 0x00, // FF 66 | 0x00, // CR 67 | 0x00, // SO 68 | 0x00, // SI 69 | 0x00, // DEL 70 | 0x00, // DC1 71 | 0x00, // DC2 72 | 0x00, // DC3 73 | 0x00, // DC4 74 | 0x00, // NAK 75 | 0x00, // SYN 76 | 0x00, // ETB 77 | 0x00, // CAN 78 | 0x00, // EM 79 | 0x00, // SUB 80 | 0x00, // ESC 81 | 0x00, // FS 82 | 0x00, // GS 83 | 0x00, // RS 84 | 0x00, // US 85 | 86 | 0x2c, // ' ' 87 | 0x1e|SHIFT, // ! 88 | 0x1f|SHIFT, // " 89 | 0x20|SHIFT, // # 90 | 0x21|ALT_GR, // $ 91 | 0x22|SHIFT, // % 92 | 0x23|SHIFT, // & 93 | 0x31, // ' 94 | 0x25|SHIFT, // ( 95 | 0x26|SHIFT, // ) 96 | 0x31|SHIFT, // * 97 | 0x2d, // + 98 | 0x36, // , 99 | 0x38, // - 100 | 0x37, // . 101 | 0x24|SHIFT, // / 102 | 0x27, // 0 103 | 0x1e, // 1 104 | 0x1f, // 2 105 | 0x20, // 3 106 | 0x21, // 4 107 | 0x22, // 5 108 | 0x23, // 6 109 | 0x24, // 7 110 | 0x25, // 8 111 | 0x26, // 9 112 | 0x37|SHIFT, // : 113 | 0x36|SHIFT, // ; 114 | 0x32, // < 115 | 0x27|SHIFT, // = 116 | 0x32|SHIFT, // > 117 | 0x2d|SHIFT, // ? 118 | 0x1f|ALT_GR, // @ 119 | 0x04|SHIFT, // A 120 | 0x05|SHIFT, // B 121 | 0x06|SHIFT, // C 122 | 0x07|SHIFT, // D 123 | 0x08|SHIFT, // E 124 | 0x09|SHIFT, // F 125 | 0x0a|SHIFT, // G 126 | 0x0b|SHIFT, // H 127 | 0x0c|SHIFT, // I 128 | 0x0d|SHIFT, // J 129 | 0x0e|SHIFT, // K 130 | 0x0f|SHIFT, // L 131 | 0x10|SHIFT, // M 132 | 0x11|SHIFT, // N 133 | 0x12|SHIFT, // O 134 | 0x13|SHIFT, // P 135 | 0x14|SHIFT, // Q 136 | 0x15|SHIFT, // R 137 | 0x16|SHIFT, // S 138 | 0x17|SHIFT, // T 139 | 0x18|SHIFT, // U 140 | 0x19|SHIFT, // V 141 | 0x1a|SHIFT, // W 142 | 0x1b|SHIFT, // X 143 | 0x1c|SHIFT, // Y 144 | 0x1d|SHIFT, // Z 145 | 0x25|ALT_GR, // [ 146 | 0x2e, // bslash 147 | 0x26|ALT_GR, // ] 148 | 0x00, // ^ not supported (requires dead key + space) 149 | 0x38|SHIFT, // _ 150 | 0x00, // ` not supported (requires dead key + space) 151 | 0x04, // a 152 | 0x05, // b 153 | 0x06, // c 154 | 0x07, // d 155 | 0x08, // e 156 | 0x09, // f 157 | 0x0a, // g 158 | 0x0b, // h 159 | 0x0c, // i 160 | 0x0d, // j 161 | 0x0e, // k 162 | 0x0f, // l 163 | 0x10, // m 164 | 0x11, // n 165 | 0x12, // o 166 | 0x13, // p 167 | 0x14, // q 168 | 0x15, // r 169 | 0x16, // s 170 | 0x17, // t 171 | 0x18, // u 172 | 0x19, // v 173 | 0x1a, // w 174 | 0x1b, // x 175 | 0x1c, // y 176 | 0x1d, // z 177 | 0x24|ALT_GR, // { 178 | 0x35, // | 179 | 0x27|ALT_GR, // } 180 | 0x00, // ~ not supported (requires dead key + space) 181 | 0x00 // DEL 182 | }; 183 | 184 | class KeyboardLayout_NO : public KeyboardLayout 185 | { 186 | public: 187 | KeyboardLayout_NO() 188 | { 189 | } 190 | ~KeyboardLayout_NO(){}; 191 | const uint8_t *getKeymap() 192 | { 193 | return KeyboardLayout_nb_NO; 194 | } 195 | /** 196 | * @brief Returns the keycode for the given key 197 | * 198 | * @param key Key value as string 199 | * @return Key code if possible 200 | */ 201 | uint16_t getKeycode(char16_t key) 202 | { 203 | Serial.print("Keycode"); 204 | uint16_t specialKeyCode = isSpecialKey(key); 205 | 206 | Serial.println(specialKeyCode); 207 | // Check if special key is in the map 208 | if (specialKeyCode != 0) 209 | { 210 | return specialKeyCode; 211 | } 212 | // No special key use the normal layout 213 | else 214 | { 215 | if (key < 128) 216 | { 217 | return KeyboardLayout_nb_NO[key]; 218 | } 219 | // Could not match code 220 | return 0; 221 | } 222 | } 223 | 224 | uint16_t isSpecialKey(char16_t key) 225 | { 226 | uint16_t keycode = 0; 227 | for (int i = 0; i < AMOUNT_OF_SPECIAL_CHARS; i++) 228 | { 229 | Serial.print("Searching key: "); 230 | Serial.println(key); 231 | Serial.print("Comparing with list: "); 232 | Serial.println((char16_t)KeyboardLayout_nb_NO_special_characters[i]); 233 | 234 | if (key == KeyboardLayout_nb_NO_special_characters[i]) 235 | { 236 | Serial.println("Compare keys"); 237 | Serial.println(key); 238 | Serial.println((char16_t)KeyboardLayout_nb_NO_special_characters[i]); 239 | Serial.println((char)key); 240 | Serial.println((char)KeyboardLayout_nb_NO_special_characters[i]); 241 | 242 | 243 | keycode = KeyboardLayout_nb_NO_special_keycodes[i]; 244 | Serial.println(keycode); 245 | break; 246 | } 247 | } 248 | return keycode; 249 | } 250 | 251 | protected: 252 | }; 253 | -------------------------------------------------------------------------------- /src/Keyboard-Layouts/KeyboardLayout_BR.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Brazilian keyboard layout. 3 | */ 4 | 5 | #include "KeyboardLayout.h" 6 | 7 | #pragma once 8 | 9 | //================================================================================ 10 | //================================================================================ 11 | // Keyboard 12 | 13 | // pt_BR keys 14 | #define KEY_MASCULINE_ORDINAL (136+0x31) 15 | #define KEY_SIX (136+0x23) 16 | #define KEY_ACUTE (136+0x2f) 17 | #define KEY_C_CEDILLA (136+0x33) 18 | #define KEY_TILDE (136+0x34) 19 | 20 | #define AMOUNT_OF_SPECIAL_CHARS 9 21 | 22 | extern const char16_t KeyboardLayout_pt_BR_special_characters[AMOUNT_OF_SPECIAL_CHARS] PROGMEM = { 23 | u'º', // Doesn't work 24 | u'¨', 25 | u'´', 26 | u'ç', 27 | u'~', 28 | u'ª', // Doesn't work 29 | u'`', 30 | u'Ç', 31 | u'^' 32 | }; 33 | 34 | extern const uint16_t KeyboardLayout_pt_BR_special_keycodes[AMOUNT_OF_SPECIAL_CHARS] PROGMEM = { 35 | KEY_MASCULINE_ORDINAL, 36 | KEY_SIX | U16SHIFT, 37 | KEY_ACUTE, 38 | KEY_C_CEDILLA, 39 | KEY_TILDE, 40 | KEY_MASCULINE_ORDINAL | U16SHIFT, 41 | KEY_ACUTE | U16SHIFT, 42 | KEY_C_CEDILLA | U16SHIFT, 43 | KEY_TILDE | U16SHIFT 44 | }; 45 | 46 | extern const uint8_t KeyboardLayout_pt_BR[128] PROGMEM = 47 | { 48 | 0x00, // NUL 49 | 0x00, // SOH 50 | 0x00, // STX 51 | 0x00, // ETX 52 | 0x00, // EOT 53 | 0x00, // ENQ 54 | 0x00, // ACK 55 | 0x00, // BEL 56 | 0x2a, // BS Backspace 57 | 0x2b, // TAB Tab 58 | 0x28, // LF Enter 59 | 0x00, // VT 60 | 0x00, // FF 61 | 0x00, // CR 62 | 0x00, // SO 63 | 0x00, // SI 64 | 0x00, // DEL 65 | 0x00, // DC1 66 | 0x00, // DC2 67 | 0x00, // DC3 68 | 0x00, // DC4 69 | 0x00, // NAK 70 | 0x00, // SYN 71 | 0x00, // ETB 72 | 0x00, // CAN 73 | 0x00, // EM 74 | 0x00, // SUB 75 | 0x00, // ESC 76 | 0x00, // FS 77 | 0x00, // GS 78 | 0x00, // RS 79 | 0x00, // US 80 | 81 | 0x2c, // ' ' 82 | 0x1e|SHIFT, // ! 83 | 0x35|SHIFT, // " 84 | 0x20|SHIFT, // # 85 | 0x21|SHIFT, // $ 86 | 0x22|SHIFT, // % 87 | 0x24|SHIFT, // & 88 | 0x35, // ' 89 | 0x26|SHIFT, // ( 90 | 0x27|SHIFT, // ) 91 | 0x25|SHIFT, // * 92 | 0x2e|SHIFT, // + 93 | 0x36, // , 94 | 0x2d, // - 95 | 0x37, // . 96 | 0x14|ALT_GR, // / 97 | 0x27, // 0 98 | 0x1e, // 1 99 | 0x1f, // 2 100 | 0x20, // 3 101 | 0x21, // 4 102 | 0x22, // 5 103 | 0x23, // 6 104 | 0x24, // 7 105 | 0x25, // 8 106 | 0x26, // 9 107 | 0x38|SHIFT, // : 108 | 0x38, // ; 109 | 0x36|SHIFT, // < 110 | 0x2e, // = 111 | 0x37|SHIFT, // > 112 | 0x1a|ALT_GR, // ? 113 | 0x1f|SHIFT, // @ 114 | 0x04|SHIFT, // A 115 | 0x05|SHIFT, // B 116 | 0x06|SHIFT, // C 117 | 0x07|SHIFT, // D 118 | 0x08|SHIFT, // E 119 | 0x09|SHIFT, // F 120 | 0x0a|SHIFT, // G 121 | 0x0b|SHIFT, // H 122 | 0x0c|SHIFT, // I 123 | 0x0d|SHIFT, // J 124 | 0x0e|SHIFT, // K 125 | 0x0f|SHIFT, // L 126 | 0x10|SHIFT, // M 127 | 0x11|SHIFT, // N 128 | 0x12|SHIFT, // O 129 | 0x13|SHIFT, // P 130 | 0x14|SHIFT, // Q 131 | 0x15|SHIFT, // R 132 | 0x16|SHIFT, // S 133 | 0x17|SHIFT, // T 134 | 0x18|SHIFT, // U 135 | 0x19|SHIFT, // V 136 | 0x1a|SHIFT, // W 137 | 0x1b|SHIFT, // X 138 | 0x1c|SHIFT, // Y 139 | 0x1d|SHIFT, // Z 140 | 0x30, // [ 141 | 0x32, // bslash 142 | 0x31, // ] 143 | 0x00, // ^ not supported (requires dead key + space) 144 | 0x38|SHIFT, // _ 145 | 0x00, // ` not supported (requires dead key + space) 146 | 0x04, // a 147 | 0x05, // b 148 | 0x06, // c 149 | 0x07, // d 150 | 0x08, // e 151 | 0x09, // f 152 | 0x0a, // g 153 | 0x0b, // h 154 | 0x0c, // i 155 | 0x0d, // j 156 | 0x0e, // k 157 | 0x0f, // l 158 | 0x10, // m 159 | 0x11, // n 160 | 0x12, // o 161 | 0x13, // p 162 | 0x14, // q 163 | 0x15, // r 164 | 0x16, // s 165 | 0x17, // t 166 | 0x18, // u 167 | 0x19, // v 168 | 0x1a, // w 169 | 0x1b, // x 170 | 0x1c, // y 171 | 0x1d, // z 172 | 0x30|SHIFT, // { 173 | 0x32|SHIFT, // | 174 | 0x31|SHIFT, // } 175 | 0x21|ALT_GR, // ~ not supported (requires dead key + space) 176 | 0x00 // DEL 177 | }; 178 | 179 | class KeyboardLayout_BR : public KeyboardLayout 180 | { 181 | public: 182 | KeyboardLayout_BR() 183 | { 184 | } 185 | ~KeyboardLayout_BR(){}; 186 | const uint8_t *getKeymap() 187 | { 188 | return KeyboardLayout_pt_BR; 189 | } 190 | /** 191 | * @brief Returns the keycode for the given key 192 | * 193 | * @param key Key value as string 194 | * @return Key code if possible 195 | */ 196 | uint16_t getKeycode(char16_t key) 197 | { 198 | Serial.print("Keycode"); 199 | uint16_t specialKeyCode = isSpecialKey(key); 200 | 201 | Serial.println(specialKeyCode); 202 | // Check if special key is in the map 203 | if (specialKeyCode != 0) 204 | { 205 | return specialKeyCode; 206 | } 207 | // No special key use the normal layout 208 | else 209 | { 210 | if (key < 128) 211 | { 212 | return KeyboardLayout_pt_BR[key]; 213 | } 214 | // Could not match code 215 | return 0; 216 | } 217 | } 218 | 219 | uint16_t isSpecialKey(char16_t key) 220 | { 221 | uint16_t keycode = 0; 222 | for (int i = 0; i < AMOUNT_OF_SPECIAL_CHARS; i++) 223 | { 224 | Serial.print("Searching key: "); 225 | Serial.println(key); 226 | Serial.print("Comparing with list: "); 227 | Serial.println((char16_t)KeyboardLayout_pt_BR_special_characters[i]); 228 | 229 | if (key == KeyboardLayout_pt_BR_special_characters[i]) 230 | { 231 | Serial.println("Compare keys"); 232 | Serial.println(key); 233 | Serial.println((char16_t)KeyboardLayout_pt_BR_special_characters[i]); 234 | Serial.println((char)key); 235 | Serial.println((char)KeyboardLayout_pt_BR_special_characters[i]); 236 | 237 | 238 | keycode = KeyboardLayout_pt_BR_special_keycodes[i]; 239 | Serial.println(keycode); 240 | break; 241 | } 242 | } 243 | return keycode; 244 | } 245 | 246 | protected: 247 | }; 248 | -------------------------------------------------------------------------------- /src/Keyboard-Layouts/KeyboardLayout_DE.h: -------------------------------------------------------------------------------- 1 | /* 2 | * German keyboard layout. 3 | */ 4 | 5 | #include "KeyboardLayout.h" 6 | 7 | #pragma once 8 | 9 | // //================================================================================ 10 | // //================================================================================ 11 | // // Keyboard 12 | 13 | // // de_DE keys 14 | #define KEY_CIRCUMFLEX (136 + 0x35) 15 | #define KEY_ESZETT (136 + 0x2d) 16 | #define KEY_ACUTE (136 + 0x2e) 17 | #define KEY_U_UMLAUT (136 + 0x2f) 18 | #define KEY_O_UMLAUT (136 + 0x33) 19 | #define KEY_A_UMLAUT (136 + 0x34) 20 | 21 | #define AMOUNT_OF_SPECIAL_CHARS 11 22 | 23 | extern const char16_t KeyboardLayout_de_DE_special_characters[AMOUNT_OF_SPECIAL_CHARS] PROGMEM = 24 | { 25 | u'^', 26 | u'ß', 27 | u'´', 28 | u'ü', 29 | u'ö', 30 | u'ä', 31 | u'º', 32 | u'`', 33 | u'Ü', 34 | u'Ö', 35 | u'Ä' 36 | }; 37 | 38 | extern const uint16_t KeyboardLayout_de_DE_special_keycodes[AMOUNT_OF_SPECIAL_CHARS] PROGMEM = 39 | { 40 | KEY_CIRCUMFLEX, 41 | KEY_ESZETT, 42 | KEY_ACUTE, 43 | KEY_U_UMLAUT, 44 | KEY_O_UMLAUT, 45 | KEY_A_UMLAUT, 46 | KEY_CIRCUMFLEX | U16SHIFT, 47 | KEY_ACUTE | U16SHIFT, 48 | KEY_U_UMLAUT | U16SHIFT, 49 | KEY_O_UMLAUT | U16SHIFT, 50 | KEY_A_UMLAUT | U16SHIFT 51 | }; 52 | 53 | extern const uint8_t KeyboardLayout_de_DE[128] PROGMEM = 54 | { 55 | 0x00, // NUL 56 | 0x00, // SOH 57 | 0x00, // STX 58 | 0x00, // ETX 59 | 0x00, // EOT 60 | 0x00, // ENQ 61 | 0x00, // ACK 62 | 0x00, // BEL 63 | 0x2a, // BS Backspace 64 | 0x2b, // TAB Tab 65 | 0x28, // LF Enter 66 | 0x00, // VT 67 | 0x00, // FF 68 | 0x00, // CR 69 | 0x00, // SO 70 | 0x00, // SI 71 | 0x00, // DEL 72 | 0x00, // DC1 73 | 0x00, // DC2 74 | 0x00, // DC3 75 | 0x00, // DC4 76 | 0x00, // NAK 77 | 0x00, // SYN 78 | 0x00, // ETB 79 | 0x00, // CAN 80 | 0x00, // EM 81 | 0x00, // SUB 82 | 0x00, // ESC 83 | 0x00, // FS 84 | 0x00, // GS 85 | 0x00, // RS 86 | 0x00, // US 87 | 88 | 0x2c, // ' ' 89 | 0x1e | SHIFT, // ! 90 | 0x1f | SHIFT, // " 91 | 0x31, // # 92 | 0x21 | SHIFT, // $ 93 | 0x22 | SHIFT, // % 94 | 0x23 | SHIFT, // & 95 | 0x31 | SHIFT, // ' 96 | 0x25 | SHIFT, // ( 97 | 0x26 | SHIFT, // ) 98 | 0x30 | SHIFT, // * 99 | 0x30, // + 100 | 0x36, // , 101 | 0x38, // - 102 | 0x37, // . 103 | 0x24 | SHIFT, // / 104 | 0x27, // 0 105 | 0x1e, // 1 106 | 0x1f, // 2 107 | 0x20, // 3 108 | 0x21, // 4 109 | 0x22, // 5 110 | 0x23, // 6 111 | 0x24, // 7 112 | 0x25, // 8 113 | 0x26, // 9 114 | 0x37 | SHIFT, // : 115 | 0x36 | SHIFT, // ; 116 | 0x32, // < 117 | 0x27 | SHIFT, // = 118 | 0x32 | SHIFT, // > 119 | 0x2d | SHIFT, // ? 120 | 0x14 | ALT_GR, // @ 121 | 0x04 | SHIFT, // A 122 | 0x05 | SHIFT, // B 123 | 0x06 | SHIFT, // C 124 | 0x07 | SHIFT, // D 125 | 0x08 | SHIFT, // E 126 | 0x09 | SHIFT, // F 127 | 0x0a | SHIFT, // G 128 | 0x0b | SHIFT, // H 129 | 0x0c | SHIFT, // I 130 | 0x0d | SHIFT, // J 131 | 0x0e | SHIFT, // K 132 | 0x0f | SHIFT, // L 133 | 0x10 | SHIFT, // M 134 | 0x11 | SHIFT, // N 135 | 0x12 | SHIFT, // O 136 | 0x13 | SHIFT, // P 137 | 0x14 | SHIFT, // Q 138 | 0x15 | SHIFT, // R 139 | 0x16 | SHIFT, // S 140 | 0x17 | SHIFT, // T 141 | 0x18 | SHIFT, // U 142 | 0x19 | SHIFT, // V 143 | 0x1a | SHIFT, // W 144 | 0x1b | SHIFT, // X 145 | 0x1d | SHIFT, // Y 146 | 0x1c | SHIFT, // Z 147 | 0x25 | ALT_GR, // [ 148 | 0x2d | ALT_GR, // bslash 149 | 0x26 | ALT_GR, // ] 150 | 0x00, // ^ not supported (requires dead key + space) 151 | 0x38 | SHIFT, // _ 152 | 0x00, // ` not supported (requires dead key + space) 153 | 0x04, // a 154 | 0x05, // b 155 | 0x06, // c 156 | 0x07, // d 157 | 0x08, // e 158 | 0x09, // f 159 | 0x0a, // g 160 | 0x0b, // h 161 | 0x0c, // i 162 | 0x0d, // j 163 | 0x0e, // k 164 | 0x0f, // l 165 | 0x10, // m 166 | 0x11, // n 167 | 0x12, // o 168 | 0x13, // p 169 | 0x14, // q 170 | 0x15, // r 171 | 0x16, // s 172 | 0x17, // t 173 | 0x18, // u 174 | 0x19, // v 175 | 0x1a, // w 176 | 0x1b, // x 177 | 0x1d, // y 178 | 0x1c, // z 179 | 0x24 | ALT_GR, // { 180 | 0x32 | ALT_GR, // | 181 | 0x27 | ALT_GR, // } 182 | 0x30 | ALT_GR, // ~ 183 | 0x00 // DEL 184 | }; 185 | 186 | class KeyboardLayout_DE : public KeyboardLayout 187 | { 188 | public: 189 | KeyboardLayout_DE() 190 | { 191 | } 192 | ~KeyboardLayout_DE(){}; 193 | const uint8_t *getKeymap() 194 | { 195 | return KeyboardLayout_de_DE; 196 | } 197 | /** 198 | * @brief Returns the keycode for the given key 199 | * 200 | * @param key Key value as string 201 | * @return Key code if possible 202 | */ 203 | uint16_t getKeycode(char16_t key) 204 | { 205 | Serial.print("Keycode"); 206 | uint16_t specialKeyCode = isSpecialKey(key); 207 | 208 | Serial.println(specialKeyCode); 209 | // Check if special key is in the map 210 | if (specialKeyCode != 0) 211 | { 212 | return specialKeyCode; 213 | } 214 | // No special key use the normal layout 215 | else 216 | { 217 | if (key < 128) 218 | { 219 | return KeyboardLayout_de_DE[key]; 220 | } 221 | // Could not match code 222 | return 0; 223 | } 224 | } 225 | 226 | uint16_t isSpecialKey(char16_t key) 227 | { 228 | uint16_t keycode = 0; 229 | for (int i = 0; i < AMOUNT_OF_SPECIAL_CHARS; i++) 230 | { 231 | Serial.print("Searching key: "); 232 | Serial.println(key); 233 | Serial.print("Comparing with list: "); 234 | Serial.println((char16_t)KeyboardLayout_de_DE_special_characters[i]); 235 | 236 | if (key == KeyboardLayout_de_DE_special_characters[i]) 237 | { 238 | Serial.println("Compare keys"); 239 | Serial.println(key); 240 | Serial.println((char16_t)KeyboardLayout_de_DE_special_characters[i]); 241 | Serial.println((char)key); 242 | Serial.println((char)KeyboardLayout_de_DE_special_characters[i]); 243 | 244 | 245 | keycode = KeyboardLayout_de_DE_special_keycodes[i]; 246 | Serial.println(keycode); 247 | break; 248 | } 249 | } 250 | return keycode; 251 | } 252 | 253 | protected: 254 | }; 255 | -------------------------------------------------------------------------------- /src/Keyboard-Layouts/KeyboardLayout_ES.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Spanish keyboard layout. 3 | */ 4 | 5 | #include "KeyboardLayout.h" 6 | 7 | #pragma once 8 | 9 | //================================================================================ 10 | //================================================================================ 11 | // Keyboard 12 | 13 | // es_ES keys 14 | #define KEY_MASCULINE_ORDINAL (136+0x35) 15 | #define KEY_INVERTED_EXCLAMATION (136+0x2e) 16 | #define KEY_GRAVE (136+0x2f) 17 | #define KEY_N_TILDE (136+0x33) 18 | #define KEY_ACUTE (136+0x34) 19 | #define KEY_C_CEDILLA (136+0x31) 20 | 21 | #define AMOUNT_OF_SPECIAL_CHARS 11 22 | 23 | extern const char16_t KeyboardLayout_es_ES_special_characters[AMOUNT_OF_SPECIAL_CHARS] PROGMEM = { 24 | u'º', 25 | u'¡', 26 | u'`', 27 | u'ñ', 28 | u'´', 29 | u'ç', 30 | u'ª', 31 | u'^', 32 | u'Ñ', 33 | u'¨', 34 | u'Ç' 35 | }; 36 | 37 | extern const uint16_t KeyboardLayout_es_ES_special_keycodes[AMOUNT_OF_SPECIAL_CHARS] PROGMEM = { 38 | KEY_MASCULINE_ORDINAL, 39 | KEY_INVERTED_EXCLAMATION, 40 | KEY_GRAVE, 41 | KEY_N_TILDE, 42 | KEY_ACUTE, 43 | KEY_C_CEDILLA, 44 | KEY_MASCULINE_ORDINAL | U16SHIFT, 45 | KEY_GRAVE | U16SHIFT, 46 | KEY_N_TILDE | U16SHIFT, 47 | KEY_ACUTE | U16SHIFT, 48 | KEY_C_CEDILLA | U16SHIFT 49 | }; 50 | 51 | extern const uint8_t KeyboardLayout_es_ES[128] PROGMEM = 52 | { 53 | 0x00, // NUL 54 | 0x00, // SOH 55 | 0x00, // STX 56 | 0x00, // ETX 57 | 0x00, // EOT 58 | 0x00, // ENQ 59 | 0x00, // ACK 60 | 0x00, // BEL 61 | 0x2a, // BS Backspace 62 | 0x2b, // TAB Tab 63 | 0x28, // LF Enter 64 | 0x00, // VT 65 | 0x00, // FF 66 | 0x00, // CR 67 | 0x00, // SO 68 | 0x00, // SI 69 | 0x00, // DEL 70 | 0x00, // DC1 71 | 0x00, // DC2 72 | 0x00, // DC3 73 | 0x00, // DC4 74 | 0x00, // NAK 75 | 0x00, // SYN 76 | 0x00, // ETB 77 | 0x00, // CAN 78 | 0x00, // EM 79 | 0x00, // SUB 80 | 0x00, // ESC 81 | 0x00, // FS 82 | 0x00, // GS 83 | 0x00, // RS 84 | 0x00, // US 85 | 86 | 0x2c, // ' ' 87 | 0x1e|SHIFT, // ! 88 | 0x1f|SHIFT, // " 89 | 0x20|ALT_GR, // # 90 | 0x21|SHIFT, // $ 91 | 0x22|SHIFT, // % 92 | 0x23|SHIFT, // & 93 | 0x2d, // ' 94 | 0x25|SHIFT, // ( 95 | 0x26|SHIFT, // ) 96 | 0x30|SHIFT, // * 97 | 0x30, // + 98 | 0x36, // , 99 | 0x38, // - 100 | 0x37, // . 101 | 0x24|SHIFT, // / 102 | 0x27, // 0 103 | 0x1e, // 1 104 | 0x1f, // 2 105 | 0x20, // 3 106 | 0x21, // 4 107 | 0x22, // 5 108 | 0x23, // 6 109 | 0x24, // 7 110 | 0x25, // 8 111 | 0x26, // 9 112 | 0x37|SHIFT, // : 113 | 0x36|SHIFT, // ; 114 | 0x32, // < 115 | 0x27|SHIFT, // = 116 | 0x32|SHIFT, // > 117 | 0x2d|SHIFT, // ? 118 | 0x1f|ALT_GR, // @ 119 | 0x04|SHIFT, // A 120 | 0x05|SHIFT, // B 121 | 0x06|SHIFT, // C 122 | 0x07|SHIFT, // D 123 | 0x08|SHIFT, // E 124 | 0x09|SHIFT, // F 125 | 0x0a|SHIFT, // G 126 | 0x0b|SHIFT, // H 127 | 0x0c|SHIFT, // I 128 | 0x0d|SHIFT, // J 129 | 0x0e|SHIFT, // K 130 | 0x0f|SHIFT, // L 131 | 0x10|SHIFT, // M 132 | 0x11|SHIFT, // N 133 | 0x12|SHIFT, // O 134 | 0x13|SHIFT, // P 135 | 0x14|SHIFT, // Q 136 | 0x15|SHIFT, // R 137 | 0x16|SHIFT, // S 138 | 0x17|SHIFT, // T 139 | 0x18|SHIFT, // U 140 | 0x19|SHIFT, // V 141 | 0x1a|SHIFT, // W 142 | 0x1b|SHIFT, // X 143 | 0x1c|SHIFT, // Y 144 | 0x1d|SHIFT, // Z 145 | 0x2f|ALT_GR, // [ 146 | 0x35|ALT_GR, // bslash 147 | 0x30|ALT_GR, // ] 148 | 0x00, // ^ not supported (requires dead key + space) 149 | 0x38|SHIFT, // _ 150 | 0x00, // ` not supported (requires dead key + space) 151 | 0x04, // a 152 | 0x05, // b 153 | 0x06, // c 154 | 0x07, // d 155 | 0x08, // e 156 | 0x09, // f 157 | 0x0a, // g 158 | 0x0b, // h 159 | 0x0c, // i 160 | 0x0d, // j 161 | 0x0e, // k 162 | 0x0f, // l 163 | 0x10, // m 164 | 0x11, // n 165 | 0x12, // o 166 | 0x13, // p 167 | 0x14, // q 168 | 0x15, // r 169 | 0x16, // s 170 | 0x17, // t 171 | 0x18, // u 172 | 0x19, // v 173 | 0x1a, // w 174 | 0x1b, // x 175 | 0x1c, // y 176 | 0x1d, // z 177 | 0x34|ALT_GR, // { 178 | 0x1e|ALT_GR, // | 179 | 0x31|ALT_GR, // } 180 | 0x21|ALT_GR, // ~ 181 | 0x00 // DEL 182 | }; 183 | 184 | class KeyboardLayout_ES : public KeyboardLayout 185 | { 186 | public: 187 | KeyboardLayout_ES() 188 | { 189 | } 190 | ~KeyboardLayout_ES(){}; 191 | const uint8_t *getKeymap() 192 | { 193 | return KeyboardLayout_es_ES; 194 | } 195 | /** 196 | * @brief Returns the keycode for the given key 197 | * 198 | * @param key Key value as string 199 | * @return Key code if possible 200 | */ 201 | uint16_t getKeycode(char16_t key) 202 | { 203 | Serial.print("Keycode"); 204 | uint16_t specialKeyCode = isSpecialKey(key); 205 | 206 | Serial.println(specialKeyCode); 207 | // Check if special key is in the map 208 | if (specialKeyCode != 0) 209 | { 210 | return specialKeyCode; 211 | } 212 | // No special key use the normal layout 213 | else 214 | { 215 | if (key < 128) 216 | { 217 | return KeyboardLayout_es_ES[key]; 218 | } 219 | // Could not match code 220 | return 0; 221 | } 222 | } 223 | 224 | uint16_t isSpecialKey(char16_t key) 225 | { 226 | uint16_t keycode = 0; 227 | for (int i = 0; i < AMOUNT_OF_SPECIAL_CHARS; i++) 228 | { 229 | Serial.print("Searching key: "); 230 | Serial.println(key); 231 | Serial.print("Comparing with list: "); 232 | Serial.println((char16_t)KeyboardLayout_es_ES_special_characters[i]); 233 | 234 | if (key == KeyboardLayout_es_ES_special_characters[i]) 235 | { 236 | Serial.println("Compare keys"); 237 | Serial.println(key); 238 | Serial.println((char16_t)KeyboardLayout_es_ES_special_characters[i]); 239 | Serial.println((char)key); 240 | Serial.println((char)KeyboardLayout_es_ES_special_characters[i]); 241 | 242 | 243 | keycode = KeyboardLayout_es_ES_special_keycodes[i]; 244 | Serial.println(keycode); 245 | break; 246 | } 247 | } 248 | return keycode; 249 | } 250 | 251 | protected: 252 | }; 253 | -------------------------------------------------------------------------------- /src/Keyboard-Layouts/KeyboardLayout_PT.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Portuguese keyboard layout. 3 | */ 4 | 5 | #include "KeyboardLayout.h" 6 | 7 | #pragma once 8 | 9 | //================================================================================ 10 | //================================================================================ 11 | // Keyboard 12 | 13 | // pt_PT keys 14 | #define KEY_LEFT_GUILLEMET (136+0x2e) 15 | #define KEY_ACUTE (136+0x30) 16 | #define KEY_C_CEDILLA (136+0x33) 17 | #define KEY_MASCULINE_ORDINAL (136+0x34) 18 | #define KEY_TILDE (136+0x31) 19 | 20 | #define AMOUNT_OF_SPECIAL_CHARS 10 21 | 22 | extern const char16_t KeyboardLayout_pt_PT_special_characters[AMOUNT_OF_SPECIAL_CHARS] PROGMEM = { 23 | u'«', 24 | u'º', 25 | u'´', 26 | u'ç', 27 | u'~', 28 | u'»', 29 | u'ª', 30 | u'^', 31 | u'`', 32 | u'Ç', 33 | }; 34 | 35 | extern const uint16_t KeyboardLayout_pt_PT_special_keycodes[AMOUNT_OF_SPECIAL_CHARS] PROGMEM = { 36 | KEY_LEFT_GUILLEMET, 37 | KEY_MASCULINE_ORDINAL, 38 | KEY_ACUTE, 39 | KEY_C_CEDILLA, 40 | KEY_TILDE, 41 | KEY_LEFT_GUILLEMET | U16SHIFT, 42 | KEY_MASCULINE_ORDINAL | U16SHIFT, 43 | KEY_TILDE | U16SHIFT, 44 | KEY_ACUTE | U16SHIFT, 45 | KEY_C_CEDILLA | U16SHIFT, 46 | }; 47 | 48 | extern const uint8_t KeyboardLayout_pt_PT[128] PROGMEM = 49 | { 50 | 0x00, // NUL 51 | 0x00, // SOH 52 | 0x00, // STX 53 | 0x00, // ETX 54 | 0x00, // EOT 55 | 0x00, // ENQ 56 | 0x00, // ACK 57 | 0x00, // BEL 58 | 0x2a, // BS Backspace 59 | 0x2b, // TAB Tab 60 | 0x28, // LF Enter 61 | 0x00, // VT 62 | 0x00, // FF 63 | 0x00, // CR 64 | 0x00, // SO 65 | 0x00, // SI 66 | 0x00, // DEL 67 | 0x00, // DC1 68 | 0x00, // DC2 69 | 0x00, // DC3 70 | 0x00, // DC4 71 | 0x00, // NAK 72 | 0x00, // SYN 73 | 0x00, // ETB 74 | 0x00, // CAN 75 | 0x00, // EM 76 | 0x00, // SUB 77 | 0x00, // ESC 78 | 0x00, // FS 79 | 0x00, // GS 80 | 0x00, // RS 81 | 0x00, // US 82 | 83 | 0x2c, // ' ' 84 | 0x1e|SHIFT, // ! 85 | 0x1f|SHIFT, // " 86 | 0x20|SHIFT, // # 87 | 0x21|SHIFT, // $ 88 | 0x22|SHIFT, // % 89 | 0x23|SHIFT, // & 90 | 0x2d, // ' 91 | 0x25|SHIFT, // ( 92 | 0x26|SHIFT, // ) 93 | 0x2f|SHIFT, // * 94 | 0x2f, // + 95 | 0x36, // , 96 | 0x38, // - 97 | 0x37, // . 98 | 0x24|SHIFT, // / 99 | 0x27, // 0 100 | 0x1e, // 1 101 | 0x1f, // 2 102 | 0x20, // 3 103 | 0x21, // 4 104 | 0x22, // 5 105 | 0x23, // 6 106 | 0x24, // 7 107 | 0x25, // 8 108 | 0x26, // 9 109 | 0x37|SHIFT, // : 110 | 0x36|SHIFT, // ; 111 | 0x32, // < 112 | 0x27|SHIFT, // = 113 | 0x32|SHIFT, // > 114 | 0x2d|SHIFT, // ? 115 | 0x1f|ALT_GR, // @ 116 | 0x04|SHIFT, // A 117 | 0x05|SHIFT, // B 118 | 0x06|SHIFT, // C 119 | 0x07|SHIFT, // D 120 | 0x08|SHIFT, // E 121 | 0x09|SHIFT, // F 122 | 0x0a|SHIFT, // G 123 | 0x0b|SHIFT, // H 124 | 0x0c|SHIFT, // I 125 | 0x0d|SHIFT, // J 126 | 0x0e|SHIFT, // K 127 | 0x0f|SHIFT, // L 128 | 0x10|SHIFT, // M 129 | 0x11|SHIFT, // N 130 | 0x12|SHIFT, // O 131 | 0x13|SHIFT, // P 132 | 0x14|SHIFT, // Q 133 | 0x15|SHIFT, // R 134 | 0x16|SHIFT, // S 135 | 0x17|SHIFT, // T 136 | 0x18|SHIFT, // U 137 | 0x19|SHIFT, // V 138 | 0x1a|SHIFT, // W 139 | 0x1b|SHIFT, // X 140 | 0x1c|SHIFT, // Y 141 | 0x1d|SHIFT, // Z 142 | 0x25|ALT_GR, // [ 143 | 0x35, // bslash 144 | 0x26|ALT_GR, // ] 145 | 0x00, // ^ not supported (requires dead key + space) 146 | 0x38|SHIFT, // _ 147 | 0x00, // ` not supported (requires dead key + space) 148 | 0x04, // a 149 | 0x05, // b 150 | 0x06, // c 151 | 0x07, // d 152 | 0x08, // e 153 | 0x09, // f 154 | 0x0a, // g 155 | 0x0b, // h 156 | 0x0c, // i 157 | 0x0d, // j 158 | 0x0e, // k 159 | 0x0f, // l 160 | 0x10, // m 161 | 0x11, // n 162 | 0x12, // o 163 | 0x13, // p 164 | 0x14, // q 165 | 0x15, // r 166 | 0x16, // s 167 | 0x17, // t 168 | 0x18, // u 169 | 0x19, // v 170 | 0x1a, // w 171 | 0x1b, // x 172 | 0x1c, // y 173 | 0x1d, // z 174 | 0x24|ALT_GR, // { 175 | 0x35|SHIFT, // | 176 | 0x27|ALT_GR, // } 177 | 0x00, // ~ not supported (requires dead key + space) 178 | 0x00 // DEL 179 | }; 180 | 181 | class KeyboardLayout_PT : public KeyboardLayout 182 | { 183 | public: 184 | KeyboardLayout_PT() 185 | { 186 | } 187 | ~KeyboardLayout_PT(){}; 188 | const uint8_t *getKeymap() 189 | { 190 | return KeyboardLayout_pt_PT; 191 | } 192 | /** 193 | * @brief Returns the keycode for the given key 194 | * 195 | * @param key Key value as string 196 | * @return Key code if possible 197 | */ 198 | uint16_t getKeycode(char16_t key) 199 | { 200 | Serial.print("Keycode"); 201 | uint16_t specialKeyCode = isSpecialKey(key); 202 | 203 | Serial.println(specialKeyCode); 204 | // Check if special key is in the map 205 | if (specialKeyCode != 0) 206 | { 207 | return specialKeyCode; 208 | } 209 | // No special key use the normal layout 210 | else 211 | { 212 | if (key < 128) 213 | { 214 | return KeyboardLayout_pt_PT[key]; 215 | } 216 | // Could not match code 217 | return 0; 218 | } 219 | } 220 | 221 | uint16_t isSpecialKey(char16_t key) 222 | { 223 | uint16_t keycode = 0; 224 | for (int i = 0; i < AMOUNT_OF_SPECIAL_CHARS; i++) 225 | { 226 | Serial.print("Searching key: "); 227 | Serial.println(key); 228 | Serial.print("Comparing with list: "); 229 | Serial.println((char16_t)KeyboardLayout_pt_PT_special_characters[i]); 230 | 231 | if (key == KeyboardLayout_pt_PT_special_characters[i]) 232 | { 233 | Serial.println("Compare keys"); 234 | Serial.println(key); 235 | Serial.println((char16_t)KeyboardLayout_pt_PT_special_characters[i]); 236 | Serial.println((char)key); 237 | Serial.println((char)KeyboardLayout_pt_PT_special_characters[i]); 238 | 239 | 240 | keycode = KeyboardLayout_pt_PT_special_keycodes[i]; 241 | Serial.println(keycode); 242 | break; 243 | } 244 | } 245 | return keycode; 246 | } 247 | 248 | protected: 249 | }; 250 | 251 | //#endif 252 | //#endif 253 | -------------------------------------------------------------------------------- /src/Keyboard-Layouts/KeyboardLayout_BE.h: -------------------------------------------------------------------------------- 1 | /* 2 | * French-Belgian keyboard layout. 3 | */ 4 | 5 | #include "KeyboardLayout.h" 6 | 7 | #pragma once 8 | 9 | //================================================================================ 10 | //================================================================================ 11 | // Keyboard 12 | 13 | // fr_BE keys ?? 14 | #define KEY_SUPERSCRIPT_TWO (136+0x35) 15 | #define KEY_E_ACUTE (136+0x1f) 16 | #define KEY_E_GRAVE (136+0x24) 17 | #define KEY_C_CEDILLA (136+0x26) 18 | #define KEY_A_GRAVE (136+0x27) 19 | #define KEY_U_GRAVE (136+0x34) 20 | #define KEY_SECTION (136+0x23) 21 | #define KEY_MICRO (136+0x31) 22 | #define KEY_EURO (136+0x08) 23 | 24 | #define AMOUNT_OF_SPECIAL_CHARS 11 25 | 26 | extern const char16_t KeyboardLayout_fr_BE_special_characters[AMOUNT_OF_SPECIAL_CHARS] PROGMEM = { 27 | u'²', 28 | u'³', 29 | u'é', 30 | u'è', 31 | u'ç', 32 | u'à', 33 | u'ù', 34 | u'§', 35 | u'µ', 36 | u'£', 37 | u'€', 38 | }; 39 | 40 | extern const uint16_t KeyboardLayout_fr_BE_special_keycodes[AMOUNT_OF_SPECIAL_CHARS] PROGMEM = { 41 | KEY_SUPERSCRIPT_TWO, 42 | KEY_SUPERSCRIPT_TWO | U16SHIFT, 43 | KEY_E_ACUTE, 44 | KEY_E_GRAVE, 45 | KEY_C_CEDILLA, 46 | KEY_A_GRAVE, 47 | KEY_U_GRAVE, 48 | KEY_SECTION, 49 | KEY_MICRO, 50 | KEY_MICRO | U16SHIFT, 51 | KEY_EURO | U16SHIFT, 52 | }; 53 | 54 | extern const uint8_t KeyboardLayout_fr_BE[128] PROGMEM = 55 | { 56 | 0x00, // NUL 57 | 0x00, // SOH 58 | 0x00, // STX 59 | 0x00, // ETX 60 | 0x00, // EOT 61 | 0x00, // ENQ 62 | 0x00, // ACK 63 | 0x00, // BEL 64 | 0x2a, // BS Backspace 65 | 0x2b, // TAB Tab 66 | 0x28, // LF Enter 67 | 0x00, // VT 68 | 0x00, // FF 69 | 0x00, // CR 70 | 0x00, // SO 71 | 0x00, // SI 72 | 0x00, // DEL 73 | 0x00, // DC1 74 | 0x00, // DC2 75 | 0x00, // DC3 76 | 0x00, // DC4 77 | 0x00, // NAK 78 | 0x00, // SYN 79 | 0x00, // ETB 80 | 0x00, // CAN 81 | 0x00, // EM 82 | 0x00, // SUB 83 | 0x00, // ESC 84 | 0x00, // FS 85 | 0x00, // GS 86 | 0x00, // RS 87 | 0x00, // US 88 | 89 | 0x2c, // ' ' 90 | 0x25, // ! 91 | 0x20, // " 92 | 0x20|ALT_GR, // # 93 | 0x30, // $ 94 | 0x34|SHIFT, // % 95 | 0x1E, // & 96 | 0x21, // ' 97 | 0x22, // ( 98 | 0x2d, // ) 99 | 0x30|SHIFT, // * 100 | 0x38|SHIFT, // + 101 | 0x10, // , 102 | 0x2e, // - 103 | 0x36|SHIFT, // . 104 | 0x37|SHIFT, // / 105 | 0x27|SHIFT, // 0 106 | 0x1e|SHIFT, // 1 107 | 0x1f|SHIFT, // 2 108 | 0x20|SHIFT, // 3 109 | 0x21|SHIFT, // 4 110 | 0x22|SHIFT, // 5 111 | 0x23|SHIFT, // 6 112 | 0x24|SHIFT, // 7 113 | 0x25|SHIFT, // 8 114 | 0x26|SHIFT, // 9 115 | 0x37, // : 116 | 0x36, // ; 117 | 0x32, // < 118 | 0x38, // = 119 | 0x32|SHIFT, // > 120 | 0x10|SHIFT, // ? 121 | 0x1f|ALT_GR, // @ 122 | 0x14|SHIFT, // A 123 | 0x05|SHIFT, // B 124 | 0x06|SHIFT, // C 125 | 0x07|SHIFT, // D 126 | 0x08|SHIFT, // E 127 | 0x09|SHIFT, // F 128 | 0x0a|SHIFT, // G 129 | 0x0b|SHIFT, // H 130 | 0x0c|SHIFT, // I 131 | 0x0d|SHIFT, // J 132 | 0x0e|SHIFT, // K 133 | 0x0f|SHIFT, // L 134 | 0x33|SHIFT, // M 135 | 0x11|SHIFT, // N 136 | 0x12|SHIFT, // O 137 | 0x13|SHIFT, // P 138 | 0x04|SHIFT, // Q 139 | 0x15|SHIFT, // R 140 | 0x16|SHIFT, // S 141 | 0x17|SHIFT, // T 142 | 0x18|SHIFT, // U 143 | 0x19|SHIFT, // V 144 | 0x1d|SHIFT, // W 145 | 0x1b|SHIFT, // X 146 | 0x1c|SHIFT, // Y 147 | 0x1a|SHIFT, // Z 148 | 0x2f|ALT_GR, // [ 149 | 0x32|ALT_GR, // bslash 150 | 0x30|ALT_GR, // ] 151 | 0x23|ALT_GR, // ^ 152 | 0x2e|SHIFT, // _ 153 | 0x31|ALT_GR, // ` 154 | 0x14, // a 155 | 0x05, // b 156 | 0x06, // c 157 | 0x07, // d 158 | 0x08, // e 159 | 0x09, // f 160 | 0x0a, // g 161 | 0x0b, // h 162 | 0x0c, // i 163 | 0x0d, // j 164 | 0x0e, // k 165 | 0x0f, // l 166 | 0x33, // m 167 | 0x11, // n 168 | 0x12, // o 169 | 0x13, // p 170 | 0x04, // q 171 | 0x15, // r 172 | 0x16, // s 173 | 0x17, // t 174 | 0x18, // u 175 | 0x19, // v 176 | 0x1d, // w 177 | 0x1b, // x 178 | 0x1c, // y 179 | 0x1a, // z 180 | 0x26|ALT_GR, // { 181 | 0x1e|ALT_GR, // | 182 | 0x27|ALT_GR, // } 183 | 0x38|ALT_GR, // ~ 184 | 0x00 // DEL 185 | }; 186 | 187 | class KeyboardLayout_BE : public KeyboardLayout 188 | { 189 | public: 190 | KeyboardLayout_BE() 191 | { 192 | } 193 | ~KeyboardLayout_BE(){}; 194 | const uint8_t *getKeymap() 195 | { 196 | return KeyboardLayout_fr_BE; 197 | } 198 | /** 199 | * @brief Returns the keycode for the given key 200 | * 201 | * @param key Key value as string 202 | * @return Key code if possible 203 | */ 204 | uint16_t getKeycode(char16_t key) 205 | { 206 | Serial.print("Keycode"); 207 | uint16_t specialKeyCode = isSpecialKey(key); 208 | 209 | Serial.println(specialKeyCode); 210 | // Check if special key is in the map 211 | if (specialKeyCode != 0) 212 | { 213 | return specialKeyCode; 214 | } 215 | // No special key use the normal layout 216 | else 217 | { 218 | if (key < 128) 219 | { 220 | return KeyboardLayout_fr_BE[key]; 221 | } 222 | // Could not match code 223 | return 0; 224 | } 225 | } 226 | 227 | uint16_t isSpecialKey(char16_t key) 228 | { 229 | uint16_t keycode = 0; 230 | for (int i = 0; i < AMOUNT_OF_SPECIAL_CHARS; i++) 231 | { 232 | Serial.print("Searching key: "); 233 | Serial.println(key); 234 | Serial.print("Comparing with list: "); 235 | Serial.println((char16_t)KeyboardLayout_fr_BE_special_characters[i]); 236 | 237 | if (key == KeyboardLayout_fr_BE_special_characters[i]) 238 | { 239 | Serial.println("Compare keys"); 240 | Serial.println(key); 241 | Serial.println((char16_t)KeyboardLayout_fr_BE_special_characters[i]); 242 | Serial.println((char)key); 243 | Serial.println((char)KeyboardLayout_fr_BE_special_characters[i]); 244 | 245 | 246 | keycode = KeyboardLayout_fr_BE_special_keycodes[i]; 247 | Serial.println(keycode); 248 | break; 249 | } 250 | } 251 | return keycode; 252 | } 253 | 254 | protected: 255 | }; 256 | 257 | //#endif 258 | //#endif 259 | -------------------------------------------------------------------------------- /src/Keyboard-Layouts/KeyboardLayout_DK.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Danish keyboard layout. 3 | */ 4 | 5 | #include "KeyboardLayout.h" 6 | 7 | #pragma once 8 | 9 | // //================================================================================ 10 | // //================================================================================ 11 | // // Keyboard 12 | 13 | // DA_DK keys 14 | #define KEY_A_RING (136+0x2f) 15 | #define KEY_SLASHED_O (136+0x34) 16 | #define KEY_ASH (136+0x33) 17 | #define KEY_UMLAUT (136+0x30) 18 | #define KEY_ACUTE_ACC (136+0x2e) 19 | #define KEY_HALF (136+0x35) 20 | #define KEY_FOUR (136+0x21) 21 | 22 | #define AMOUNT_OF_SPECIAL_CHARS 14 23 | 24 | extern const char16_t KeyboardLayout_da_DK_special_characters[AMOUNT_OF_SPECIAL_CHARS] PROGMEM = 25 | { 26 | u'å', 27 | u'ø', 28 | u'æ', 29 | u'¨', 30 | u'´', 31 | u'½', 32 | u'¤', 33 | u'Å', 34 | u'Ø', 35 | u'Æ', 36 | u'^', 37 | u'~', 38 | u'`', 39 | u'§' 40 | }; 41 | 42 | extern const uint16_t KeyboardLayout_da_DK_special_keycodes[AMOUNT_OF_SPECIAL_CHARS] PROGMEM = 43 | { 44 | KEY_A_RING, 45 | KEY_SLASHED_O, 46 | KEY_ASH, 47 | KEY_UMLAUT, 48 | KEY_ACUTE_ACC, 49 | KEY_HALF, 50 | KEY_FOUR | ALT_GR, 51 | KEY_A_RING | U16SHIFT, 52 | KEY_SLASHED_O | U16SHIFT, 53 | KEY_ASH | U16SHIFT, 54 | KEY_UMLAUT | U16SHIFT, 55 | KEY_UMLAUT | ALT_GR, 56 | KEY_ACUTE_ACC | U16SHIFT, 57 | KEY_HALF | U16SHIFT 58 | }; 59 | 60 | extern const uint8_t KeyboardLayout_da_DK[128] PROGMEM = 61 | { 62 | 0x00, // NUL 63 | 0x00, // SOH 64 | 0x00, // STX 65 | 0x00, // ETX 66 | 0x00, // EOT 67 | 0x00, // ENQ 68 | 0x00, // ACK 69 | 0x00, // BEL 70 | 0x2a, // BS Backspace 71 | 0x2b, // TAB Tab 72 | 0x28, // LF Enter 73 | 0x00, // VT 74 | 0x00, // FF 75 | 0x00, // CR 76 | 0x00, // SO 77 | 0x00, // SI 78 | 0x00, // DEL 79 | 0x00, // DC1 80 | 0x00, // DC2 81 | 0x00, // DC3 82 | 0x00, // DC4 83 | 0x00, // NAK 84 | 0x00, // SYN 85 | 0x00, // ETB 86 | 0x00, // CAN 87 | 0x00, // EM 88 | 0x00, // SUB 89 | 0x00, // ESC 90 | 0x00, // FS 91 | 0x00, // GS 92 | 0x00, // RS 93 | 0x00, // US 94 | 95 | 0x2c, // ' ' 96 | 0x1e|SHIFT, // ! 97 | 0x1f|SHIFT, // " 98 | 0x20|SHIFT, // # 99 | 0x21|ALT_GR, // $ 100 | 0x22|SHIFT, // % 101 | 0x23|SHIFT, // & 102 | 0x31, // ' 103 | 0x25|SHIFT, // ( 104 | 0x26|SHIFT, // ) 105 | 0x31|SHIFT, // * 106 | 0x2d, // + 107 | 0x36, // , 108 | 0x38, // - 109 | 0x37, // . 110 | 0x24|SHIFT, // / 111 | 0x27, // 0 112 | 0x1e, // 1 113 | 0x1f, // 2 114 | 0x20, // 3 115 | 0x21, // 4 116 | 0x22, // 5 117 | 0x23, // 6 118 | 0x24, // 7 119 | 0x25, // 8 120 | 0x26, // 9 121 | 0x37|SHIFT, // : 122 | 0x36|SHIFT, // ; 123 | 0x32, // < 124 | 0x27|SHIFT, // = 125 | 0x32|SHIFT, // > 126 | 0x2d|SHIFT, // ? 127 | 0x1f|ALT_GR, // @ 128 | 0x04|SHIFT, // A 129 | 0x05|SHIFT, // B 130 | 0x06|SHIFT, // C 131 | 0x07|SHIFT, // D 132 | 0x08|SHIFT, // E 133 | 0x09|SHIFT, // F 134 | 0x0a|SHIFT, // G 135 | 0x0b|SHIFT, // H 136 | 0x0c|SHIFT, // I 137 | 0x0d|SHIFT, // J 138 | 0x0e|SHIFT, // K 139 | 0x0f|SHIFT, // L 140 | 0x10|SHIFT, // M 141 | 0x11|SHIFT, // N 142 | 0x12|SHIFT, // O 143 | 0x13|SHIFT, // P 144 | 0x14|SHIFT, // Q 145 | 0x15|SHIFT, // R 146 | 0x16|SHIFT, // S 147 | 0x17|SHIFT, // T 148 | 0x18|SHIFT, // U 149 | 0x19|SHIFT, // V 150 | 0x1a|SHIFT, // W 151 | 0x1b|SHIFT, // X 152 | 0x1c|SHIFT, // Y 153 | 0x1d|SHIFT, // Z 154 | 0x25|ALT_GR, // [ 155 | 0x32|ALT_GR, // bslash 156 | 0x26|ALT_GR, // ] 157 | 0x00, // ^ not supported (requires dead key + space) 158 | 0x38|SHIFT, // _ 159 | 0x00, // ` not supported (requires dead key + space) 160 | 0x04, // a 161 | 0x05, // b 162 | 0x06, // c 163 | 0x07, // d 164 | 0x08, // e 165 | 0x09, // f 166 | 0x0a, // g 167 | 0x0b, // h 168 | 0x0c, // i 169 | 0x0d, // j 170 | 0x0e, // k 171 | 0x0f, // l 172 | 0x10, // m 173 | 0x11, // n 174 | 0x12, // o 175 | 0x13, // p 176 | 0x14, // q 177 | 0x15, // r 178 | 0x16, // s 179 | 0x17, // t 180 | 0x18, // u 181 | 0x19, // v 182 | 0x1a, // w 183 | 0x1b, // x 184 | 0x1c, // y 185 | 0x1d, // z 186 | 0x24|ALT_GR, // { 187 | 0x2e|ALT_GR, // | 188 | 0x27|ALT_GR, // } 189 | 0x00, // ~ not supported (requires dead key + space) 190 | 0x00 // DEL 191 | }; 192 | 193 | class KeyboardLayout_DK : public KeyboardLayout 194 | { 195 | public: 196 | KeyboardLayout_DK() 197 | { 198 | } 199 | ~KeyboardLayout_DK(){}; 200 | const uint8_t *getKeymap() 201 | { 202 | return KeyboardLayout_da_DK; 203 | } 204 | /** 205 | * @brief Returns the keycode for the given key 206 | * 207 | * @param key Key value as string 208 | * @return Key code if possible 209 | */ 210 | uint16_t getKeycode(char16_t key) 211 | { 212 | Serial.print("Keycode"); 213 | uint16_t specialKeyCode = isSpecialKey(key); 214 | 215 | Serial.println(specialKeyCode); 216 | // Check if special key is in the map 217 | if (specialKeyCode != 0) 218 | { 219 | return specialKeyCode; 220 | } 221 | // No special key use the normal layout 222 | else 223 | { 224 | if (key < 128) 225 | { 226 | return KeyboardLayout_da_DK[key]; 227 | } 228 | // Could not match code 229 | return 0; 230 | } 231 | } 232 | 233 | uint16_t isSpecialKey(char16_t key) 234 | { 235 | uint16_t keycode = 0; 236 | for (int i = 0; i < AMOUNT_OF_SPECIAL_CHARS; i++) 237 | { 238 | Serial.print("Searching key: "); 239 | Serial.println(key); 240 | Serial.print("Comparing with list: "); 241 | Serial.println((char16_t)KeyboardLayout_da_DK_special_characters[i]); 242 | 243 | if (key == KeyboardLayout_da_DK_special_characters[i]) 244 | { 245 | Serial.println("Compare keys"); 246 | Serial.println(key); 247 | Serial.println((char16_t)KeyboardLayout_da_DK_special_characters[i]); 248 | Serial.println((char)key); 249 | Serial.println((char)KeyboardLayout_da_DK_special_characters[i]); 250 | 251 | 252 | keycode = KeyboardLayout_da_DK_special_keycodes[i]; 253 | Serial.println(keycode); 254 | break; 255 | } 256 | } 257 | return keycode; 258 | } 259 | 260 | protected: 261 | }; 262 | -------------------------------------------------------------------------------- /src/Keyboard-Layouts/KeyboardLayout_HU.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Hungarian keyboard layout. 3 | */ 4 | 5 | #include "KeyboardLayout.h" 6 | 7 | #pragma once 8 | 9 | //================================================================================ 10 | //================================================================================ 11 | // Keyboard 12 | 13 | // hu_HU keys 14 | #define KEY_O_ACUTE (136+0x2e) 15 | #define KEY_O_UMLAUT (136+0x27) 16 | #define KEY_O_DOUBLE_ACUTE (136+0x2f) 17 | 18 | #define KEY_U_ACUTE (136+0x30) 19 | #define KEY_U_UMLAUT (136+0x2d) 20 | #define KEY_U_DOUBLE_ACUTE (136+0x31) 21 | 22 | #define KEY_A_ACUTE (136+0x34) 23 | 24 | #define KEY_E_ACUTE (136+0x33) 25 | 26 | #define KEY_I_ACUTE (136+0x32) 27 | #define KEY_TWO (136+0x1f) 28 | #define KEY_THREE (136+0x20) 29 | #define KEY_FOUR (136+0x21) 30 | #define KEY_FIVE (136+0x22) 31 | #define KEY_SIX (136+0x23) 32 | #define KEY_EIGHT (136+0x25) 33 | #define KEY_NINE (136+0x26) 34 | 35 | #define AMOUNT_OF_SPECIAL_CHARS 30 36 | 37 | extern const char16_t KeyboardLayout_hu_HU_special_characters[AMOUNT_OF_SPECIAL_CHARS] PROGMEM = { 38 | u'ó', 39 | u'ö', 40 | u'ő', 41 | u'ú', 42 | u'ü', 43 | u'ű', 44 | u'á', 45 | u'é', 46 | u'í', 47 | u'Ó', 48 | u'Ö', 49 | u'Ő', 50 | u'Ú', 51 | u'Ü', 52 | u'Ű', 53 | u'Á', 54 | u'É', 55 | u'Í', 56 | u'ˇ', 57 | u'^', 58 | u'˘', 59 | u'°', 60 | u'˛', 61 | u'˙', 62 | u'´', 63 | u'˝', 64 | u'¨', 65 | u'¸', 66 | u'ß', 67 | u'¤' 68 | }; 69 | 70 | extern const uint16_t KeyboardLayout_hu_HU_special_keycodes[AMOUNT_OF_SPECIAL_CHARS] PROGMEM = { 71 | KEY_O_ACUTE, 72 | KEY_O_UMLAUT, 73 | KEY_O_DOUBLE_ACUTE, 74 | KEY_U_ACUTE, 75 | KEY_U_UMLAUT, 76 | KEY_U_DOUBLE_ACUTE, 77 | KEY_A_ACUTE, 78 | KEY_E_ACUTE, 79 | KEY_I_ACUTE, 80 | KEY_O_ACUTE | U16SHIFT, 81 | KEY_O_UMLAUT | U16SHIFT, 82 | KEY_O_DOUBLE_ACUTE | U16SHIFT, 83 | KEY_U_ACUTE | U16SHIFT, 84 | KEY_U_UMLAUT | U16SHIFT, 85 | KEY_U_DOUBLE_ACUTE | U16SHIFT, 86 | KEY_A_ACUTE | U16SHIFT, 87 | KEY_E_ACUTE | U16SHIFT, 88 | KEY_I_ACUTE | U16SHIFT, 89 | KEY_TWO | ALT_GR, 90 | KEY_THREE | ALT_GR, 91 | KEY_FOUR | ALT_GR, 92 | KEY_FIVE | ALT_GR, 93 | KEY_SIX | ALT_GR, 94 | KEY_EIGHT | ALT_GR, 95 | KEY_NINE | ALT_GR, 96 | KEY_O_UMLAUT | U16SHIFT, 97 | KEY_U_UMLAUT | U16SHIFT, 98 | KEY_O_ACUTE | U16SHIFT, 99 | KEY_A_ACUTE | ALT_GR, 100 | KEY_U_DOUBLE_ACUTE | ALT_GR 101 | }; 102 | 103 | extern const uint8_t KeyboardLayout_hu_HU[128] PROGMEM = 104 | { 105 | 0x00, // NUL 106 | 0x00, // SOH 107 | 0x00, // STX 108 | 0x00, // ETX 109 | 0x00, // EOT 110 | 0x00, // ENQ 111 | 0x00, // ACK 112 | 0x00, // BEL 113 | 0x2a, // BS Backspace 114 | 0x2b, // TAB Tab 115 | 0x28, // LF Enter 116 | 0x00, // VT 117 | 0x00, // FF 118 | 0x00, // CR 119 | 0x00, // SO 120 | 0x00, // SI 121 | 0x00, // DEL 122 | 0x00, // DC1 123 | 0x00, // DC2 124 | 0x00, // DC3 125 | 0x00, // DC4 126 | 0x00, // NAK 127 | 0x00, // SYN 128 | 0x00, // ETB 129 | 0x00, // CAN 130 | 0x00, // EM 131 | 0x00, // SUB 132 | 0x00, // ESC 133 | 0x00, // FS 134 | 0x00, // GS 135 | 0x00, // RS 136 | 0x00, // US 137 | 138 | 0x2c, // ' ' 139 | 0x21|SHIFT, // ! 140 | 0x1f|SHIFT, // " 141 | 0x1b|ALT_GR, // # 142 | 0x33|ALT_GR, // $ 143 | 0x22|SHIFT, // % 144 | 0x06|ALT_GR, // & 145 | 0x1e|SHIFT, // ' 146 | 0x25|SHIFT, // ( 147 | 0x26|SHIFT, // ) 148 | 0x38|ALT_GR, // * 149 | 0x20|SHIFT, // + 150 | 0x36, // , 151 | 0x38, // - 152 | 0x37, // . 153 | 0x23|SHIFT, // / 154 | 155 | 0x35, // 0 156 | 0x1e, // 1 157 | 0x1f, // 2 158 | 0x20, // 3 159 | 0x21, // 4 160 | 0x22, // 5 161 | 0x23, // 6 162 | 0x24, // 7 163 | 0x25, // 8 164 | 0x26, // 9 165 | 166 | 0x37|SHIFT, // : 167 | 0x36|ALT_GR, // ; 168 | 0x32|ALT_GR, // < 169 | 0x24|SHIFT, // = 170 | 0x1d|ALT_GR, // > 171 | 0x36|SHIFT, // ? 172 | 0x19|ALT_GR, // @ 173 | 174 | 0x04|SHIFT, // A 175 | 0x05|SHIFT, // B 176 | 0x06|SHIFT, // C 177 | 0x07|SHIFT, // D 178 | 0x08|SHIFT, // E 179 | 0x09|SHIFT, // F 180 | 0x0a|SHIFT, // G 181 | 0x0b|SHIFT, // H 182 | 0x0c|SHIFT, // I 183 | 0x0d|SHIFT, // J 184 | 0x0e|SHIFT, // K 185 | 0x0f|SHIFT, // L 186 | 0x10|SHIFT, // M 187 | 0x11|SHIFT, // N 188 | 0x12|SHIFT, // O 189 | 0x13|SHIFT, // P 190 | 0x14|SHIFT, // Q 191 | 0x15|SHIFT, // R 192 | 0x16|SHIFT, // S 193 | 0x17|SHIFT, // T 194 | 0x18|SHIFT, // U 195 | 0x19|SHIFT, // V 196 | 0x1a|SHIFT, // W 197 | 0x1b|SHIFT, // X 198 | 0x1d|SHIFT, // Y 199 | 0x1c|SHIFT, // Z 200 | 201 | 0x09|ALT_GR, // [ 202 | 0x14|ALT_GR, // bslash 203 | 0x0a|ALT_GR, // ] 204 | 0x20|ALT_GR, // ^ 205 | 0x38|SHIFT, // _ 206 | 0x24|ALT_GR, // ` 207 | 208 | 0x04, // a 209 | 0x05, // b 210 | 0x06, // c 211 | 0x07, // d 212 | 0x08, // e 213 | 0x09, // f 214 | 0x0a, // g 215 | 0x0b, // h 216 | 0x0c, // i 217 | 0x0d, // j 218 | 0x0e, // k 219 | 0x0f, // l 220 | 0x10, // m 221 | 0x11, // n 222 | 0x12, // o 223 | 0x13, // p 224 | 0x14, // q 225 | 0x15, // r 226 | 0x16, // s 227 | 0x17, // t 228 | 0x18, // u 229 | 0x19, // v 230 | 0x1a, // w 231 | 0x1b, // x 232 | 0x1d, // y 233 | 0x1c, // z 234 | 235 | 0x05|ALT_GR, // { 236 | 0x1a|ALT_GR, // | 237 | 0x11|ALT_GR, // } 238 | 0x1e|ALT_GR, // ~ 239 | 0x00 // DEL 240 | }; 241 | 242 | class KeyboardLayout_HU : public KeyboardLayout 243 | { 244 | public: 245 | KeyboardLayout_HU() 246 | { 247 | } 248 | ~KeyboardLayout_HU(){}; 249 | const uint8_t *getKeymap() 250 | { 251 | return KeyboardLayout_hu_HU; 252 | } 253 | /** 254 | * @brief Returns the keycode for the given key 255 | * 256 | * @param key Key value as string 257 | * @return Key code if possible 258 | */ 259 | uint16_t getKeycode(char16_t key) 260 | { 261 | Serial.print("Keycode"); 262 | uint16_t specialKeyCode = isSpecialKey(key); 263 | 264 | Serial.println(specialKeyCode); 265 | // Check if special key is in the map 266 | if (specialKeyCode != 0) 267 | { 268 | return specialKeyCode; 269 | } 270 | // No special key use the normal layout 271 | else 272 | { 273 | if (key < 128) 274 | { 275 | return KeyboardLayout_hu_HU[key]; 276 | } 277 | // Could not match code 278 | return 0; 279 | } 280 | } 281 | 282 | uint16_t isSpecialKey(char16_t key) 283 | { 284 | uint16_t keycode = 0; 285 | for (int i = 0; i < AMOUNT_OF_SPECIAL_CHARS; i++) 286 | { 287 | Serial.print("Searching key: "); 288 | Serial.println(key); 289 | Serial.print("Comparing with list: "); 290 | Serial.println((char16_t)KeyboardLayout_hu_HU_special_characters[i]); 291 | 292 | if (key == KeyboardLayout_hu_HU_special_characters[i]) 293 | { 294 | Serial.println("Compare keys"); 295 | Serial.println(key); 296 | Serial.println((char16_t)KeyboardLayout_hu_HU_special_characters[i]); 297 | Serial.println((char)key); 298 | Serial.println((char)KeyboardLayout_hu_HU_special_characters[i]); 299 | 300 | 301 | keycode = KeyboardLayout_hu_HU_special_keycodes[i]; 302 | Serial.println(keycode); 303 | break; 304 | } 305 | } 306 | return keycode; 307 | } 308 | 309 | protected: 310 | }; 311 | -------------------------------------------------------------------------------- /src/Unicode/unicode.cpp: -------------------------------------------------------------------------------- 1 | // From gist: https://gist.github.com/tommai78101/3631ed1f136b78238e85582f08bdc618 2 | 3 | /* 4 | MIT License 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | #include "Arduino.h" 26 | #include "unicode.h" 27 | 28 | #define __STD_UTF_16__ 29 | 30 | //Pointer arrays must always include the array size, because pointers do not know about the size of the supposed array size. 31 | void utf8_to_utf16(unsigned char* const utf8_str, int utf8_str_size, char16_t* utf16_str_output, int utf16_str_output_size) { 32 | //First, grab the first byte of the UTF-8 string 33 | unsigned char* utf8_currentCodeUnit = utf8_str; 34 | char16_t* utf16_currentCodeUnit = utf16_str_output; 35 | int utf8_str_iterator = 0; 36 | int utf16_str_iterator = 0; 37 | 38 | //In a while loop, we check if the UTF-16 iterator is less than the max output size. If true, then we check if UTF-8 iterator 39 | //is less than UTF-8 max string size. This conditional checking based on order of precedence is intentionally done so it 40 | //prevents the while loop from continuing onwards if the iterators are outside of the intended sizes. 41 | while (*utf8_currentCodeUnit && (utf16_str_iterator < utf16_str_output_size || utf8_str_iterator < utf8_str_size)) { 42 | //Figure out the current code unit to determine the range. It is split into 6 main groups, each of which handles the data 43 | //differently from one another. 44 | if (*utf8_currentCodeUnit < 0x80) { 45 | //0..127, the ASCII range. 46 | 47 | //We directly plug in the values to the UTF-16 code unit. 48 | *utf16_currentCodeUnit = (char16_t) (*utf8_currentCodeUnit); 49 | utf16_currentCodeUnit++; 50 | utf16_str_iterator++; 51 | 52 | //Increment the current code unit pointer to the next code unit 53 | utf8_currentCodeUnit++; 54 | 55 | //Increment the iterator to keep track of where we are in the UTF-8 string 56 | utf8_str_iterator++; 57 | } 58 | else if (*utf8_currentCodeUnit < 0xC0) { 59 | //0x80..0xBF, we ignore. These are reserved for UTF-8 encoding. 60 | utf8_currentCodeUnit++; 61 | utf8_str_iterator++; 62 | } 63 | else if (*utf8_currentCodeUnit < 0xE0) { 64 | //128..2047, the extended ASCII range, and into the Basic Multilingual Plane. 65 | 66 | //Work on the first code unit. 67 | char16_t highShort = (char16_t) ((*utf8_currentCodeUnit) & 0x1F); 68 | 69 | //Increment the current code unit pointer to the next code unit 70 | utf8_currentCodeUnit++; 71 | 72 | //Work on the second code unit. 73 | char16_t lowShort = (char16_t) ((*utf8_currentCodeUnit) & 0x3F); 74 | 75 | //Increment the current code unit pointer to the next code unit 76 | utf8_currentCodeUnit++; 77 | 78 | //Create the UTF-16 code unit, then increment the iterator. 79 | //Credits to @tbeu. 80 | //Thanks to @k6l2 for explaining why we need 6 instead of 8. 81 | //It's because 0x3F is 6 bits of information from the low short. By shifting 8 bits, you are 82 | //adding 2 extra zeroes in between the actual data of both shorts. 83 | int unicode = (highShort << 6) | lowShort; 84 | 85 | //Check to make sure the "unicode" is in the range [0..D7FF] and [E000..FFFF]. 86 | if ((0 <= unicode && unicode <= 0xD7FF) || (0xE000 <= unicode && unicode <= 0xFFFF)) { 87 | //Directly set the value to the UTF-16 code unit. 88 | *utf16_currentCodeUnit = (char16_t) unicode; 89 | utf16_currentCodeUnit++; 90 | utf16_str_iterator++; 91 | } 92 | 93 | //Increment the iterator to keep track of where we are in the UTF-8 string 94 | utf8_str_iterator += 2; 95 | } 96 | else if (*utf8_currentCodeUnit < 0xF0) { 97 | //2048..65535, the remaining Basic Multilingual Plane. 98 | 99 | //Work on the UTF-8 code units one by one. 100 | //If drawn out, it would be 1110aaaa 10bbbbcc 10ccdddd 101 | //Where a is 4th byte, b is 3rd byte, c is 2nd byte, and d is 1st byte. 102 | char16_t fourthChar = (char16_t) ((*utf8_currentCodeUnit) & 0xF); 103 | utf8_currentCodeUnit++; 104 | char16_t thirdChar = (char16_t) ((*utf8_currentCodeUnit) & 0x3C) >> 2; 105 | char16_t secondCharHigh = (char16_t) ((*utf8_currentCodeUnit) & 0x3); 106 | utf8_currentCodeUnit++; 107 | char16_t secondCharLow = (char16_t) ((*utf8_currentCodeUnit) & 0x30) >> 4; 108 | char16_t firstChar = (char16_t) ((*utf8_currentCodeUnit) & 0xF); 109 | utf8_currentCodeUnit++; 110 | 111 | //Create the resulting UTF-16 code unit, then increment the iterator. 112 | int unicode = (fourthChar << 12) | (thirdChar << 8) | (secondCharHigh << 6) | (secondCharLow << 4) | firstChar; 113 | 114 | //Check to make sure the "unicode" is in the range [0..D7FF] and [E000..FFFF]. 115 | //According to math, UTF-8 encoded "unicode" should always fall within these two ranges. 116 | if ((0 <= unicode && unicode <= 0xD7FF) || (0xE000 <= unicode && unicode <= 0xFFFF)) { 117 | //Directly set the value to the UTF-16 code unit. 118 | *utf16_currentCodeUnit = (char16_t) unicode; 119 | utf16_currentCodeUnit++; 120 | utf16_str_iterator++; 121 | } 122 | 123 | //Increment the iterator to keep track of where we are in the UTF-8 string 124 | utf8_str_iterator += 3; 125 | } 126 | else if (*utf8_currentCodeUnit < 0xF8) { 127 | //65536..10FFFF, the Unicode UTF range 128 | 129 | //Work on the UTF-8 code units one by one. 130 | //If drawn out, it would be 11110abb 10bbcccc 10ddddee 10eeffff 131 | //Where a is 6th byte, b is 5th byte, c is 4th byte, and so on. 132 | char16_t sixthChar = (char16_t) ((*utf8_currentCodeUnit) & 0x4) >> 2; 133 | char16_t fifthCharHigh = (char16_t) ((*utf8_currentCodeUnit) & 0x3); 134 | utf8_currentCodeUnit++; 135 | char16_t fifthCharLow = (char16_t) ((*utf8_currentCodeUnit) & 0x30) >> 4; 136 | char16_t fourthChar = (char16_t) ((*utf8_currentCodeUnit) & 0xF); 137 | utf8_currentCodeUnit++; 138 | char16_t thirdChar = (char16_t) ((*utf8_currentCodeUnit) & 0x3C) >> 2; 139 | char16_t secondCharHigh = (char16_t) ((*utf8_currentCodeUnit) & 0x3); 140 | utf8_currentCodeUnit++; 141 | char16_t secondCharLow = (char16_t) ((*utf8_currentCodeUnit) & 0x30) >> 4; 142 | char16_t firstChar = (char16_t) ((*utf8_currentCodeUnit) & 0xF); 143 | utf8_currentCodeUnit++; 144 | 145 | int unicode = (sixthChar << 4) | (fifthCharHigh << 2) | fifthCharLow | (fourthChar << 12) | (thirdChar << 8) | (secondCharHigh << 6) | (secondCharLow << 4) | firstChar; 146 | char16_t highSurrogate = (unicode - 0x10000) / 0x400 + 0xD800; 147 | char16_t lowSurrogate = (unicode - 0x10000) % 0x400 + 0xDC00; 148 | 149 | //Set the UTF-16 code units 150 | *utf16_currentCodeUnit = lowSurrogate; 151 | utf16_currentCodeUnit++; 152 | utf16_str_iterator++; 153 | 154 | //Check to see if we're still below the output string size before continuing, otherwise, we cut off here. 155 | if (utf16_str_iterator < utf16_str_output_size) { 156 | *utf16_currentCodeUnit = highSurrogate; 157 | utf16_currentCodeUnit++; 158 | utf16_str_iterator++; 159 | } 160 | 161 | //Increment the iterator to keep track of where we are in the UTF-8 string 162 | utf8_str_iterator += 4; 163 | } 164 | else { 165 | //Invalid UTF-8 code unit, we ignore. 166 | utf8_currentCodeUnit++; 167 | utf8_str_iterator++; 168 | } 169 | } 170 | 171 | //We clean up the output string if the UTF-16 iterator is still less than the output string size. 172 | while (utf16_str_iterator < utf16_str_output_size) { 173 | *utf16_currentCodeUnit = '\0'; 174 | utf16_currentCodeUnit++; 175 | utf16_str_iterator++; 176 | } 177 | }; 178 | -------------------------------------------------------------------------------- /src/USBHID-Keyboard/USBHIDKeyboard.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Keyboard.cpp 3 | 4 | Copyright (c) 2015, Arduino LLC 5 | Original code (pre-library): Copyright (c) 2011, Peter Barrett 6 | 7 | This library is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU Lesser General Public 9 | License as published by the Free Software Foundation; either 10 | version 2.1 of the License, or (at your option) any later version. 11 | 12 | This library is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public 18 | License along with this library; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | #include "USBHID.h" 22 | #if CONFIG_TINYUSB_HID_ENABLED 23 | 24 | #include "USBHIDKeyboard.h" 25 | 26 | ESP_EVENT_DEFINE_BASE(ARDUINO_USB_HID_KEYBOARD_EVENTS); 27 | esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait); 28 | esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg); 29 | 30 | static const uint8_t report_descriptor[] = { 31 | TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(HID_REPORT_ID_KEYBOARD))}; 32 | 33 | USBHIDKeyboard::USBHIDKeyboard() : hid() 34 | { 35 | // Use US Keyboard as default 36 | _asciimap = KeyboardLayout_en_US; 37 | static bool initialized = false; 38 | if (!initialized) 39 | { 40 | initialized = true; 41 | hid.addDevice(this, sizeof(report_descriptor)); 42 | } 43 | } 44 | 45 | uint16_t USBHIDKeyboard::_onGetDescriptor(uint8_t *dst) 46 | { 47 | memcpy(dst, report_descriptor, sizeof(report_descriptor)); 48 | return sizeof(report_descriptor); 49 | } 50 | 51 | void USBHIDKeyboard::begin(KeyboardLayout *layout) 52 | { 53 | if (layout != nullptr) 54 | { 55 | keyboardlayout = layout; 56 | _asciimap = layout->getKeymap(); 57 | } 58 | else 59 | { 60 | layout = new KeyboardLayout_US(); 61 | } 62 | hid.begin(); 63 | } 64 | 65 | void USBHIDKeyboard::end() 66 | { 67 | } 68 | 69 | void USBHIDKeyboard::onEvent(esp_event_handler_t callback) 70 | { 71 | onEvent(ARDUINO_USB_HID_KEYBOARD_ANY_EVENT, callback); 72 | } 73 | void USBHIDKeyboard::onEvent(arduino_usb_hid_keyboard_event_t event, esp_event_handler_t callback) 74 | { 75 | arduino_usb_event_handler_register_with(ARDUINO_USB_HID_KEYBOARD_EVENTS, event, callback, this); 76 | } 77 | 78 | void USBHIDKeyboard::_onOutput(uint8_t report_id, const uint8_t *buffer, uint16_t len) 79 | { 80 | if (report_id == HID_REPORT_ID_KEYBOARD) 81 | { 82 | arduino_usb_hid_keyboard_event_data_t p; 83 | p.leds = buffer[0]; 84 | arduino_usb_event_post(ARDUINO_USB_HID_KEYBOARD_EVENTS, ARDUINO_USB_HID_KEYBOARD_LED_EVENT, &p, sizeof(arduino_usb_hid_keyboard_event_data_t), portMAX_DELAY); 85 | } 86 | } 87 | 88 | void USBHIDKeyboard::sendReport(KeyReport *keys) 89 | { 90 | hid_keyboard_report_t report; 91 | report.reserved = 0; 92 | report.modifier = keys->modifiers; 93 | if (keys->keys) 94 | { 95 | memcpy(report.keycode, keys->keys, 6); 96 | } 97 | else 98 | { 99 | memset(report.keycode, 0, 6); 100 | } 101 | hid.SendReport(HID_REPORT_ID_KEYBOARD, &report, sizeof(report)); 102 | } 103 | 104 | size_t USBHIDKeyboard::pressRaw(uint8_t k) 105 | { 106 | uint8_t i; 107 | if (k >= 0xE0 && k < 0xE8) 108 | { 109 | // it's a modifier key 110 | _keyReport.modifiers |= (1 << (k - 0x80)); 111 | } 112 | else if (k && k < 0xA5) 113 | { 114 | // Add k to the key report only if it's not already present 115 | // and if there is an empty slot. 116 | if (_keyReport.keys[0] != k && _keyReport.keys[1] != k && 117 | _keyReport.keys[2] != k && _keyReport.keys[3] != k && 118 | _keyReport.keys[4] != k && _keyReport.keys[5] != k) 119 | { 120 | 121 | for (i = 0; i < 6; i++) 122 | { 123 | if (_keyReport.keys[i] == 0x00) 124 | { 125 | _keyReport.keys[i] = k; 126 | break; 127 | } 128 | } 129 | if (i == 6) 130 | { 131 | return 0; 132 | } 133 | } 134 | } 135 | else 136 | { 137 | // not a modifier and not a key 138 | return 0; 139 | } 140 | sendReport(&_keyReport); 141 | return 1; 142 | } 143 | 144 | size_t USBHIDKeyboard::releaseRaw(uint8_t k) 145 | { 146 | uint8_t i; 147 | if (k >= 0xE0 && k < 0xE8) 148 | { 149 | // it's a modifier key 150 | _keyReport.modifiers &= ~(1 << (k - 0x80)); 151 | } 152 | else if (k && k < 0xA5) 153 | { 154 | // Test the key report to see if k is present. Clear it if it exists. 155 | // Check all positions in case the key is present more than once (which it shouldn't be) 156 | for (i = 0; i < 6; i++) 157 | { 158 | if (0 != k && _keyReport.keys[i] == k) 159 | { 160 | _keyReport.keys[i] = 0x00; 161 | } 162 | } 163 | } 164 | else 165 | { 166 | // not a modifier and not a key 167 | return 0; 168 | } 169 | 170 | sendReport(&_keyReport); 171 | return 1; 172 | } 173 | 174 | void USBHIDKeyboard::setModifier(uint8_t modifier) 175 | { 176 | _keyReport.modifiers |= modifier; 177 | sendReport(&_keyReport); 178 | } 179 | 180 | void USBHIDKeyboard::unsetModifier(uint8_t modifier) 181 | { 182 | _keyReport.modifiers &= ~(modifier); 183 | sendReport(&_keyReport); 184 | } 185 | 186 | // press() adds the specified key (printing, non-printing, or modifier) 187 | // to the persistent key report and sends the report. Because of the way 188 | // USB HID works, the host acts like the key remains pressed until we 189 | // call release(), releaseAll(), or otherwise clear the report and resend. 190 | size_t USBHIDKeyboard::press(uint8_t k) 191 | { 192 | 193 | if (k >= 0x88) 194 | { // it's a non-printing key (not a modifier) 195 | k = k - 0x88; 196 | } 197 | else if (k >= 0x80) 198 | { // it's a modifier key 199 | _keyReport.modifiers |= (1 << (k - 0x80)); 200 | k = 0; 201 | } 202 | else 203 | { // it's a printing key 204 | 205 | k = _asciimap[k]; 206 | if (!k) 207 | { 208 | return 0; 209 | } 210 | if ((k & ALT_GR) == ALT_GR) 211 | { 212 | _keyReport.modifiers |= 0x40; // AltGr = right Alt 213 | k &= 0x3F; 214 | } 215 | else if ((k & SHIFT) == SHIFT) 216 | { // it's a capital letter or other character reached with shift 217 | _keyReport.modifiers |= 0x02; // the left shift modifier 218 | k &= 0x7F; 219 | } 220 | if (k == ISO_REPLACEMENT) 221 | { 222 | k = ISO_KEY; 223 | } 224 | } 225 | return pressRaw(k); 226 | } 227 | 228 | // release() takes the specified key out of the persistent key report and 229 | // sends the report. This tells the OS the key is no longer pressed and that 230 | // it shouldn't be repeated any more. 231 | size_t USBHIDKeyboard::release(uint8_t k) 232 | { 233 | if (k >= 0x88) 234 | { // it's a non-printing key (not a modifier) 235 | Serial.println("No printing key"); 236 | Serial.println((char)k); 237 | k = k - 0x88; 238 | } 239 | else if (k >= 0x80) 240 | { // it's a modifier key 241 | _keyReport.modifiers &= ~(1 << (k - 0x80)); 242 | k = 0; 243 | } 244 | else 245 | { // it's a printing key 246 | 247 | k = _asciimap[k]; 248 | 249 | if (!k) 250 | { 251 | return 0; 252 | } 253 | if ((k & ALT_GR) == ALT_GR) 254 | { 255 | _keyReport.modifiers &= ~(0x40); // AltGr = right Alt 256 | k &= 0x3F; 257 | } 258 | else if ((k & SHIFT) == SHIFT) 259 | { 260 | _keyReport.modifiers &= ~(0x02); // the left shift modifier 261 | k &= 0x7F; 262 | } 263 | if (k == ISO_REPLACEMENT) 264 | { 265 | k = ISO_KEY; 266 | } 267 | } 268 | return releaseRaw(k); 269 | } 270 | 271 | void USBHIDKeyboard::releaseAll(void) 272 | { 273 | _keyReport.keys[0] = 0; 274 | _keyReport.keys[1] = 0; 275 | _keyReport.keys[2] = 0; 276 | _keyReport.keys[3] = 0; 277 | _keyReport.keys[4] = 0; 278 | _keyReport.keys[5] = 0; 279 | _keyReport.modifiers = 0; 280 | sendReport(&_keyReport); 281 | } 282 | 283 | size_t USBHIDKeyboard::write(uint8_t c) 284 | { 285 | uint8_t p = press(c); // Keydown 286 | release(c); // Keyup 287 | return p; // just return the result of press() since release() almost always returns 1 288 | } 289 | 290 | size_t USBHIDKeyboard::write(const uint8_t *buffer, size_t size) 291 | { 292 | size_t n = 0; 293 | while (size--) 294 | { 295 | if (*buffer != '\r') 296 | { 297 | if (write(*buffer)) 298 | { 299 | n++; 300 | } 301 | else 302 | { 303 | break; 304 | } 305 | } 306 | buffer++; 307 | } 308 | return n; 309 | } 310 | 311 | size_t USBHIDKeyboard::press(uint16_t key) 312 | { 313 | if (key > 0x88) 314 | { 315 | uint16_t keycode = keyboardlayout->isSpecialKey(key); 316 | if (keycode & 0x8000) 317 | { 318 | setModifier(0x02); 319 | keycode = keycode & 0x7FFF; 320 | return press((uint8_t)keycode); 321 | } 322 | else 323 | { 324 | return press((uint8_t)keycode); 325 | } 326 | } 327 | else 328 | { 329 | return press((uint8_t)key); 330 | } 331 | } 332 | size_t USBHIDKeyboard::release(uint16_t key) 333 | { 334 | if (key > 0x88) 335 | { 336 | uint16_t keycode = keyboardlayout->isSpecialKey(key); 337 | if (keycode & 0x8000) 338 | { 339 | keycode = keycode & 0x7FFF; 340 | auto returnval = release((uint8_t)keycode); 341 | unsetModifier(0x02); 342 | return returnval; 343 | } 344 | else 345 | { 346 | return release((uint8_t)keycode); 347 | } 348 | } 349 | else 350 | { 351 | return release((uint8_t)key); 352 | } 353 | } 354 | 355 | size_t USBHIDKeyboard::write(uint16_t k) 356 | { 357 | uint8_t p = press(k); // Keydown 358 | release(k); // Keyup 359 | return p; // just return the result of press() since release() almost always returns 1 360 | } 361 | size_t USBHIDKeyboard::write(const uint16_t *buffer, size_t size) 362 | { 363 | size_t n = 0; 364 | while (size--) 365 | { 366 | if (*buffer != '\r') 367 | { 368 | if (write(*buffer)) 369 | { 370 | n++; 371 | } 372 | else 373 | { 374 | break; 375 | } 376 | } 377 | buffer++; 378 | } 379 | return n; 380 | } 381 | size_t USBHIDKeyboard::write(std::u16string text) 382 | { 383 | for (uint16_t i = 0; i < text.length(); i++) 384 | { 385 | press((uint16_t)text.at(i)); 386 | release((uint16_t)text.at(i)); 387 | } 388 | return text.length(); 389 | } 390 | 391 | #endif /* CONFIG_TINYUSB_HID_ENABLED */ 392 | -------------------------------------------------------------------------------- /src/BLE-Keyboard/BleKeyboard.cpp: -------------------------------------------------------------------------------- 1 | #include "BleKeyboard.h" 2 | 3 | #if defined(USE_NIMBLE) 4 | #include 5 | #include 6 | #include 7 | #include 8 | #else 9 | #include 10 | #include 11 | #include 12 | #include "BLE2902.h" 13 | #include "BLEHIDDevice.h" 14 | #endif // USE_NIMBLE 15 | #include "HIDTypes.h" 16 | #include 17 | #include "sdkconfig.h" 18 | 19 | 20 | #if defined(CONFIG_ARDUHAL_ESP_LOG) 21 | #include "esp32-hal-log.h" 22 | #define LOG_TAG "" 23 | #else 24 | #include "esp_log.h" 25 | static const char* LOG_TAG = "BLEDevice"; 26 | #endif 27 | 28 | 29 | // Report IDs: 30 | #define KEYBOARD_ID 0x01 31 | #define MEDIA_KEYS_ID 0x02 32 | 33 | static const uint8_t _hidReportDescriptor[] = { 34 | USAGE_PAGE(1), 0x01, // USAGE_PAGE (Generic Desktop Ctrls) 35 | USAGE(1), 0x06, // USAGE (Keyboard) 36 | COLLECTION(1), 0x01, // COLLECTION (Application) 37 | // ------------------------------------------------- Keyboard 38 | REPORT_ID(1), KEYBOARD_ID, // REPORT_ID (1) 39 | USAGE_PAGE(1), 0x07, // USAGE_PAGE (Kbrd/Keypad) 40 | USAGE_MINIMUM(1), 0xE0, // USAGE_MINIMUM (0xE0) 41 | USAGE_MAXIMUM(1), 0xE7, // USAGE_MAXIMUM (0xE7) 42 | LOGICAL_MINIMUM(1), 0x00, // LOGICAL_MINIMUM (0) 43 | LOGICAL_MAXIMUM(1), 0x01, // Logical Maximum (1) 44 | REPORT_SIZE(1), 0x01, // REPORT_SIZE (1) 45 | REPORT_COUNT(1), 0x08, // REPORT_COUNT (8) 46 | HIDINPUT(1), 0x02, // INPUT (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 47 | REPORT_COUNT(1), 0x01, // REPORT_COUNT (1) ; 1 byte (Reserved) 48 | REPORT_SIZE(1), 0x08, // REPORT_SIZE (8) 49 | HIDINPUT(1), 0x01, // INPUT (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) 50 | REPORT_COUNT(1), 0x05, // REPORT_COUNT (5) ; 5 bits (Num lock, Caps lock, Scroll lock, Compose, Kana) 51 | REPORT_SIZE(1), 0x01, // REPORT_SIZE (1) 52 | USAGE_PAGE(1), 0x08, // USAGE_PAGE (LEDs) 53 | USAGE_MINIMUM(1), 0x01, // USAGE_MINIMUM (0x01) ; Num Lock 54 | USAGE_MAXIMUM(1), 0x05, // USAGE_MAXIMUM (0x05) ; Kana 55 | HIDOUTPUT(1), 0x02, // OUTPUT (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 56 | REPORT_COUNT(1), 0x01, // REPORT_COUNT (1) ; 3 bits (Padding) 57 | REPORT_SIZE(1), 0x03, // REPORT_SIZE (3) 58 | HIDOUTPUT(1), 0x01, // OUTPUT (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 59 | REPORT_COUNT(1), 0x06, // REPORT_COUNT (6) ; 6 bytes (Keys) 60 | REPORT_SIZE(1), 0x08, // REPORT_SIZE(8) 61 | LOGICAL_MINIMUM(1), 0x00, // LOGICAL_MINIMUM(0) 62 | LOGICAL_MAXIMUM(1), 0x65, // LOGICAL_MAXIMUM(0x65) ; 101 keys 63 | USAGE_PAGE(1), 0x07, // USAGE_PAGE (Kbrd/Keypad) 64 | USAGE_MINIMUM(1), 0x00, // USAGE_MINIMUM (0) 65 | USAGE_MAXIMUM(1), 0x65, // USAGE_MAXIMUM (0x65) 66 | HIDINPUT(1), 0x00, // INPUT (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) 67 | END_COLLECTION(0), // END_COLLECTION 68 | // ------------------------------------------------- Media Keys 69 | USAGE_PAGE(1), 0x0C, // USAGE_PAGE (Consumer) 70 | USAGE(1), 0x01, // USAGE (Consumer Control) 71 | COLLECTION(1), 0x01, // COLLECTION (Application) 72 | REPORT_ID(1), MEDIA_KEYS_ID, // REPORT_ID (3) 73 | USAGE_PAGE(1), 0x0C, // USAGE_PAGE (Consumer) 74 | LOGICAL_MINIMUM(1), 0x00, // LOGICAL_MINIMUM (0) 75 | LOGICAL_MAXIMUM(1), 0x01, // LOGICAL_MAXIMUM (1) 76 | REPORT_SIZE(1), 0x01, // REPORT_SIZE (1) 77 | REPORT_COUNT(1), 0x10, // REPORT_COUNT (16) 78 | USAGE(1), 0xB5, // USAGE (Scan Next Track) ; bit 0: 1 79 | USAGE(1), 0xB6, // USAGE (Scan Previous Track) ; bit 1: 2 80 | USAGE(1), 0xB7, // USAGE (Stop) ; bit 2: 4 81 | USAGE(1), 0xCD, // USAGE (Play/Pause) ; bit 3: 8 82 | USAGE(1), 0xE2, // USAGE (Mute) ; bit 4: 16 83 | USAGE(1), 0xE9, // USAGE (Volume Increment) ; bit 5: 32 84 | USAGE(1), 0xEA, // USAGE (Volume Decrement) ; bit 6: 64 85 | USAGE(2), 0x23, 0x02, // Usage (WWW Home) ; bit 7: 128 86 | USAGE(2), 0x94, 0x01, // Usage (My Computer) ; bit 0: 1 87 | USAGE(2), 0x92, 0x01, // Usage (Calculator) ; bit 1: 2 88 | USAGE(2), 0x2A, 0x02, // Usage (WWW fav) ; bit 2: 4 89 | USAGE(2), 0x21, 0x02, // Usage (WWW search) ; bit 3: 8 90 | USAGE(2), 0x26, 0x02, // Usage (WWW stop) ; bit 4: 16 91 | USAGE(2), 0x24, 0x02, // Usage (WWW back) ; bit 5: 32 92 | USAGE(2), 0x83, 0x01, // Usage (Media sel) ; bit 6: 64 93 | USAGE(2), 0x8A, 0x01, // Usage (Mail) ; bit 7: 128 94 | HIDINPUT(1), 0x02, // INPUT (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 95 | END_COLLECTION(0) // END_COLLECTION 96 | }; 97 | 98 | BleKeyboard::BleKeyboard(std::string deviceName, std::string deviceManufacturer, uint8_t batteryLevel) 99 | : hid(0) 100 | , deviceName(std::string(deviceName).substr(0, 15)) 101 | , deviceManufacturer(std::string(deviceManufacturer).substr(0,15)) 102 | , batteryLevel(batteryLevel) { 103 | _asciimap = KeyboardLayout_en_US; 104 | } 105 | 106 | void BleKeyboard::begin(void) 107 | { 108 | BLEDevice::init(deviceName); 109 | BLEServer* pServer = BLEDevice::createServer(); 110 | pServer->setCallbacks(this); 111 | 112 | hid = new BLEHIDDevice(pServer); 113 | inputKeyboard = hid->inputReport(KEYBOARD_ID); // <-- input REPORTID from report map 114 | outputKeyboard = hid->outputReport(KEYBOARD_ID); 115 | inputMediaKeys = hid->inputReport(MEDIA_KEYS_ID); 116 | 117 | outputKeyboard->setCallbacks(this); 118 | 119 | hid->manufacturer()->setValue(deviceManufacturer); 120 | 121 | hid->pnp(0x02, vid, pid, version); 122 | hid->hidInfo(0x00, 0x01); 123 | 124 | 125 | #if defined(USE_NIMBLE) 126 | 127 | BLEDevice::setSecurityAuth(true, true, true); 128 | 129 | #else 130 | 131 | BLESecurity* pSecurity = new BLESecurity(); 132 | pSecurity->setAuthenticationMode(ESP_LE_AUTH_REQ_SC_MITM_BOND); 133 | 134 | #endif // USE_NIMBLE 135 | 136 | hid->reportMap((uint8_t*)_hidReportDescriptor, sizeof(_hidReportDescriptor)); 137 | hid->startServices(); 138 | 139 | onStarted(pServer); 140 | 141 | advertising = pServer->getAdvertising(); 142 | advertising->setAppearance(HID_KEYBOARD); 143 | advertising->addServiceUUID(hid->hidService()->getUUID()); 144 | advertising->setScanResponse(false); 145 | advertising->start(); 146 | hid->setBatteryLevel(batteryLevel); 147 | 148 | ESP_LOGD(LOG_TAG, "Advertising started!"); 149 | } 150 | 151 | void BleKeyboard::setLayout(KeyboardLayout *layout) { 152 | if (layout != nullptr) { 153 | keyboardLayout = layout; 154 | _asciimap = layout->getKeymap(); 155 | } else { 156 | layout = new KeyboardLayout_US(); 157 | } 158 | } 159 | 160 | void BleKeyboard::end(void) 161 | { 162 | } 163 | 164 | bool BleKeyboard::isConnected(void) { 165 | return this->connected; 166 | } 167 | 168 | void BleKeyboard::setBatteryLevel(uint8_t level) { 169 | this->batteryLevel = level; 170 | if (hid != 0) 171 | this->hid->setBatteryLevel(this->batteryLevel); 172 | } 173 | 174 | //must be called before begin in order to set the name 175 | void BleKeyboard::setName(std::string deviceName) { 176 | this->deviceName = deviceName; 177 | } 178 | 179 | /** 180 | * @brief Sets the waiting time (in milliseconds) between multiple keystrokes in NimBLE mode. 181 | * 182 | * @param ms Time in milliseconds 183 | */ 184 | void BleKeyboard::setDelay(uint32_t ms) { 185 | this->_delay_ms = ms; 186 | } 187 | 188 | void BleKeyboard::set_vendor_id(uint16_t vid) { 189 | this->vid = vid; 190 | } 191 | 192 | void BleKeyboard::set_product_id(uint16_t pid) { 193 | this->pid = pid; 194 | } 195 | 196 | void BleKeyboard::set_version(uint16_t version) { 197 | this->version = version; 198 | } 199 | 200 | void BleKeyboard::sendReport(BLEKeyReport* keys) 201 | { 202 | if (this->isConnected()) 203 | { 204 | this->inputKeyboard->setValue((uint8_t*)keys, sizeof(BLEKeyReport)); 205 | this->inputKeyboard->notify(); 206 | #if defined(USE_NIMBLE) 207 | // vTaskDelay(delayTicks); 208 | this->delay_ms(_delay_ms); 209 | #endif // USE_NIMBLE 210 | } 211 | } 212 | 213 | void BleKeyboard::sendReport(MediaKeyReport* keys) 214 | { 215 | if (this->isConnected()) 216 | { 217 | this->inputMediaKeys->setValue((uint8_t*)keys, sizeof(MediaKeyReport)); 218 | this->inputMediaKeys->notify(); 219 | #if defined(USE_NIMBLE) 220 | //vTaskDelay(delayTicks); 221 | this->delay_ms(_delay_ms); 222 | #endif // USE_NIMBLE 223 | } 224 | } 225 | 226 | uint8_t USBPutChar(uint8_t c); 227 | 228 | // press() adds the specified key (printing, non-printing, or modifier) 229 | // to the persistent key report and sends the report. Because of the way 230 | // USB HID works, the host acts like the key remains pressed until we 231 | // call release(), releaseAll(), or otherwise clear the report and resend. 232 | size_t BleKeyboard::press(uint8_t k) 233 | { 234 | if (k >= 0x88) { // it's a non-printing key (not a modifier) 235 | k = k - 0x88; 236 | } else if (k >= 0x80) { // it's a modifier key 237 | _keyReport.modifiers |= (1<<(k-0x80)); 238 | k = 0; 239 | } else { // it's a printing key 240 | k = pgm_read_byte(_asciimap + k); 241 | if (!k) { 242 | setWriteError(); 243 | return 0; 244 | } 245 | if ((k & ALT_GR) == ALT_GR) { 246 | _keyReport.modifiers |= 0x40; 247 | k &= 0x3F; 248 | } 249 | else if ((k & SHIFT) == SHIFT) { // it's a capital letter or other character reached with shift 250 | _keyReport.modifiers |= 0x02; // the left shift modifier 251 | k &= 0x7F; 252 | } 253 | if (k == ISO_REPLACEMENT) { 254 | k = ISO_KEY; 255 | } 256 | } 257 | 258 | uint8_t i; 259 | if (k >= 0xE0 && k < 0xE8) { 260 | _keyReport.modifiers |= (1 << (k - 0x80)); 261 | } else if (k && k < 0xA5) { 262 | // Add k to the key report only if it's not already present 263 | // and if there is an empty slot. 264 | if (_keyReport.keys[0] != k && _keyReport.keys[1] != k && 265 | _keyReport.keys[2] != k && _keyReport.keys[3] != k && 266 | _keyReport.keys[4] != k && _keyReport.keys[5] != k) { 267 | 268 | for (i=0; i<6; i++) { 269 | if (_keyReport.keys[i] == 0x00) { 270 | _keyReport.keys[i] = k; 271 | break; 272 | } 273 | } 274 | if (i == 6) { 275 | setWriteError(); 276 | return 0; 277 | } 278 | } 279 | } else { 280 | return 0; 281 | } 282 | 283 | sendReport(&_keyReport); 284 | return 1; 285 | } 286 | 287 | size_t BleKeyboard::press(const MediaKeyReport k) 288 | { 289 | uint16_t k_16 = k[1] | (k[0] << 8); 290 | uint16_t mediaKeyReport_16 = _mediaKeyReport[1] | (_mediaKeyReport[0] << 8); 291 | 292 | mediaKeyReport_16 |= k_16; 293 | _mediaKeyReport[0] = (uint8_t)((mediaKeyReport_16 & 0xFF00) >> 8); 294 | _mediaKeyReport[1] = (uint8_t)(mediaKeyReport_16 & 0x00FF); 295 | 296 | sendReport(&_mediaKeyReport); 297 | return 1; 298 | } 299 | 300 | // release() takes the specified key out of the persistent key report and 301 | // sends the report. This tells the OS the key is no longer pressed and that 302 | // it shouldn't be repeated any more. 303 | size_t BleKeyboard::release(uint8_t k) 304 | { 305 | if (k >= 0x88) { // it's a non-printing key (not a modifier) 306 | k = k - 0x88; 307 | } else if (k >= 0x80) { // it's a modifier key 308 | _keyReport.modifiers &= ~(1<<(k-0x80)); 309 | k = 0; 310 | } else { // it's a printing key 311 | k = pgm_read_byte(_asciimap + k); 312 | if (!k) { 313 | return 0; 314 | } 315 | if ((k & ALT_GR) == ALT_GR) { 316 | _keyReport.modifiers &= ~(0x40); 317 | k &= 0x3F; 318 | } 319 | else if ((k & SHIFT) == SHIFT) { // it's a capital letter or other character reached with shift 320 | _keyReport.modifiers &= ~(0x02); // the left shift modifier 321 | k &= 0x7F; 322 | } 323 | if (k == ISO_REPLACEMENT) { 324 | k = ISO_KEY; 325 | } 326 | } 327 | 328 | uint8_t i; 329 | if (k >= 0xE0 && k < 0xE8) { 330 | _keyReport.modifiers &= ~(1<<(k-0x80)); 331 | } else if (k && k < 0xA5) { 332 | // Test the key report to see if k is present. Clear it if it exists. 333 | // Check all positions in case the key is present more than once (which it shouldn't be) 334 | for (i=0; i<6; i++) { 335 | if (0 != k && _keyReport.keys[i] == k) { 336 | _keyReport.keys[i] = 0x00; 337 | } 338 | } 339 | } else { 340 | return 0; 341 | } 342 | 343 | sendReport(&_keyReport); 344 | return 1; 345 | } 346 | 347 | size_t BleKeyboard::release(const MediaKeyReport k) 348 | { 349 | uint16_t k_16 = k[1] | (k[0] << 8); 350 | uint16_t mediaKeyReport_16 = _mediaKeyReport[1] | (_mediaKeyReport[0] << 8); 351 | mediaKeyReport_16 &= ~k_16; 352 | _mediaKeyReport[0] = (uint8_t)((mediaKeyReport_16 & 0xFF00) >> 8); 353 | _mediaKeyReport[1] = (uint8_t)(mediaKeyReport_16 & 0x00FF); 354 | 355 | sendReport(&_mediaKeyReport); 356 | return 1; 357 | } 358 | 359 | void BleKeyboard::releaseAll(void) 360 | { 361 | _keyReport.keys[0] = 0; 362 | _keyReport.keys[1] = 0; 363 | _keyReport.keys[2] = 0; 364 | _keyReport.keys[3] = 0; 365 | _keyReport.keys[4] = 0; 366 | _keyReport.keys[5] = 0; 367 | _keyReport.modifiers = 0; 368 | _mediaKeyReport[0] = 0; 369 | _mediaKeyReport[1] = 0; 370 | sendReport(&_keyReport); 371 | sendReport(&_mediaKeyReport); 372 | } 373 | 374 | size_t BleKeyboard::write(uint8_t c) 375 | { 376 | uint8_t p = press(c); // Keydown 377 | release(c); // Keyup 378 | return p; // just return the result of press() since release() almost always returns 1 379 | } 380 | 381 | size_t BleKeyboard::write(const MediaKeyReport c) 382 | { 383 | uint16_t p = press(c); // Keydown 384 | release(c); // Keyup 385 | return p; // just return the result of press() since release() almost always returns 1 386 | } 387 | 388 | size_t BleKeyboard::write(const uint8_t *buffer, size_t size) { 389 | size_t n = 0; 390 | while (size--) { 391 | if (*buffer != '\r') { 392 | if (write(*buffer)) { 393 | n++; 394 | } else { 395 | break; 396 | } 397 | } 398 | buffer++; 399 | } 400 | return n; 401 | } 402 | 403 | void BleKeyboard::onConnect(BLEServer* pServer) { 404 | this->connected = true; 405 | 406 | #if !defined(USE_NIMBLE) 407 | 408 | BLE2902* desc = (BLE2902*)this->inputKeyboard->getDescriptorByUUID(BLEUUID((uint16_t)0x2902)); 409 | desc->setNotifications(true); 410 | desc = (BLE2902*)this->inputMediaKeys->getDescriptorByUUID(BLEUUID((uint16_t)0x2902)); 411 | desc->setNotifications(true); 412 | 413 | #endif // !USE_NIMBLE 414 | 415 | } 416 | 417 | void BleKeyboard::onDisconnect(BLEServer* pServer) { 418 | this->connected = false; 419 | 420 | #if !defined(USE_NIMBLE) 421 | 422 | BLE2902* desc = (BLE2902*)this->inputKeyboard->getDescriptorByUUID(BLEUUID((uint16_t)0x2902)); 423 | desc->setNotifications(false); 424 | desc = (BLE2902*)this->inputMediaKeys->getDescriptorByUUID(BLEUUID((uint16_t)0x2902)); 425 | desc->setNotifications(false); 426 | 427 | advertising->start(); 428 | 429 | #endif // !USE_NIMBLE 430 | } 431 | 432 | void BleKeyboard::onWrite(BLECharacteristic* me) { 433 | uint8_t* value = (uint8_t*)(me->getValue().c_str()); 434 | (void)value; 435 | ESP_LOGI(LOG_TAG, "special keys: %d", *value); 436 | } 437 | 438 | void BleKeyboard::delay_ms(uint64_t ms) { 439 | uint64_t m = esp_timer_get_time(); 440 | if(ms){ 441 | uint64_t e = (m + (ms * 1000)); 442 | if(m > e){ //overflow 443 | while(esp_timer_get_time() > e) { } 444 | } 445 | while(esp_timer_get_time() < e) {} 446 | } 447 | } 448 | -------------------------------------------------------------------------------- /src/USBHID-Keyboard/USBHID.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #include "USBHID.h" 15 | 16 | #if CONFIG_TINYUSB_HID_ENABLED 17 | 18 | #include "esp32-hal-tinyusb.h" 19 | #include "USB.h" 20 | #include "esp_hid_common.h" 21 | 22 | #define USB_HID_DEVICES_MAX 10 23 | 24 | ESP_EVENT_DEFINE_BASE(ARDUINO_USB_HID_EVENTS); 25 | esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait); 26 | esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg); 27 | 28 | typedef struct { 29 | USBHIDDevice * device; 30 | uint8_t reports_num; 31 | uint8_t * report_ids; 32 | } tinyusb_hid_device_t; 33 | 34 | static tinyusb_hid_device_t tinyusb_hid_devices[USB_HID_DEVICES_MAX]; 35 | 36 | static uint8_t tinyusb_hid_devices_num = 0; 37 | static bool tinyusb_hid_devices_is_initialized = false; 38 | static xSemaphoreHandle tinyusb_hid_device_input_sem = NULL; 39 | static xSemaphoreHandle tinyusb_hid_device_input_mutex = NULL; 40 | 41 | static bool tinyusb_hid_is_initialized = false; 42 | static uint8_t tinyusb_loaded_hid_devices_num = 0; 43 | static uint16_t tinyusb_hid_device_descriptor_len = 0; 44 | static uint8_t * tinyusb_hid_device_descriptor = NULL; 45 | #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG 46 | static const char * tinyusb_hid_device_report_types[4] = {"INVALID", "INPUT", "OUTPUT", "FEATURE"}; 47 | #endif 48 | 49 | static bool tinyusb_enable_hid_device(uint16_t descriptor_len, USBHIDDevice * device){ 50 | if(tinyusb_hid_is_initialized){ 51 | log_e("TinyUSB HID has already started! Device not enabled"); 52 | return false; 53 | } 54 | if(tinyusb_loaded_hid_devices_num >= USB_HID_DEVICES_MAX){ 55 | log_e("Maximum devices already enabled! Device not enabled"); 56 | return false; 57 | } 58 | tinyusb_hid_device_descriptor_len += descriptor_len; 59 | tinyusb_hid_devices[tinyusb_loaded_hid_devices_num++].device = device; 60 | 61 | log_d("Device[%u] len: %u", tinyusb_loaded_hid_devices_num-1, descriptor_len); 62 | return true; 63 | } 64 | 65 | USBHIDDevice * tinyusb_get_device_by_report_id(uint8_t report_id){ 66 | for(uint8_t i=0; idevice && device->reports_num){ 69 | for(uint8_t r=0; rreports_num; r++){ 70 | if(report_id == device->report_ids[r]){ 71 | return device->device; 72 | } 73 | } 74 | } 75 | } 76 | return NULL; 77 | } 78 | 79 | static uint16_t tinyusb_on_get_feature(uint8_t report_id, uint8_t* buffer, uint16_t reqlen){ 80 | USBHIDDevice * device = tinyusb_get_device_by_report_id(report_id); 81 | if(device){ 82 | return device->_onGetFeature(report_id, buffer, reqlen); 83 | } 84 | return 0; 85 | } 86 | 87 | static bool tinyusb_on_set_feature(uint8_t report_id, const uint8_t* buffer, uint16_t reqlen){ 88 | USBHIDDevice * device = tinyusb_get_device_by_report_id(report_id); 89 | if(device){ 90 | device->_onSetFeature(report_id, buffer, reqlen); 91 | return true; 92 | } 93 | return false; 94 | } 95 | 96 | static bool tinyusb_on_set_output(uint8_t report_id, const uint8_t* buffer, uint16_t reqlen){ 97 | USBHIDDevice * device = tinyusb_get_device_by_report_id(report_id); 98 | if(device){ 99 | device->_onOutput(report_id, buffer, reqlen); 100 | return true; 101 | } 102 | return false; 103 | } 104 | 105 | static uint16_t tinyusb_on_add_descriptor(uint8_t device_index, uint8_t * dst){ 106 | uint16_t res = 0; 107 | uint8_t report_id = 0, reports_num = 0; 108 | tinyusb_hid_device_t * device = &tinyusb_hid_devices[device_index]; 109 | if(device->device){ 110 | res = device->device->_onGetDescriptor(dst); 111 | if(res){ 112 | 113 | esp_hid_report_map_t *hid_report_map = esp_hid_parse_report_map(dst, res); 114 | if(hid_report_map){ 115 | if(device->report_ids){ 116 | free(device->report_ids); 117 | } 118 | device->reports_num = hid_report_map->reports_len; 119 | device->report_ids = (uint8_t*)malloc(device->reports_num); 120 | memset(device->report_ids, 0, device->reports_num); 121 | reports_num = device->reports_num; 122 | 123 | for(uint8_t i=0; ireports_num; i++){ 124 | if(hid_report_map->reports[i].protocol_mode == ESP_HID_PROTOCOL_MODE_REPORT){ 125 | report_id = hid_report_map->reports[i].report_id; 126 | for(uint8_t r=0; rreports_num; r++){ 127 | if(!report_id){ 128 | //todo: handle better when device has no report ID set 129 | break; 130 | } else if(report_id == device->report_ids[r]){ 131 | //already added 132 | reports_num--; 133 | break; 134 | } else if(!device->report_ids[r]){ 135 | //empty slot 136 | device->report_ids[r] = report_id; 137 | break; 138 | } 139 | } 140 | } else { 141 | reports_num--; 142 | } 143 | } 144 | device->reports_num = reports_num; 145 | esp_hid_free_report_map(hid_report_map); 146 | } 147 | 148 | } 149 | } 150 | return res; 151 | } 152 | 153 | 154 | static bool tinyusb_load_enabled_hid_devices(){ 155 | if(tinyusb_hid_device_descriptor != NULL){ 156 | return true; 157 | } 158 | tinyusb_hid_device_descriptor = (uint8_t *)malloc(tinyusb_hid_device_descriptor_len); 159 | if (tinyusb_hid_device_descriptor == NULL) { 160 | log_e("HID Descriptor Malloc Failed"); 161 | return false; 162 | } 163 | uint8_t * dst = tinyusb_hid_device_descriptor; 164 | 165 | for(uint8_t i=0; ireports_len; i++){ 178 | if(hid_report_map->reports[i].protocol_mode == ESP_HID_PROTOCOL_MODE_REPORT){ 179 | log_d(" ID: %3u, Type: %7s, Size: %2u, Usage: %8s", 180 | hid_report_map->reports[i].report_id, 181 | esp_hid_report_type_str(hid_report_map->reports[i].report_type), 182 | hid_report_map->reports[i].value_len, 183 | esp_hid_usage_str(hid_report_map->reports[i].usage) 184 | ); 185 | } 186 | } 187 | esp_hid_free_report_map(hid_report_map); 188 | } else { 189 | log_e("Failed to parse the hid report descriptor!"); 190 | return false; 191 | } 192 | 193 | return true; 194 | } 195 | 196 | extern "C" uint16_t tusb_hid_load_descriptor(uint8_t * dst, uint8_t * itf) 197 | { 198 | if(tinyusb_hid_is_initialized){ 199 | return 0; 200 | } 201 | tinyusb_hid_is_initialized = true; 202 | 203 | uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB HID"); 204 | uint8_t ep_in = tinyusb_get_free_in_endpoint(); 205 | TU_VERIFY (ep_in != 0); 206 | uint8_t ep_out = tinyusb_get_free_out_endpoint(); 207 | TU_VERIFY (ep_out != 0); 208 | uint8_t descriptor[TUD_HID_INOUT_DESC_LEN] = { 209 | // HID Input & Output descriptor 210 | // Interface number, string index, protocol, report descriptor len, EP OUT & IN address, size & polling interval 211 | TUD_HID_INOUT_DESCRIPTOR(*itf, str_index, HID_ITF_PROTOCOL_NONE, tinyusb_hid_device_descriptor_len, ep_out, (uint8_t)(0x80 | ep_in), 64, 1) 212 | }; 213 | *itf+=1; 214 | memcpy(dst, descriptor, TUD_HID_INOUT_DESC_LEN); 215 | return TUD_HID_INOUT_DESC_LEN; 216 | } 217 | 218 | 219 | 220 | 221 | // Invoked when received GET HID REPORT DESCRIPTOR request 222 | // Application return pointer to descriptor, whose contents must exist long enough for transfer to complete 223 | uint8_t const * tud_hid_descriptor_report_cb(uint8_t instance){ 224 | log_v("instance: %u", instance); 225 | if(!tinyusb_load_enabled_hid_devices()){ 226 | return NULL; 227 | } 228 | return tinyusb_hid_device_descriptor; 229 | } 230 | 231 | // Invoked when received SET_PROTOCOL request 232 | // protocol is either HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1) 233 | void tud_hid_set_protocol_cb(uint8_t instance, uint8_t protocol){ 234 | log_v("instance: %u, protocol:%u", instance, protocol); 235 | arduino_usb_hid_event_data_t p; 236 | p.instance = instance; 237 | p.set_protocol.protocol = protocol; 238 | arduino_usb_event_post(ARDUINO_USB_HID_EVENTS, ARDUINO_USB_HID_SET_PROTOCOL_EVENT, &p, sizeof(arduino_usb_hid_event_data_t), portMAX_DELAY); 239 | } 240 | 241 | // Invoked when received SET_IDLE request. return false will stall the request 242 | // - Idle Rate = 0 : only send report if there is changes, i.e skip duplication 243 | // - Idle Rate > 0 : skip duplication, but send at least 1 report every idle rate (in unit of 4 ms). 244 | bool tud_hid_set_idle_cb(uint8_t instance, uint8_t idle_rate){ 245 | log_v("instance: %u, idle_rate:%u", instance, idle_rate); 246 | arduino_usb_hid_event_data_t p; 247 | p.instance = instance; 248 | p.set_idle.idle_rate = idle_rate; 249 | arduino_usb_event_post(ARDUINO_USB_HID_EVENTS, ARDUINO_USB_HID_SET_IDLE_EVENT, &p, sizeof(arduino_usb_hid_event_data_t), portMAX_DELAY); 250 | return true; 251 | } 252 | 253 | // Invoked when received GET_REPORT control request 254 | // Application must fill buffer report's content and return its length. 255 | // Return zero will cause the stack to STALL request 256 | uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen){ 257 | uint16_t res = tinyusb_on_get_feature(report_id, buffer, reqlen); 258 | if(!res){ 259 | log_d("instance: %u, report_id: %u, report_type: %s, reqlen: %u", instance, report_id, tinyusb_hid_device_report_types[report_type], reqlen); 260 | } 261 | return res; 262 | } 263 | 264 | // Invoked when received SET_REPORT control request or 265 | // received data on OUT endpoint ( Report ID = 0, Type = 0 ) 266 | void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize){ 267 | if(!report_id && !report_type){ 268 | if(!tinyusb_on_set_output(0, buffer, bufsize) && !tinyusb_on_set_output(buffer[0], buffer+1, bufsize-1)){ 269 | log_d("instance: %u, report_id: %u, report_type: %s, bufsize: %u", instance, buffer[0], tinyusb_hid_device_report_types[HID_REPORT_TYPE_OUTPUT], bufsize-1); 270 | } 271 | } else { 272 | if(!tinyusb_on_set_feature(report_id, buffer, bufsize)){ 273 | log_d("instance: %u, report_id: %u, report_type: %s, bufsize: %u", instance, report_id, tinyusb_hid_device_report_types[report_type], bufsize); 274 | } 275 | } 276 | } 277 | 278 | USBHID::USBHID(){ 279 | if(!tinyusb_hid_devices_is_initialized){ 280 | tinyusb_hid_devices_is_initialized = true; 281 | for(uint8_t i=0; i struct ArgType; 317 | 318 | template 319 | struct ArgType { 320 | typedef T1 type1; 321 | typedef T2 type2; 322 | typedef T3 type3; 323 | }; 324 | 325 | typedef ArgType::type3 tud_hid_report_complete_cb_len_t; 326 | 327 | void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, tud_hid_report_complete_cb_len_t len){ 328 | if (tinyusb_hid_device_input_sem) { 329 | xSemaphoreGive(tinyusb_hid_device_input_sem); 330 | } 331 | } 332 | 333 | bool USBHID::SendReport(uint8_t id, const void* data, size_t len, uint32_t timeout_ms){ 334 | if(!tinyusb_hid_device_input_sem || !tinyusb_hid_device_input_mutex){ 335 | log_e("TX Semaphore is NULL. You must call USBHID::begin() before you can send reports"); 336 | return false; 337 | } 338 | 339 | if(xSemaphoreTake(tinyusb_hid_device_input_mutex, timeout_ms / portTICK_PERIOD_MS) != pdTRUE){ 340 | log_e("report %u mutex failed", id); 341 | return false; 342 | } 343 | 344 | bool res = ready(); 345 | if(!res){ 346 | log_e("not ready"); 347 | } else { 348 | // The semaphore may be given if the last SendReport() timed out waiting for the report to 349 | // be sent. Or, tud_hid_report_complete_cb() may be called an extra time, causing the 350 | // semaphore to be given. In these cases, take the semaphore to clear its state so that 351 | // we can wait for it to be given after calling tud_hid_n_report(). 352 | xSemaphoreTake(tinyusb_hid_device_input_sem, 0); 353 | 354 | res = tud_hid_n_report(0, id, data, len); 355 | if(!res){ 356 | log_e("report %u failed", id); 357 | } else { 358 | if(xSemaphoreTake(tinyusb_hid_device_input_sem, timeout_ms / portTICK_PERIOD_MS) != pdTRUE){ 359 | log_e("report %u wait failed", id); 360 | res = false; 361 | } 362 | } 363 | } 364 | 365 | xSemaphoreGive(tinyusb_hid_device_input_mutex); 366 | return res; 367 | } 368 | 369 | bool USBHID::addDevice(USBHIDDevice * device, uint16_t descriptor_len){ 370 | if(device && tinyusb_loaded_hid_devices_num < USB_HID_DEVICES_MAX){ 371 | if(!tinyusb_enable_hid_device(descriptor_len, device)){ 372 | return false; 373 | } 374 | return true; 375 | } 376 | return false; 377 | } 378 | 379 | void USBHID::onEvent(esp_event_handler_t callback){ 380 | onEvent(ARDUINO_USB_HID_ANY_EVENT, callback); 381 | } 382 | void USBHID::onEvent(arduino_usb_hid_event_t event, esp_event_handler_t callback){ 383 | arduino_usb_event_handler_register_with(ARDUINO_USB_HID_EVENTS, event, callback, this); 384 | } 385 | 386 | #endif /* CONFIG_TINYUSB_HID_ENABLED */ 387 | -------------------------------------------------------------------------------- /icons.h: -------------------------------------------------------------------------------- 1 | static const uint16_t Empty[256] = { 2 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 3 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 4 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 5 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 6 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 7 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 8 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 9 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 10 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 11 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 12 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 13 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 14 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 15 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 16 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 17 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 18 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 19 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 20 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 21 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 22 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 23 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 24 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 25 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 26 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 27 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 28 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 29 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 30 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 31 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 32 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 33 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 34 | }; 35 | static const uint16_t Fileicon[256] = { 36 | // ∙∙░░░░░░░░░∙∙∙∙∙ 37 | // ∙∙░∙∙∙∙∙∙∙░░∙∙∙∙ 38 | // ∙∙░∙∙∙∙∙∙∙░∙░∙∙∙ 39 | // ∙∙░∙∙∙∙∙∙∙░░░░∙∙ 40 | // ∙∙░∙∙∙∙∙∙∙∙∙∙░∙∙ 41 | // ∙∙░∙∙∙∙∙∙∙∙∙∙░∙∙ 42 | // ∙∙░∙∙∙∙∙∙∙∙∙∙░∙∙ 43 | // ∙∙░∙∙∙∙∙∙∙∙∙∙░∙∙ 44 | // ∙∙░∙∙∙∙∙∙∙∙∙∙░∙∙ 45 | // ∙∙░∙∙∙∙∙∙∙∙∙∙░∙∙ 46 | // ∙∙░∙∙∙∙∙∙∙∙∙∙░∙∙ 47 | // ∙∙░∙∙∙∙∙∙∙∙∙∙░∙∙ 48 | // ∙∙░∙∙∙∙∙∙∙∙∙∙░∙∙ 49 | // ∙∙░∙∙∙∙∙∙∙∙∙∙░∙∙ 50 | // ∙∙░∙∙∙∙∙∙∙∙∙∙░∙∙ 51 | // ∙∙░░░░░░░░░░░░∙∙ 52 | 0x0000, 0x0000, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 53 | 0x8010, 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 54 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 55 | 0x0000, 0x0000, 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 56 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 57 | 0x0000, 0x0000, 0x8010, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 58 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 59 | 0x0000, 0x0000, 0x8010, 0x8010, 0x8010, 0x8010, 0x0000, 0x0000, 60 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 61 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 62 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 63 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 64 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 65 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 66 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 67 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 68 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 69 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 70 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 71 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 72 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 73 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 74 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 75 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 76 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 77 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 78 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 79 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 80 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 81 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 82 | 0x0000, 0x0000, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 83 | 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x0000, 0x0000 84 | }; 85 | 86 | static const uint16_t KBLayouticon[256] = { 87 | // ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙ 88 | // ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙ 89 | // ∙∙∙∙∙∙∙░░∙∙∙∙∙∙∙ 90 | // ∙∙∙∙∙∙∙░░∙∙∙∙∙∙∙ 91 | // ░░░░░░░░░░░░░░░░ 92 | // ░∙∙∙∙∙∙∙∙∙∙∙∙∙∙░ 93 | // ░∙░∙░∙░∙░∙░∙░∙∙░ 94 | // ░∙∙∙∙∙∙∙∙∙∙∙∙∙∙░ 95 | // ░∙∙░∙░∙░∙░∙░∙░∙░ 96 | // ░∙∙∙∙∙∙∙∙∙∙∙∙∙∙░ 97 | // ░∙∙∙∙∙∙∙∙∙∙∙∙∙∙░ 98 | // ░∙░∙░░░░░░░░∙░∙░ 99 | // ░∙∙∙∙∙∙∙∙∙∙∙∙∙∙░ 100 | // ░░░░░░░░░░░░░░░░ 101 | // ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙ 102 | // ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙ 103 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 104 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 105 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 106 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 107 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 108 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 109 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 110 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 111 | 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 112 | 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 113 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 114 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 115 | 0x8010, 0x0000, 0x8010, 0x0000, 0x8010, 0x0000, 0x8010, 0x0000, 116 | 0x8010, 0x0000, 0x8010, 0x0000, 0x8010, 0x0000, 0x0000, 0x8010, 117 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 118 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 119 | 0x8010, 0x0000, 0x0000, 0x8010, 0x0000, 0x8010, 0x0000, 0x8010, 120 | 0x0000, 0x8010, 0x0000, 0x8010, 0x0000, 0x8010, 0x0000, 0x8010, 121 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 122 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 123 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 124 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 125 | 0x8010, 0x0000, 0x8010, 0x0000, 0x8010, 0x8010, 0x8010, 0x8010, 126 | 0x8010, 0x8010, 0x8010, 0x8010, 0x0000, 0x8010, 0x0000, 0x8010, 127 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 128 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 129 | 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 130 | 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 131 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 132 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 133 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 134 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 135 | }; 136 | 137 | static const uint16_t BLEicon[256] = { 138 | // ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙ 139 | // ∙∙∙∙∙∙∙░░░∙∙∙∙∙∙ 140 | // ∙∙∙∙∙∙∙░░░░∙∙∙∙∙ 141 | // ∙∙░░∙∙∙░░∙░░∙∙∙∙ 142 | // ∙∙∙░░∙∙░░∙∙░░∙∙∙ 143 | // ∙∙∙∙░░∙░░∙∙∙░░∙∙ 144 | // ∙∙∙∙∙░░░░∙∙░░∙∙∙ 145 | // ∙∙∙∙∙∙░░░∙░░∙∙∙∙ 146 | // ∙∙∙∙∙∙∙░░░░∙∙∙∙∙ 147 | // ∙∙∙∙∙∙░░░∙░░∙∙∙∙ 148 | // ∙∙∙∙∙░░░░∙∙░░∙∙∙ 149 | // ∙∙∙∙░░∙░░∙∙∙░░∙∙ 150 | // ∙∙∙░░∙∙░░∙∙░░∙∙∙ 151 | // ∙∙░░∙∙∙░░∙░░∙∙∙∙ 152 | // ∙∙∙∙∙∙∙░░░░∙∙∙∙∙ 153 | // ∙∙∙∙∙∙∙░░░∙∙∙∙∙∙ 154 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 155 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 156 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 157 | 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 158 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 159 | 0x8010, 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 160 | 0x0000, 0x0000, 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 0x8010, 161 | 0x8010, 0x0000, 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 162 | 0x0000, 0x0000, 0x0000, 0x8010, 0x8010, 0x0000, 0x0000, 0x8010, 163 | 0x8010, 0x0000, 0x0000, 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 164 | 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x8010, 0x0000, 0x8010, 165 | 0x8010, 0x0000, 0x0000, 0x0000, 0x8010, 0x8010, 0x0000, 0x0000, 166 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x8010, 0x8010, 167 | 0x8010, 0x0000, 0x0000, 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 168 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x8010, 169 | 0x8010, 0x0000, 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 170 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 171 | 0x8010, 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 172 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x8010, 173 | 0x8010, 0x0000, 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 174 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x8010, 0x8010, 175 | 0x8010, 0x0000, 0x0000, 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 176 | 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x8010, 0x0000, 0x8010, 177 | 0x8010, 0x0000, 0x0000, 0x0000, 0x8010, 0x8010, 0x0000, 0x0000, 178 | 0x0000, 0x0000, 0x0000, 0x8010, 0x8010, 0x0000, 0x0000, 0x8010, 179 | 0x8010, 0x0000, 0x0000, 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 180 | 0x0000, 0x0000, 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 0x8010, 181 | 0x8010, 0x0000, 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 182 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 183 | 0x8010, 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 184 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 185 | 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 186 | }; 187 | 188 | static const uint16_t Foldericon[256] = { 189 | // ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙ 190 | // ∙░░░░░░░░∙∙∙∙∙∙∙ 191 | // ░∙∙∙∙∙∙∙∙░∙∙∙∙∙∙ 192 | // ░∙∙∙∙∙∙∙∙∙░∙∙∙∙∙ 193 | // ░░░░░░░░░░░░░░░∙ 194 | // ░∙∙∙∙∙∙∙∙∙∙∙∙∙∙░ 195 | // ░∙∙∙∙∙∙∙∙∙∙∙∙∙∙░ 196 | // ░∙∙∙∙∙∙∙∙∙∙∙∙∙∙░ 197 | // ░∙∙∙∙∙∙∙∙∙∙∙∙∙∙░ 198 | // ░∙∙∙∙∙∙∙∙∙∙∙∙∙∙░ 199 | // ░∙∙∙∙∙∙∙∙∙∙∙∙∙∙░ 200 | // ░∙∙∙∙∙∙∙∙∙∙∙∙∙∙░ 201 | // ░∙∙∙∙∙∙∙∙∙∙∙∙∙∙░ 202 | // ░∙∙∙∙∙∙∙∙∙∙∙∙∙∙░ 203 | // ∙░░░░░░░░░░░░░░∙ 204 | // ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙ 205 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 206 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 207 | 0x0000, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 208 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 209 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 210 | 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 211 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 212 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 213 | 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 214 | 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x0000, 215 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 216 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 217 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 218 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 219 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 220 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 221 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 222 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 223 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 224 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 225 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 226 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 227 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 228 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 229 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 230 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 231 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 232 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 233 | 0x0000, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 234 | 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x0000, 235 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 236 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 237 | }; 238 | 239 | static const uint16_t Newfileicon[256] = { 240 | // ∙∙░░░░░░░░░∙∙∙∙∙ 241 | // ∙∙░∙∙∙∙∙∙∙░░∙∙∙∙ 242 | // ∙∙░∙∙∙∙∙∙∙░∙░∙∙∙ 243 | // ∙∙░∙∙∙∙∙∙∙░░░░∙∙ 244 | // ∙∙░∙∙∙∙∙∙∙∙∙∙░∙∙ 245 | // ∙∙░∙∙∙∙░░∙∙∙∙░∙∙ 246 | // ∙∙░∙∙∙∙░░∙∙∙∙░∙∙ 247 | // ∙∙░∙∙░░░░░░∙∙░∙∙ 248 | // ∙∙░∙∙░░░░░░∙∙░∙∙ 249 | // ∙∙░∙∙∙∙░░∙∙∙∙░∙∙ 250 | // ∙∙░∙∙∙∙░░∙∙∙∙░∙∙ 251 | // ∙∙░∙∙∙∙∙∙∙∙∙∙░∙∙ 252 | // ∙∙░∙∙∙∙∙∙∙∙∙∙░∙∙ 253 | // ∙∙░∙∙∙∙∙∙∙∙∙∙░∙∙ 254 | // ∙∙░∙∙∙∙∙∙∙∙∙∙░∙∙ 255 | // ∙∙░░░░░░░░░░░░∙∙ 256 | 0x0000, 0x0000, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 257 | 0x8010, 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 258 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 259 | 0x0000, 0x0000, 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 260 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 261 | 0x0000, 0x0000, 0x8010, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 262 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 263 | 0x0000, 0x0000, 0x8010, 0x8010, 0x8010, 0x8010, 0x0000, 0x0000, 264 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 265 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 266 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 267 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 268 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 269 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 270 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x8010, 0x8010, 0x8010, 271 | 0x8010, 0x8010, 0x8010, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 272 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x8010, 0x8010, 0x8010, 273 | 0x8010, 0x8010, 0x8010, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 274 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 275 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 276 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 277 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 278 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 279 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 280 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 281 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 282 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 283 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 284 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 285 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 286 | 0x0000, 0x0000, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 287 | 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x0000, 0x0000 288 | }; 289 | 290 | static const uint16_t Newfoldericon[256] = { 291 | // ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙ 292 | // ∙░░░░░░░░∙∙∙∙∙∙∙ 293 | // ░∙∙∙∙∙∙∙∙░∙∙∙∙∙∙ 294 | // ░∙∙∙∙∙∙∙∙∙░∙∙∙∙∙ 295 | // ░░░░░░░░░░░░░░░∙ 296 | // ░∙∙∙∙∙∙∙∙∙∙∙∙∙∙░ 297 | // ░∙∙∙∙∙∙░░░∙∙∙∙∙░ 298 | // ░∙∙∙∙∙∙░░░∙∙∙∙∙░ 299 | // ░∙∙∙∙░░░░░░░∙∙∙░ 300 | // ░∙∙∙∙░░░░░░░∙∙∙░ 301 | // ░∙∙∙∙░░░░░░░∙∙∙░ 302 | // ░∙∙∙∙∙∙░░░∙∙∙∙∙░ 303 | // ░∙∙∙∙∙∙░░░∙∙∙∙∙░ 304 | // ░∙∙∙∙∙∙∙∙∙∙∙∙∙∙░ 305 | // ∙░░░░░░░░░░░░░░∙ 306 | // ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙ 307 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 308 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 309 | 0x0000, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 310 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 311 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 312 | 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 313 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 314 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 315 | 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 316 | 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x0000, 317 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 318 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 319 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 320 | 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 321 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 322 | 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 323 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x8010, 0x8010, 324 | 0x8010, 0x8010, 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 0x8010, 325 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x8010, 0x8010, 326 | 0x8010, 0x8010, 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 0x8010, 327 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x8010, 0x8010, 328 | 0x8010, 0x8010, 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 0x8010, 329 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 330 | 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 331 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 332 | 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 333 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 334 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 335 | 0x0000, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 336 | 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x0000, 337 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 338 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 339 | }; 340 | 341 | static const uint16_t Previousicon[256] = { 342 | // ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙ 343 | // ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙ 344 | // ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙ 345 | // ∙∙∙∙░∙∙∙∙∙∙∙∙∙∙∙ 346 | // ∙∙∙░░∙∙∙∙∙∙∙∙∙∙∙ 347 | // ∙∙░░░∙∙∙∙∙∙∙∙∙∙∙ 348 | // ∙░░░░∙∙∙∙∙∙∙∙∙∙∙ 349 | // ░░░░░░░░░░░░░░░∙ 350 | // ░░░░░░░░░░░░░░░░ 351 | // ∙░░░░∙∙∙∙∙∙∙∙∙░░ 352 | // ∙∙░░░∙∙∙∙∙∙∙∙∙░░ 353 | // ∙∙∙░░∙∙∙∙∙∙░░░░░ 354 | // ∙∙∙∙░∙∙∙∙∙∙░░░░∙ 355 | // ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙ 356 | // ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙ 357 | // ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙ 358 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 359 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 360 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 361 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 362 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 363 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 364 | 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 365 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 366 | 0x0000, 0x0000, 0x0000, 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 367 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 368 | 0x0000, 0x0000, 0x8010, 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 369 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 370 | 0x0000, 0x8010, 0x8010, 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 371 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 372 | 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 373 | 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x0000, 374 | 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 375 | 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 376 | 0x0000, 0x8010, 0x8010, 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 377 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x8010, 378 | 0x0000, 0x0000, 0x8010, 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 379 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x8010, 380 | 0x0000, 0x0000, 0x0000, 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 381 | 0x0000, 0x0000, 0x0000, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 382 | 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 383 | 0x0000, 0x0000, 0x0000, 0x8010, 0x8010, 0x8010, 0x8010, 0x0000, 384 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 385 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 386 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 387 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 388 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 389 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 390 | }; 391 | 392 | static const uint16_t Executeicon[256] = { 393 | // ∙∙∙░░░░░░░░░░∙∙∙ 394 | // ∙∙░░░░░░░░░░░░∙∙ 395 | // ∙░░∙░░░░░░░░∙░░∙ 396 | // ░░∙∙∙░░░░░░∙∙∙░░ 397 | // ░∙∙∙∙∙░░░░∙∙∙∙∙░ 398 | // ░∙∙∙∙∙∙░░∙∙∙∙∙∙░ 399 | // ░░∙∙∙∙∙░░∙∙∙∙∙░░ 400 | // ░░░∙∙∙∙░░∙∙∙∙░░░ 401 | // ∙░░░░░░░░░░░░░░∙ 402 | // ∙∙░░░░░∙∙░░░░░∙∙ 403 | // ∙∙░░░░∙∙∙∙░░░░∙∙ 404 | // ∙░░░░░∙░░∙░░░░░∙ 405 | // ∙░░░░░░░░░░░░░░∙ 406 | // ∙∙░░∙░∙░░∙░∙░░∙∙ 407 | // ∙∙∙░∙░∙░░∙░∙░∙∙∙ 408 | // ∙∙∙∙∙░∙░░∙░∙∙∙∙∙ 409 | 0x0000, 0x0000, 0x0000, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 410 | 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 411 | 0x0000, 0x0000, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 412 | 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x0000, 0x0000, 413 | 0x0000, 0x8010, 0x8010, 0x0000, 0x8010, 0x8010, 0x8010, 0x8010, 414 | 0x8010, 0x8010, 0x8010, 0x8010, 0x0000, 0x8010, 0x8010, 0x0000, 415 | 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 0x8010, 0x8010, 0x8010, 416 | 0x8010, 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 0x8010, 0x8010, 417 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x8010, 418 | 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 419 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 420 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 421 | 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 422 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x8010, 423 | 0x8010, 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 424 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x8010, 0x8010, 425 | 0x0000, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 426 | 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x0000, 427 | 0x0000, 0x0000, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x0000, 428 | 0x0000, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x0000, 0x0000, 429 | 0x0000, 0x0000, 0x8010, 0x8010, 0x8010, 0x8010, 0x0000, 0x0000, 430 | 0x0000, 0x0000, 0x8010, 0x8010, 0x8010, 0x8010, 0x0000, 0x0000, 431 | 0x0000, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x0000, 0x8010, 432 | 0x8010, 0x0000, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x0000, 433 | 0x0000, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 434 | 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x0000, 435 | 0x0000, 0x0000, 0x8010, 0x8010, 0x0000, 0x8010, 0x0000, 0x8010, 436 | 0x8010, 0x0000, 0x8010, 0x0000, 0x8010, 0x8010, 0x0000, 0x0000, 437 | 0x0000, 0x0000, 0x0000, 0x8010, 0x0000, 0x8010, 0x0000, 0x8010, 438 | 0x8010, 0x0000, 0x8010, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 439 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x0000, 0x8010, 440 | 0x8010, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 441 | }; 442 | 443 | static const uint16_t Editicon[256] = { 444 | // ∙∙∙∙∙∙∙∙∙∙∙∙░∙∙∙ 445 | // ∙∙∙∙∙∙∙∙∙∙∙░░░∙∙ 446 | // ∙∙∙∙∙∙∙∙∙∙░░░░░∙ 447 | // ∙∙∙∙∙∙∙∙∙░∙∙░░░░ 448 | // ∙∙∙∙∙∙∙∙░∙∙░∙░░∙ 449 | // ∙∙∙∙∙∙∙░∙∙░∙∙░∙∙ 450 | // ∙∙∙∙∙∙░∙∙░∙∙░∙∙∙ 451 | // ∙∙∙∙∙░∙∙░∙∙░∙∙∙∙ 452 | // ∙∙∙∙░∙∙░∙∙░∙∙∙∙∙ 453 | // ∙∙∙░∙∙░∙∙░∙∙∙∙∙∙ 454 | // ∙∙░∙∙░∙∙░∙∙∙∙∙∙∙ 455 | // ∙░∙∙░∙∙░∙∙∙∙∙∙∙∙ 456 | // ░∙∙░∙∙░∙∙∙∙∙∙∙∙∙ 457 | // ░░░∙∙░∙∙∙∙∙∙∙∙∙∙ 458 | // ░░░∙░∙∙∙∙∙∙∙∙∙∙∙ 459 | // ░░░░∙∙∙∙∙∙∙∙∙∙∙∙ 460 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 461 | 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 462 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 463 | 0x0000, 0x0000, 0x0000, 0x8010, 0x8010, 0x8010, 0x0000, 0x0000, 464 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 465 | 0x0000, 0x0000, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x0000, 466 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 467 | 0x0000, 0x8010, 0x0000, 0x0000, 0x8010, 0x8010, 0x8010, 0x8010, 468 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 469 | 0x8010, 0x0000, 0x0000, 0x8010, 0x0000, 0x8010, 0x8010, 0x0000, 470 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 471 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 472 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x0000, 473 | 0x0000, 0x8010, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 474 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 475 | 0x8010, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 476 | 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x8010, 477 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 478 | 0x0000, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x8010, 0x0000, 479 | 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 480 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 481 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 482 | 0x0000, 0x8010, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x8010, 483 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 484 | 0x8010, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x8010, 0x0000, 485 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 486 | 0x8010, 0x8010, 0x8010, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 487 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 488 | 0x8010, 0x8010, 0x8010, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 489 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 490 | 0x8010, 0x8010, 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 491 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 492 | }; 493 | 494 | static const uint16_t Deleteicon[256] = { 495 | // ∙∙∙∙∙░░░░░░∙∙∙∙∙ 496 | // ∙∙∙∙░∙∙∙∙∙∙░∙∙∙∙ 497 | // ∙░░░░░░░░░░░░░░∙ 498 | // ░∙∙∙∙∙∙∙∙∙∙∙∙∙∙░ 499 | // ░░░░░░░░░░░░░░░░ 500 | // ∙░∙∙∙∙∙∙∙∙∙∙∙∙░∙ 501 | // ∙░∙░░∙∙░░∙∙░░∙░∙ 502 | // ∙░∙░░∙∙░░∙∙░░∙░∙ 503 | // ∙░∙░░∙∙░░∙∙░░∙░∙ 504 | // ∙░∙░░∙∙░░∙∙░░∙░∙ 505 | // ∙░∙░░∙∙░░∙∙░░∙░∙ 506 | // ∙░∙░░∙∙░░∙∙░░∙░∙ 507 | // ∙░∙░░∙∙░░∙∙░░∙░∙ 508 | // ∙░∙∙░∙∙░░∙∙░∙∙░∙ 509 | // ∙∙░∙∙∙∙∙∙∙∙∙∙░∙∙ 510 | // ∙∙∙░░░░░░░░░░∙∙∙ 511 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x8010, 0x8010, 512 | 0x8010, 0x8010, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 513 | 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 514 | 0x0000, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 515 | 0x0000, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 516 | 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x0000, 517 | 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 518 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 519 | 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 520 | 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 521 | 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 522 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x0000, 523 | 0x0000, 0x8010, 0x0000, 0x8010, 0x8010, 0x0000, 0x0000, 0x8010, 524 | 0x8010, 0x0000, 0x0000, 0x8010, 0x8010, 0x0000, 0x8010, 0x0000, 525 | 0x0000, 0x8010, 0x0000, 0x8010, 0x8010, 0x0000, 0x0000, 0x8010, 526 | 0x8010, 0x0000, 0x0000, 0x8010, 0x8010, 0x0000, 0x8010, 0x0000, 527 | 0x0000, 0x8010, 0x0000, 0x8010, 0x8010, 0x0000, 0x0000, 0x8010, 528 | 0x8010, 0x0000, 0x0000, 0x8010, 0x8010, 0x0000, 0x8010, 0x0000, 529 | 0x0000, 0x8010, 0x0000, 0x8010, 0x8010, 0x0000, 0x0000, 0x8010, 530 | 0x8010, 0x0000, 0x0000, 0x8010, 0x8010, 0x0000, 0x8010, 0x0000, 531 | 0x0000, 0x8010, 0x0000, 0x8010, 0x8010, 0x0000, 0x0000, 0x8010, 532 | 0x8010, 0x0000, 0x0000, 0x8010, 0x8010, 0x0000, 0x8010, 0x0000, 533 | 0x0000, 0x8010, 0x0000, 0x8010, 0x8010, 0x0000, 0x0000, 0x8010, 534 | 0x8010, 0x0000, 0x0000, 0x8010, 0x8010, 0x0000, 0x8010, 0x0000, 535 | 0x0000, 0x8010, 0x0000, 0x8010, 0x8010, 0x0000, 0x0000, 0x8010, 536 | 0x8010, 0x0000, 0x0000, 0x8010, 0x8010, 0x0000, 0x8010, 0x0000, 537 | 0x0000, 0x8010, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x8010, 538 | 0x8010, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x8010, 0x0000, 539 | 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 540 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8010, 0x0000, 0x0000, 541 | 0x0000, 0x0000, 0x0000, 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 542 | 0x8010, 0x8010, 0x8010, 0x8010, 0x8010, 0x0000, 0x0000, 0x0000 543 | }; 544 | 545 | const uint16_t* icons[11] = { 546 | Empty, 547 | Newfileicon, 548 | Newfoldericon, 549 | BLEicon, 550 | KBLayouticon, 551 | Fileicon, 552 | Foldericon, 553 | Previousicon, 554 | Executeicon, 555 | Editicon, 556 | Deleteicon 557 | }; 558 | --------------------------------------------------------------------------------