|
| 1 | +import lvgl as lv |
| 2 | +from micropython import const # NOQA |
| 3 | +import micropython # NOQA # NOQA |
| 4 | +import keypad_framework |
| 5 | + |
| 6 | +KEY_UNKNOWN = 0 |
| 7 | +KEY_BACKSPACE = 8 # LV_KEY_BACKSPACE |
| 8 | +KEY_TAB = 9 # LV_KEY_NEXT |
| 9 | +KEY_CLEAR = 12 |
| 10 | +KEY_RETURN = 13 # LV_KEY_ENTER |
| 11 | +KEY_PAUSE = 19 # |
| 12 | +KEY_ESCAPE = 27 # LV_KEY_ESC |
| 13 | +KEY_SPACE = 32 # " " |
| 14 | +KEY_EXCLAIM = 33 # ! |
| 15 | +KEY_QUOTEDBL = 34 # " |
| 16 | +KEY_HASH = 35 # # |
| 17 | +KEY_DOLLAR = 36 # $ |
| 18 | +KEY_AMPERSAND = 38 # & |
| 19 | +KEY_QUOTE = 39 # ' |
| 20 | +KEY_LEFTPAREN = 40 # ( |
| 21 | +KEY_RIGHTPAREN = 41 # ) |
| 22 | +KEY_ASTERISK = 42 # * |
| 23 | +KEY_PLUS = 43 # + |
| 24 | +KEY_COMMA = 44 # , |
| 25 | +KEY_MINUS = 45 # - |
| 26 | +KEY_PERIOD = 46 # . |
| 27 | +KEY_SLASH = 47 # / |
| 28 | + |
| 29 | +KEY_0 = 48 # 0 |
| 30 | +KEY_1 = 49 # 1 |
| 31 | +KEY_2 = 50 # 2 |
| 32 | +KEY_3 = 51 # 3 |
| 33 | +KEY_4 = 52 # 4 |
| 34 | +KEY_5 = 53 # 5 |
| 35 | +KEY_6 = 54 # 6 |
| 36 | +KEY_7 = 55 # 7 |
| 37 | +KEY_8 = 56 # 8 |
| 38 | +KEY_9 = 57 # 9 |
| 39 | + |
| 40 | +KEY_COLON = 58 # : |
| 41 | +KEY_SEMICOLON = 59 # ; |
| 42 | +KEY_LESS = 60 # < |
| 43 | +KEY_EQUALS = 61 # = |
| 44 | +KEY_GREATER = 62 # > |
| 45 | +KEY_QUESTION = 63 # ? |
| 46 | +KEY_AT = 64 # @ |
| 47 | +KEY_LEFTBRACKET = 91 # [ |
| 48 | +KEY_BACKSLASH = 92 # \ |
| 49 | +KEY_RIGHTBRACKET = 93 # ] |
| 50 | +KEY_CARET = 94 # ^ |
| 51 | +KEY_UNDERSCORE = 95 # _ |
| 52 | +KEY_BACKQUOTE = 96 # ` |
| 53 | +KEY_a = 97 # a |
| 54 | +KEY_z = 122 # z |
| 55 | +KEY_DELETE = 127 # LV_KEY_DEL |
| 56 | + |
| 57 | +# Numeric keypad |
| 58 | +# if MOD_KEY_NUM then it's numbers. |
| 59 | + |
| 60 | +KEYPAD_0 = 256 # 0/INS |
| 61 | +KEYPAD_1 = 257 # 1/END LV_KEY_END |
| 62 | +KEYPAD_2 = 258 # 2/DOWN LV_KEY_DOWN |
| 63 | +KEYPAD_3 = 259 # 3/PAGEDOWN |
| 64 | +KEYPAD_4 = 260 # 4/LEFT LV_KEY_LEFT |
| 65 | +KEYPAD_5 = 261 # 5 |
| 66 | +KEYPAD_6 = 262 # 6/RIGHT LV_KEY_RIGHT |
| 67 | +KEYPAD_7 = 263 # 7/HOME LV_KEY_HOME |
| 68 | +KEYPAD_8 = 264 # 8/UP LV_KEY_UP |
| 69 | +KEYPAD_9 = 265 # 9/PAGEUP |
| 70 | +KEYPAD_PERIOD = 266 # ./DEL LV_KEY_DEL |
| 71 | +KEYPAD_DIVIDE = 267 # / |
| 72 | +KEYPAD_MULTIPLY = 268 # * |
| 73 | +KEYPAD_MINUS = 269 # - |
| 74 | +KEYPAD_PLUS = 270 # + |
| 75 | +KEYPAD_ENTER = 271 # LV_KEY_ENTER |
| 76 | +KEYPAD_EQUALS = 272 # = |
| 77 | + |
| 78 | +# Arrows + Home/End pad |
| 79 | + |
| 80 | +KEY_UP = 273 # LV_KEY_UP |
| 81 | +KEY_DOWN = 274 # LV_KEY_DOWN |
| 82 | +KEY_RIGHT = 275 # LV_KEY_RIGHT |
| 83 | +KEY_LEFT = 276 # LV_KEY_LEFT |
| 84 | +KEY_INSERT = 277 |
| 85 | +KEY_HOME = 278 # LV_KEY_HOME |
| 86 | +KEY_END = 279 # LV_KEY_END |
| 87 | +KEY_PAGEUP = 280 |
| 88 | +KEY_PAGEDOWN = 281 |
| 89 | + |
| 90 | +KEY_F1 = 282 |
| 91 | +KEY_F2 = 283 |
| 92 | +KEY_F3 = 284 |
| 93 | +KEY_F4 = 285 |
| 94 | +KEY_F5 = 286 |
| 95 | +KEY_F6 = 287 |
| 96 | +KEY_F7 = 288 |
| 97 | +KEY_F8 = 289 |
| 98 | +KEY_F9 = 290 |
| 99 | +KEY_F10 = 291 |
| 100 | +KEY_F11 = 292 |
| 101 | +KEY_F12 = 293 |
| 102 | +KEY_F13 = 294 |
| 103 | +KEY_F14 = 295 |
| 104 | +KEY_F15 = 296 |
| 105 | + |
| 106 | +KEY_NUMLOCK = 300 |
| 107 | +KEY_CAPSLOCK = 301 |
| 108 | +KEY_SCROLLOCK = 302 |
| 109 | +KEY_RSHIFT = 303 |
| 110 | +KEY_LSHIFT = 304 |
| 111 | +KEY_RCTRL = 305 |
| 112 | +KEY_LCTRL = 306 |
| 113 | +KEY_RALT = 307 |
| 114 | +KEY_LALT = 308 |
| 115 | +KEY_RMETA = 309 |
| 116 | +KEY_LMETA = 310 |
| 117 | + |
| 118 | +# Left "Windows" key |
| 119 | +KEY_LSUPER = 311 |
| 120 | + |
| 121 | +# Right "Windows" key |
| 122 | +KEY_RSUPER = 312 |
| 123 | + |
| 124 | +# Alt Gr" key |
| 125 | +KEY_MODE = 313 |
| 126 | +# Multi-key compose key |
| 127 | +KEY_COMPOSE = 314 |
| 128 | + |
| 129 | +KEY_HELP = 315 |
| 130 | +KEY_PRINT = 316 |
| 131 | +KEY_SYSREQ = 317 |
| 132 | +KEY_BREAK = 318 |
| 133 | +KEY_MENU = 319 |
| 134 | +# Power Macintosh power key |
| 135 | +KEY_POWER = 320 |
| 136 | +# Some european keyboards |
| 137 | +KEY_EURO = 321 |
| 138 | +# Atari keyboard has Undo |
| 139 | +KEY_UNDO = 322 |
| 140 | + |
| 141 | +MOD_KEY_NONE = 0x0000 |
| 142 | +MOD_KEY_LSHIFT = 0x0001 |
| 143 | +MOD_KEY_RSHIFT = 0x0002 |
| 144 | +MOD_KEY_LCTRL = 0x0040 |
| 145 | +MOD_KEY_RCTRL = 0x0080 |
| 146 | +MOD_KEY_LALT = 0x0100 |
| 147 | +MOD_KEY_RALT = 0x0200 |
| 148 | +MOD_KEY_LMETA = 0x0400 |
| 149 | +MOD_KEY_RMETA = 0x0800 |
| 150 | +MOD_KEY_NUM = 0x1000 |
| 151 | +MOD_KEY_CAPS = 0x2000 |
| 152 | +MOD_KEY_MODE = 0x4000 |
| 153 | +MOD_KEY_CTRL = MOD_KEY_LCTRL | MOD_KEY_RCTRL |
| 154 | +MOD_KEY_SHIFT = MOD_KEY_LSHIFT | MOD_KEY_RSHIFT |
| 155 | +MOD_KEY_ALT = MOD_KEY_LALT | MOD_KEY_RALT |
| 156 | +MOD_KEY_META = MOD_KEY_LMETA | MOD_KEY_RMETA |
| 157 | + |
| 158 | +# SDL keycode ranges |
| 159 | +SDL_NAV_KEY_START = 1073741897 # Insert |
| 160 | +SDL_NAV_KEY_END = 1073741906 # Down Arrow |
| 161 | +SDL_FUNC_KEY_START = 1073741882 # F1 |
| 162 | +SDL_FUNC_KEY_END = 1073741893 # F12 |
| 163 | +SDL_KEYPAD_KEY_START = 1073741908 # Keypad / |
| 164 | +SDL_KEYPAD_KEY_END = 1073741923 # Keypad . |
| 165 | + |
| 166 | +# Shift key mappings for QWERTY layout |
| 167 | +SHIFT_KEY_MAP = { |
| 168 | + KEY_1: KEY_EXCLAIM, # 1 -> ! |
| 169 | + KEY_2: KEY_AT, # 2 -> @ |
| 170 | + KEY_3: KEY_HASH, # 3 -> # |
| 171 | + KEY_4: KEY_DOLLAR, # 4 -> $ |
| 172 | + KEY_5: 37, # 5 -> % (ASCII 37) |
| 173 | + KEY_6: KEY_CARET, # 6 -> ^ |
| 174 | + KEY_7: KEY_AMPERSAND, # 7 -> & |
| 175 | + KEY_8: KEY_ASTERISK, # 8 -> * |
| 176 | + KEY_9: KEY_LEFTPAREN, # 9 -> ( |
| 177 | + KEY_0: KEY_RIGHTPAREN, # 0 -> ) |
| 178 | + KEY_MINUS: KEY_UNDERSCORE, # - -> _ |
| 179 | + KEY_EQUALS: KEY_PLUS, # = -> + |
| 180 | + KEY_LEFTBRACKET: 123, # [ -> { (ASCII 123) |
| 181 | + KEY_RIGHTBRACKET: 125, # ] -> } (ASCII 125) |
| 182 | + KEY_BACKSLASH: 124, # \ -> | (ASCII 124) |
| 183 | + KEY_SEMICOLON: KEY_COLON, # ; -> : |
| 184 | + KEY_QUOTE: KEY_QUOTEDBL, # ' -> " |
| 185 | + KEY_COMMA: KEY_LESS, # , -> < |
| 186 | + KEY_PERIOD: KEY_GREATER, # . -> > |
| 187 | + KEY_SLASH: KEY_QUESTION, # / -> ? |
| 188 | + KEY_BACKQUOTE: 126, # ` -> ~ (ASCII 126) |
| 189 | +} |
| 190 | + |
| 191 | + |
| 192 | +class MposSDLKeyboard(keypad_framework.KeypadDriver): |
| 193 | + |
| 194 | + def __init__(self, *args, **kwargs): # NOQA |
| 195 | + super().__init__() |
| 196 | + self.__last_key = -1 |
| 197 | + self.__current_state = self.RELEASED |
| 198 | + |
| 199 | + self.group = lv.group_create() |
| 200 | + self.group.set_default() # NOQA |
| 201 | + self.set_group(self.group) |
| 202 | + self.set_mode(lv.INDEV_MODE.EVENT) # NOQA |
| 203 | + |
| 204 | + self._py_disp_drv._data_bus.register_keypad_callback(self._keypad_cb) # NOQA |
| 205 | + |
| 206 | + self.paste_text_callback = None |
| 207 | + |
| 208 | + def set_paste_text_callback(self, callback): |
| 209 | + self.paste_text_callback = callback |
| 210 | + |
| 211 | + def set_mode(self, mode): |
| 212 | + self._indev_drv.set_mode(mode) # NOQA |
| 213 | + |
| 214 | + def _keypad_cb(self, *args): |
| 215 | + if len(args) == 5: # Special case for paste |
| 216 | + _, state, key, mod, clipboard_text = args |
| 217 | + print(f"got clipboard paste arg: {clipboard_text}") |
| 218 | + if self.paste_text_callback and state == 1 and key == 118 and mod & MOD_KEY_CTRL: # CTRL-V |
| 219 | + self.paste_text_callback(clipboard_text) |
| 220 | + return |
| 221 | + else: |
| 222 | + _, state, key, mod = args |
| 223 | + print(f"sdl_keyboard.py _keypad_cb got {_}, {state} {key} {mod}") |
| 224 | + |
| 225 | + # Skip modifier keys and SDL-specific large keycodes (>= 2^30), except keypad, nav, and func keys |
| 226 | + if (key in {KEY_LSHIFT, KEY_RSHIFT, KEY_LCTRL, KEY_RCTRL, KEY_LALT, KEY_RALT, |
| 227 | + KEY_LMETA, KEY_RMETA, KEY_LSUPER, KEY_RSUPER, KEY_MODE, KEY_COMPOSE, |
| 228 | + KEY_NUMLOCK, KEY_CAPSLOCK, KEY_SCROLLOCK} or |
| 229 | + (key >= 1 << 30 and not (SDL_NAV_KEY_START <= key <= SDL_NAV_KEY_END or |
| 230 | + SDL_FUNC_KEY_START <= key <= SDL_FUNC_KEY_END or |
| 231 | + SDL_KEYPAD_KEY_START <= key <= SDL_KEYPAD_KEY_END))): |
| 232 | + self.__last_key = -1 # Do not send modifier keys to LVGL |
| 233 | + return |
| 234 | + |
| 235 | + if key == KEY_PAUSE: |
| 236 | + return |
| 237 | + |
| 238 | + # Handle numeric keypad keys (SDL keycodes and original KEYPAD_* range) |
| 239 | + if (KEYPAD_0 <= key <= KEYPAD_EQUALS or |
| 240 | + SDL_KEYPAD_KEY_START <= key <= SDL_KEYPAD_KEY_END): |
| 241 | + if mod & MOD_KEY_NUM: |
| 242 | + mapping = { |
| 243 | + KEYPAD_0: KEY_0, |
| 244 | + KEYPAD_1: KEY_1, |
| 245 | + KEYPAD_2: KEY_2, |
| 246 | + KEYPAD_3: KEY_3, |
| 247 | + KEYPAD_4: KEY_4, |
| 248 | + KEYPAD_5: KEY_5, |
| 249 | + KEYPAD_6: KEY_6, |
| 250 | + KEYPAD_7: KEY_7, |
| 251 | + KEYPAD_8: KEY_8, |
| 252 | + KEYPAD_9: KEY_9, |
| 253 | + KEYPAD_PERIOD: KEY_PERIOD, |
| 254 | + KEYPAD_DIVIDE: KEY_SLASH, |
| 255 | + KEYPAD_MULTIPLY: KEY_ASTERISK, |
| 256 | + KEYPAD_MINUS: KEY_MINUS, |
| 257 | + KEYPAD_PLUS: KEY_PLUS, |
| 258 | + KEYPAD_ENTER: KEY_EQUALS, |
| 259 | + KEYPAD_EQUALS: KEY_EQUALS, |
| 260 | + 1073741908: KEY_SLASH, # Keypad / |
| 261 | + 1073741909: KEY_ASTERISK, # Keypad * |
| 262 | + 1073741910: KEY_MINUS, # Keypad - |
| 263 | + 1073741911: KEY_PLUS, # Keypad + |
| 264 | + 1073741912: lv.KEY.ENTER, # Keypad ENTER |
| 265 | + 1073741913: KEY_1, # Keypad 1 |
| 266 | + 1073741914: KEY_2, # Keypad 2 |
| 267 | + 1073741915: KEY_3, # Keypad 3 |
| 268 | + 1073741916: KEY_4, # Keypad 4 |
| 269 | + 1073741917: KEY_5, # Keypad 5 |
| 270 | + 1073741918: KEY_6, # Keypad 6 |
| 271 | + 1073741919: KEY_7, # Keypad 7 |
| 272 | + 1073741920: KEY_8, # Keypad 8 |
| 273 | + 1073741921: KEY_9, # Keypad 9 |
| 274 | + 1073741922: KEY_0, # Keypad 0 |
| 275 | + 1073741923: KEY_PERIOD # Keypad . |
| 276 | + } |
| 277 | + else: |
| 278 | + mapping = { |
| 279 | + KEYPAD_0: KEY_INSERT, |
| 280 | + KEYPAD_1: lv.KEY.END, # NOQA |
| 281 | + KEYPAD_2: lv.KEY.DOWN, # NOQA |
| 282 | + KEYPAD_3: lv.KEY.PREV, # NOQA |
| 283 | + KEYPAD_4: lv.KEY.LEFT, # NOQA |
| 284 | + KEYPAD_5: KEY_5, |
| 285 | + KEYPAD_6: lv.KEY.RIGHT, # NOQA |
| 286 | + KEYPAD_7: lv.KEY.HOME, # NOQA |
| 287 | + KEYPAD_8: lv.KEY.UP, # NOQA |
| 288 | + KEYPAD_9: lv.KEY.NEXT, # NOQA |
| 289 | + KEYPAD_PERIOD: lv.KEY.DEL, # NOQA |
| 290 | + KEYPAD_DIVIDE: KEY_SLASH, |
| 291 | + KEYPAD_MULTIPLY: KEY_ASTERISK, |
| 292 | + KEYPAD_MINUS: KEY_MINUS, |
| 293 | + KEYPAD_PLUS: KEY_PLUS, |
| 294 | + KEYPAD_ENTER: lv.KEY.ENTER, # NOQA |
| 295 | + KEYPAD_EQUALS: KEY_EQUALS, |
| 296 | + 1073741908: KEY_SLASH, # Keypad / |
| 297 | + 1073741909: KEY_ASTERISK, # Keypad * |
| 298 | + 1073741910: KEY_MINUS, # Keypad - |
| 299 | + 1073741911: KEY_PLUS, # Keypad + |
| 300 | + 1073741912: lv.KEY.ENTER, # Keypad ENTER |
| 301 | + 1073741913: lv.KEY.END, # Keypad 1 |
| 302 | + 1073741914: lv.KEY.DOWN, # Keypad 2 |
| 303 | + 1073741915: lv.KEY.PREV, # Keypad 3 |
| 304 | + 1073741916: lv.KEY.LEFT, # Keypad 4 |
| 305 | + 1073741917: KEY_5, # Keypad 5 |
| 306 | + 1073741918: lv.KEY.RIGHT, # Keypad 6 |
| 307 | + 1073741919: lv.KEY.HOME, # Keypad 7 |
| 308 | + 1073741920: lv.KEY.UP, # Keypad 8 |
| 309 | + 1073741921: lv.KEY.NEXT, # Keypad 9 |
| 310 | + 1073741922: KEY_INSERT, # Keypad 0 |
| 311 | + 1073741923: lv.KEY.DEL # Keypad . |
| 312 | + } |
| 313 | + |
| 314 | + self.__last_key = mapping[key] |
| 315 | + # Apply Shift for keypad symbols if applicable |
| 316 | + if mod & MOD_KEY_SHIFT and self.__last_key in SHIFT_KEY_MAP: |
| 317 | + self.__last_key = SHIFT_KEY_MAP[self.__last_key] |
| 318 | + else: |
| 319 | + mapping = { |
| 320 | + KEY_BACKSPACE: lv.KEY.BACKSPACE, # NOQA |
| 321 | + KEY_TAB: lv.KEY.NEXT, # NOQA |
| 322 | + KEY_RETURN: lv.KEY.ENTER, # NOQA |
| 323 | + KEY_ESCAPE: lv.KEY.ESC, # NOQA |
| 324 | + KEY_DELETE: lv.KEY.DEL, # NOQA |
| 325 | + KEY_UP: lv.KEY.UP, # NOQA |
| 326 | + KEY_DOWN: lv.KEY.DOWN, # NOQA |
| 327 | + KEY_RIGHT: lv.KEY.RIGHT, # NOQA |
| 328 | + KEY_LEFT: lv.KEY.LEFT, # NOQA |
| 329 | + KEY_HOME: lv.KEY.HOME, # NOQA |
| 330 | + KEY_END: lv.KEY.END, # NOQA |
| 331 | + KEY_PAGEDOWN: lv.KEY.PREV, # NOQA |
| 332 | + KEY_PAGEUP: lv.KEY.NEXT, # NOQA |
| 333 | + 1073741897: KEY_INSERT, # SDL Insert |
| 334 | + 1073741898: lv.KEY.HOME, # SDL Home |
| 335 | + 1073741899: lv.KEY.PREV, # SDL PageUp |
| 336 | + 1073741900: lv.KEY.DEL, # SDL Delete (unconfirmed) |
| 337 | + 1073741901: lv.KEY.END, # SDL End |
| 338 | + 1073741902: lv.KEY.NEXT, # SDL PageDown |
| 339 | + 1073741903: lv.KEY.RIGHT, # SDL Right Arrow |
| 340 | + 1073741904: lv.KEY.LEFT, # SDL Left Arrow |
| 341 | + 1073741905: lv.KEY.UP, # SDL Up Arrow |
| 342 | + 1073741906: lv.KEY.DOWN, # SDL Down Arrow |
| 343 | + 1073741882: KEY_F1, # SDL F1 |
| 344 | + 1073741883: KEY_F2, # SDL F2 |
| 345 | + 1073741884: KEY_F3, # SDL F3 |
| 346 | + 1073741885: KEY_F4, # SDL F4 |
| 347 | + 1073741886: KEY_F5, # SDL F5 |
| 348 | + 1073741887: KEY_F6, # SDL F6 |
| 349 | + 1073741888: KEY_F7, # SDL F7 |
| 350 | + 1073741889: KEY_F8, # SDL F8 |
| 351 | + 1073741890: KEY_F9, # SDL F9 |
| 352 | + 1073741891: KEY_F10, # SDL F10 |
| 353 | + 1073741892: KEY_F11, # SDL F11 |
| 354 | + 1073741893: KEY_F12 # SDL F12 |
| 355 | + } |
| 356 | + |
| 357 | + # Handle Shift or Caps Lock for letters and symbols |
| 358 | + if mod & (MOD_KEY_SHIFT | MOD_KEY_CAPS) and KEY_a <= key <= KEY_z: |
| 359 | + # Convert lowercase to uppercase |
| 360 | + self.__last_key = key - 32 # ASCII lowercase to uppercase |
| 361 | + elif mod & MOD_KEY_SHIFT and key in SHIFT_KEY_MAP: |
| 362 | + # Apply Shift mapping for numbers and punctuation |
| 363 | + self.__last_key = SHIFT_KEY_MAP[key] |
| 364 | + else: |
| 365 | + # Use standard mapping or key as-is |
| 366 | + self.__last_key = mapping.get(key, key) |
| 367 | + |
| 368 | + if state: |
| 369 | + self.__current_state = self.PRESSED |
| 370 | + else: |
| 371 | + self.__current_state = self.RELEASED |
| 372 | + |
| 373 | + micropython.schedule(MposSDLKeyboard.read, self) |
| 374 | + |
| 375 | + def _get_key(self): |
| 376 | + return self.__current_state, self.__last_key |
0 commit comments