# Aktions-Engine Dateien: - `config/action.h` - `CMainController.h/.cpp` - `CButton.h/.cpp` ## `SAction` ```cpp struct __attribute__((packed)) SAction { ActionType type; uint16_t data; }; ``` Groesse: 3 Byte. Das `packed` ist zwingend, weil Config v3 bytegenau zwischen Firmware und GUI uebereinstimmen muss. ## `ActionType` | Typ | Bedeutung | `data` | |---|---|---| | `NONE` | keine Aktion | - | | `HID_KEY` | Tastaturtaste ueber USB HID | low byte = keycode, high byte = modifier | | `HID_CONSUMER` | Media/Consumer-HID | usage id | | `HOST_COMMAND` | Event an die GUI | 16-Bit-Command-ID | | `MACRO` | Makro aus `SMacroTable` | slot 0..31 | | `PROFILE_SWITCH` | Profilwechsel | 0..2, `0x00FF` oder `0xFFFF` für nächstes Profil | ## Verhalten bei `KEY_DOWN` | Typ | Effekt | |---|---| | `HID_KEY` | `usb_hid_send_key()` | | `HID_CONSUMER` | `usb_hid_send_consumer()` | | `HOST_COMMAND` | `USB_EVT_KEY_DOWN (0x81)` mit `key_id` und Command-ID senden | | `MACRO` | komplette Sequenz sofort abspielen | | `PROFILE_SWITCH` | Config aus NVM laden, Profil aendern, CRC neu berechnen, speichern, Buttons neu initialisieren | | `NONE` | nichts | ## Verhalten bei `KEY_UP` | Typ | Effekt | |---|---| | `HID_KEY` | `usb_hid_release_key()` | | `HID_CONSUMER` | `usb_hid_release_consumer()` | | `HOST_COMMAND` | `USB_EVT_KEY_UP (0x82)` mit `key_id` und Command-ID senden | | `MACRO` | nichts | | `PROFILE_SWITCH` | nichts | | `NONE` | nichts | ## Hold- und Tap-Modell - MX-Buttons und Encoder-SW benutzen fuer HID und Consumer das Hold-Modell. - Encoder `CW` und `CCW` sind immer diskrete Tap-Events: ```text down -> delay(10 ms) -> up ``` - Makros laufen komplett synchron in der Firmware. Keyboard-Keys und Modifier werden im HID-HAL referenzgezählt. Bis zu sechs unterschiedliche Keyboard-Usages können der Report gleichzeitig abbilden; beim Loslassen einer Action bleiben die übrigen Holds aktiv. Der Consumer-Descriptor kann jeweils nur ein Usage darstellen. Der HAL verwaltet mehrere Holds und zeigt das zuletzt gedrückte aktive Usage; nach dessen Release wird das zuvor aktive Usage wiederhergestellt. ## Host-Commands Der aktuelle Code sendet für jede `HOST_COMMAND`-Action nur: ```text Byte 0 = USB_EVT_KEY_DOWN (0x81) oder USB_EVT_KEY_UP (0x82) Byte 1 = Matrix-Key-ID oder Encoder-ID Byte 2 = Command-ID Low-Byte Byte 3 = Command-ID High-Byte ``` Encoder-Host-Actions senden genau ein Richtungsereignis: `ENC_CW (0x83)` beziehungsweise `ENC_CCW (0x84)`, ebenfalls mit Encoder-ID und Command-ID. Die GUI erhält damit die konfigurierte Action direkt aus dem Event und muss den aktiven Profilstand nicht rekonstruieren. ## Makro-Ausfuehrung Bei `ActionType::MACRO` wird `action.data` als Slot interpretiert. Die Firmware laeuft dann durch bis zu 8 Steps: ```text step.keycode == 0 -> Ende Key-Down 10 ms warten Key-Up 20 ms warten ``` ## Profilwechsel `PROFILE_SWITCH` arbeitet direkt auf der gespeicherten Config: 1. Config aus NVM laden 2. `active_profile` aendern 3. CRC neu berechnen 4. wieder speichern 5. `init_buttons()` Wichtig: `active_profile` liegt im CRC-geschuetzten Bereich. Ohne neue CRC wuerde die Config beim naechsten Laden verworfen. ## Sonderfall Werksreset Die Reset-Kombination uebersteuert das normale Action-System fuer genau zwei Tasten: - `key_id 9` - `key_id 24` Sobald beide gleichzeitig gehalten werden: - ihre normalen Actions werden nicht weiter ausgefuehrt - eventuell bereits gestartete HID-Holds werden sofort freigegeben - die LEDs der beiden Tasten leuchten rot - nach 5 Sekunden wird `perform_factory_reset()` ausgefuehrt