M5CardComputer Keyboard
Die Keyboardabfrage ist interrupt gesteuert.
Keyboard initialisieren[Bearbeiten | Quelltext bearbeiten]
- Eine Instanz erzeugen
- die ISR schreiben
- die ISR dem Keyboardinterrupt zuweisen.
kb = MatrixKeyboard() def kb_pressed_event(kb_0): pass kb.set_callback(kb_pressed_event) ... kb.tick() # steht in der MainLoop -> Grund?
Methoden von MatrixKeyboard[Bearbeiten | Quelltext bearbeiten]
- kb.tick()
- ist in der Mainloop erforderlich damit die Keyboard Abfrage funktioniert. Es scheint so, als ob diese Methode die Abfrage durchführt. Wenn sleep() in der Schleife vorkommt, wird nur entsprechend selten oder gar nicht abgefragt.
- Hiermit lässt sich die Keyboard Abfrage auch ein- und ausschalten:
if key_active: kb.tick()
- key_active ist eine Variable die True oder False enthält.
- True: Keyboard wird abgefragt.
- False: Keyboard wird nicht abgefragt.
- kb.get_string()
- gibt des Wert der gedrückten Taste als String zurück
- kb.get_key()
- gibt des Wert der gedrückten Taste als Integer zurück
- kb.is_pressed()
- gibt True zurück, wenn eine Taste gedrückt wurde/ist oder False wenn nicht.
- KeyCode.KEYCODE_BACKSPACE => 8
- KeyCode.KEYCODE_TAB => 9
- KeyCode.KEYCODE_ENTER => 13
- KeyCode.KEYCODE_ESC => 27
- KeyCode.KEYCODE_SPACE => 32
- KeyCode.KEYCODE_DEL => 8
- KeyCode.KEYCODE_LEFT => 180
- KeyCode.KEYCODE_RIGHT => 183
- KeyCode.KEYCODE_UP => 181
- KeyCode.KEYCODE_DOWN => 182
- Konstanten für die Sondertasten
- Funktionieren nicht: KeyCode nicht defined
Keyboard benutzen[Bearbeiten | Quelltext bearbeiten]
Um auf das Keyboard zugreifen zu können ist zum Einen die Initialisierung des Keyboards (s.o.) und zum Anderen die Funktion kb.tick() erforderlich. Erst kb.tick() sorgt dafür, das die Keyboard Abfrage überhaupt erfolgt. Wenn kb.tick() in einer Schleife mit einer sleep() Anweisung steht, wird das Keyboard auch nur in dem Abstand abgefragt!
Die Verarbeitung der Tasteneingabe erfolgt in der ISR. Ihr Name ist beliebig. Er muss nur korrekt an den Interrupt übergeben werden:
kb.set_callback(kb_pressed_event)
Zum Auslesen der gedrückten Taste gibt es 2 Methoden. Mit der Einen wird eine Zahl, mit der Anderen ein Charakter zurückgegeben. Die gedrückte Taste kann nur entweder als Zahl oder als Charakter geholt werden. Erfolgen beide Abfragen direkt hintereinander, so liefert die 2. Abfrage None zurück!
x = kb.get_key() y = kb.get_string()
Keyboard Puffer einsetzen[Bearbeiten | Quelltext bearbeiten]
dissy hat ein Blockly-Programm (UIFlow2) geschrieben, das Zeichen von der Tastatur holt, in einen Puffer schreibt und dann auf dem Display ausgibt. Bei der nächsten Ausgabe wird die alte Zeile nach oben geschoben und die neue Zeile darunter gesetzt. Die Eingabe ist mit Backspace editierbar. Ich habe den Micropythoncode mit seiner Zustimmung hier eingefügt:
import os, sys, io import M5 from M5 import * from hardware import * # Vom GUI-Editor erstellt title0 = None line1 = None line2 = None line3 = None line0 = None buffer = None kb = None _keyBuffer = None L = None _screenLine1 = None _screenLine2 = None x = None _screenLine3 = None _keyBufMaxLen = None keyCode = None keyChar = None # Describe this function... def updateScreen(): global _keyBuffer, L, _screenLine1, _screenLine2, x, _screenLine3, _keyBufMaxLen, keyCode, keyChar, title0, line1, line2, line3, line0, buffer, kb buffer.setText(str(_keyBuffer)) line1.setText(str(_screenLine1)) line2.setText(str(_screenLine2)) line3.setText(str(_screenLine3)) # Describe this function... def key_Delete(): global _keyBuffer, L, _screenLine1, _screenLine2, x, _screenLine3, _keyBufMaxLen, keyCode, keyChar, title0, line1, line2, line3, line0, buffer, kb # We are a bit limited in block options here. # First get the length of the buffer and make sure # there is a character to delete. # Next get a substring of the buffer, excluding the last char. # and store that back into the buffer. L = len(_keyBuffer) if L < 1: return x = L - 1 _keyBuffer = _keyBuffer[:x] buffer.setText(str(_keyBuffer)) Speaker.tone(1000, 50) # Describe this function... def key_Enter(): global _keyBuffer, L, _screenLine1, _screenLine2, x, _screenLine3, _keyBufMaxLen, keyCode, keyChar, title0, line1, line2, line3, line0, buffer, kb # First, scroll the history lines up for visual effect # Then put the buffer into the last line # Finally clear the buffer, play a happy sound _screenLine1 = _screenLine2 _screenLine2 = _screenLine3 _screenLine3 = _keyBuffer _keyBuffer = '' updateScreen() Speaker.tone(2000, 100) def kb_pressed_event(kb_0): global title0, line1, line2, line3, line0, buffer, kb, _keyBuffer, L, _screenLine1, _screenLine2, x, _screenLine3, _keyBufMaxLen, keyCode, keyChar # Check if buffer is full # If so, empty it and play an error sound L = len(_keyBuffer) if L > _keyBufMaxLen: _keyBuffer = '' buffer.setText(str(' ')) Speaker.tone(1000, 750) # We can not get both the key value and key string # (Either get clears the last key pressed) # Start with the special cases by value keyCode = kb.get_key() if keyCode==8: # 8 is the Delete key key_Delete() elif keyCode==9: # 9 is the Tab key, which we will just ignore Speaker.tone(3000, 50) elif keyCode==13: # 13 is the Enter key key_Enter() else: # All other keys end up here, so lets convert the keycode to ascii, # append to the buffer, and play a click. keyChar = '' keyChar = chr(keyCode) _keyBuffer = (str(_keyBuffer) + str(keyChar)) buffer.setText(str(_keyBuffer)) Speaker.tone(3000, 50) updateScreen() def setup(): global title0, line1, line2, line3, line0, buffer, kb, _keyBuffer, L, _screenLine1, _screenLine2, x, _screenLine3, _keyBufMaxLen, keyCode, keyChar M5.begin() title0 = Widgets.Title("Key Buffer Test", 3, 0xffffff, 0x0000FF, Widgets.FONTS.DejaVu18) line1 = Widgets.Label("line1", 10, 25, 1.0, 0xffffff, 0x000000, Widgets.FONTS.DejaVu18) line2 = Widgets.Label("line2", 10, 45, 1.0, 0xffffff, 0x000000, Widgets.FONTS.DejaVu18) line3 = Widgets.Label("line3", 10, 65, 1.0, 0xffffff, 0x000000, Widgets.FONTS.DejaVu18) line0 = Widgets.Line(5, 91, 235, 91, 0xffffff) buffer = Widgets.Label("Hello line buffer world!", 12, 101, 1.0, 0x00caff, 0x000000, Widgets.FONTS.DejaVu18) Widgets.fillScreen(0x000000) kb = MatrixKeyboard() kb.set_callback(kb_pressed_event) _keyBufMaxLen = 20 _keyBuffer = '' title0.setVisible(True) line0.setVisible(True) _screenLine1 = '' _screenLine2 = '' _screenLine3 = '' updateScreen() def loop(): global title0, line1, line2, line3, line0, buffer, kb, _keyBuffer, L, _screenLine1, _screenLine2, x, _screenLine3, _keyBufMaxLen, keyCode, keyChar M5.update() kb.tick() if __name__ == '__main__': try: setup() while True: loop() except (Exception, KeyboardInterrupt) as e: try: from utility import print_error_msg print_error_msg(e) except ImportError: print("please update to latest firmware")
Die Einrückung beträgt hier nur 2 Leerzeichen! Das macht M5Stack so.
Die Keyboard ISR schreiben[Bearbeiten | Quelltext bearbeiten]
Ich habe keinen Weg gefunden die ISR im laufenden Betrieb zu ändern. Deshalb sind bei der Entwicklung der ISR alle in Frage kommenden Fälle zu beachten! Das o.a. Programm von dissy kann als Orientierung dienen, wie die verschiedenen Aufgaben gelöst werden können.
Ich halte ein Modul für sinnvoll, das das Keyboard einrichtet, aber nur bei Bedarf abfragt und die Eingabe zurückgibt.
Ein Modul zur Keyboardabfrage[Bearbeiten | Quelltext bearbeiten]
English (translated with DeepL.com):
Based on dissy's Blockly design, I have created a module that fetches a complete input line (up to Enter) from the keyboard.
When importing, the keyboard is set up.
The keyboard query is started with the function kb_input(...). It is ended by entering Enter and kb_input(...) returns the entered text line.
Two text boxes (Widgets.Label(...)) are required.
In one a text specifying the desired input is output, in the other the input line is displayed.
The length of the input line must also be specified.
To use the module, only kb_input(...) needs to be imported:
Auf der Grundlage von dissy's Blockly Entwurf habe ich ein Modul erstellt das eine komplette Eingabezeile (bis Enter) vom Keyboard holt.
Beim Importieren wird das Keyboard eingerichtet.
Mit der Funktion kb_input(...) wird die Keyboardabfrage gestartet. Mit der Eingabe von Enter wird sie beendet und kb_input(...) gibt die eingegebene Textzeile zurück.
Es werden 2 Textboxen (Widgets.Label(...)) benötigt. In einer wird ein Text ausgegeben, der die gewünschte Eingabe spezifiziert, in der anderen wird die Eingabezeile angezeigt.
Ausserdem muss die Länge der Eingabezeile angegeben werden.
Zur Nutzung des Moduls braucht nur kb_input(...) import zu werden:
from cckeyboard import kb_import
Die Abfrage erfolgt dann so:
eingabezeile = kb_import('EingabeAnzeigeText', Textbox_für_die_Anzeige, Textbox_für_die_Eingabezeile, Maximale_Eingabelänge)
Hier des Script des Modules:
# cckeyboard.py # # english (translated by DeepL.com): # This script is a module for Micropython. # It enables the input of words or numbers with the keyboard of the CardComputer. # # The keyboard query is made with kb_input(message, msg_box, input_box, buff_len). # The input is returned as a string. # # The display takes place in two widgets.label(). # One for a text and the other for the input. # When kb_input(message, msg_box, input_box, buff_len) is called, # the message, the two Widgets.Label() and the buffer length are passed. # # The calling program is responsible for the rest of the display. # This module simply writes to the boxes and displays them. # # The keyboard is initialized when this module is imported. # from cckeyboard import kb_import # # Deutsch: # Dieses Script ist ein Modul für Micropython. # Es ermöglicht die Eingabe von Worten oder Zahlen # mit der Tastatur des CardComputer. # # Die Tastaturabfrage erfolgt mit # kb_input(message, msg_box, input_box, buff_len). # Die Eingabe wird als String zurückgegeben. # # Die Anzeige erfolgt in zwei Widgets.Label(). # Eine für einen Text und die andere für die Eingabe # Beim Aufruf von kb_input(message, msg_box, input_box, buff_len) # wird die Mitteilung, die beiden Widgets.Label() und # die Pufferlänge übergeben. # # Das aufrufende Programm ist für die übrige Gestaltung # des Displays verantwortlich. # Dieses Modul schreibt einfach in die Boxen und zeigt sie an. # # Beim Importieren dieses Modules wird das Keyboard initialisiert. # from cckeyboard import kb_import # file_name = 'cckeyboard.py' author = 'dissy', 'Peter Stöck' kb_version = '01.00.00' date = '16.04.2024' import os, sys, io import M5 from M5 import * from hardware import * # globale Variablen kb_buffer = '' # Puffer für die eingegebenen Werte kb_buf_max_len = None # Max. Pufferlänge kb_input_box = None # Keyboard Instanz initialisieren kb = MatrixKeyboard() # Schreibt Text in ein Widgets.Labell und zeigt es an def update_box(val, box): box.setText(str(val)) box.setVisible(True) # Löscht das letzte Zeichen def kb_delete(): global kb_buffer l = len(kb_buffer) if l < 1: return x = l - 1 kb_buffer = kb_buffer[:x] update_box(kb_buffer, kb_input_box) Speaker.tone(1000, 50) # Bearbeitet die Eingabe von Enter def kb_enter(): global kb_aktive kb_aktive = False Speaker.tone(2000, 100) # ISR def kb_pressed_event(kb_0): global kb_buffer # Puffer voll? l = len(kb_buffer) if l > kb_buf_max_len: kb_buffer = '' update_box(kb_buffer, kb_input_box) Speaker.tone(1000, 750) # Tastendruck holen auswerten und ggf. an den Puffer anhängen keyCode = kb.get_key() if keyCode==8: # 8 is the Delete key kb_delete() elif keyCode==9: # 9 is the Tab key, which we will just ignore Speaker.tone(3000, 50) elif keyCode==13: # 13 is the Enter key kb_enter() else: keyChar = '' keyChar = chr(keyCode) kb_buffer = (str(kb_buffer) + str(keyChar)) Speaker.tone(3000, 50) update_box(kb_buffer, kb_input_box) # Startet die Keyboardabfrage def kb_input(message, msg_box, input_box, buf_len): global kb_aktive, kb_buffer, kb_msg_box, kb_input_box, kb_buf_max_len update_box(message, msg_box) kb_input_box = input_box kb_buffer = '' update_box(kb_buffer, kb_input_box) kb_buf_max_len = buf_len kb_aktive = True while kb_aktive: M5.update() kb.tick() return kb_buffer # Keyboard ISR zuweisen kb.set_callback(kb_pressed_event) # Nun ist alles ist bereit # Demo def test_run(): Widgets.setRotation(1) lab_msg = Widgets.Label("---", 10, 30, 1.0, 0xffffff, 0x0, Widgets.FONTS.DejaVu18) lab_input = Widgets.Label("---", 10, 60, 1.0, 0xffffff, 0x0, Widgets.FONTS.DejaVu24) lab_msg.setVisible(True) lab_input.setVisible(True) inp = ' ' while inp: inp = '' inp = kb_input('Test-Eingabe:', lab_msg, lab_input, 13) print(inp) if __name__ == '__main__': test_run()
Z.Z. müsst Ihr es aus dem Browser kopieren und in einen Editor einfügen. Dort unter dem Namen cckeyboard.py abspeichern.
Wenn Ihr das Modul direkt startet wird eine Demo ausgeführt, mit Ihr es testen könnt.
Keycode Konstanten[Bearbeiten | Quelltext bearbeiten]
Da die eingebauten Keycode-Konstanten nicht funktionieren, habe ich ein eigenes Modul geschrieben.
Es erfordert den Präfix keycodes anstatt KeyCode. Das kann aber durch ändern des Filenamen oder einer entsprechenden Import-Anweisung (siehe Code) geändert werden.
# keycodes.py # use: import keycodes as KeyCode KEYCODE_BACKSPACE = const(8) KEYCODE_TAB = const(9) KEYCODE_ENTER = const(13) KEYCODE_ESC = const(27) KEYCODE_SPACE = const(32) KEYCODE_DEL = const(8) KEYCODE_LEFT = const(180) KEYCODE_RIGHT = const(183) KEYCODE_UP = const(181) KEYCODE_DOWN = const(182)