mirror of
https://github.com/ALLFATHER-BV/wadamesh.git
synced 2026-09-26 09:28:01 +00:00
111 lines
3.9 KiB
C++
111 lines
3.9 KiB
C++
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
#pragma once
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
#include "LatchedModifier.h"
|
|
|
|
class TDeckKeyboardState {
|
|
public:
|
|
static constexpr size_t COLS = 5;
|
|
|
|
size_t update(const uint8_t current[COLS], uint32_t now_ms,
|
|
uint8_t* out, size_t out_capacity, bool modifiers_enabled = true) {
|
|
static const char base[COLS][7] = {
|
|
{'q', 'w', '\0', 'a', '\0', ' ', '\0'},
|
|
{'e', 's', 'd', 'p', 'x', 'z', '\0'},
|
|
{'r', 'g', 't', '\0', 'v', 'c', 'f'},
|
|
{'u', 'h', 'y', '\0', 'b', 'n', 'j'},
|
|
{'o', 'l', 'i', '\0', '$', 'm', 'k'},
|
|
};
|
|
static const char symbols[COLS][7] = {
|
|
{'#', '1', '\0', '*', '\0', '\0', '0'},
|
|
{'2', '4', '5', '@', '8', '7', '\0'},
|
|
{'3', '/', '(', '\0', '?', '9', '6'},
|
|
{'_', ':', ')', '\0', '!', ',', ';'},
|
|
{'+', '"', '-', '\0', '\0', '.', '\''},
|
|
};
|
|
auto down = [&](size_t col, uint8_t row) {
|
|
return (current[col] & (uint8_t)(1U << row)) != 0;
|
|
};
|
|
auto pressed = [&](size_t col, uint8_t row) {
|
|
return down(col, row) && (previous_[col] & (uint8_t)(1U << row)) == 0;
|
|
};
|
|
auto released = [&](size_t col, uint8_t row) {
|
|
return !down(col, row) && (previous_[col] & (uint8_t)(1U << row)) != 0;
|
|
};
|
|
|
|
if (!modifiers_enabled) {
|
|
symbol_.baseline(down(0, 2));
|
|
alt_.baseline(down(0, 4));
|
|
}
|
|
if (modifiers_enabled && pressed(0, 2)) symbol_.press();
|
|
if (modifiers_enabled && pressed(0, 4)) alt_.press();
|
|
if (modifiers_enabled && released(0, 2)) symbol_.release(now_ms);
|
|
if (modifiers_enabled && released(0, 4)) alt_.release(now_ms);
|
|
|
|
const bool shift = modifiers_enabled && (down(1, 6) || down(2, 3));
|
|
size_t written = 0;
|
|
auto emit = [&](uint8_t key) {
|
|
if (written < out_capacity) out[written++] = key;
|
|
};
|
|
for (uint8_t row = 0; row < 7; ++row) {
|
|
for (size_t col = 0; col < COLS; ++col) {
|
|
if (!pressed(col, row)) continue;
|
|
if ((col == 0 && (row == 2 || row == 4)) ||
|
|
(col == 1 && row == 6) || (col == 2 && row == 3)) continue;
|
|
const bool physical_alt = modifiers_enabled && alt_.held();
|
|
if (physical_alt) alt_.markHeldUsed();
|
|
// Preserve LilyGO controller shortcuts while raw mode moves ordinary
|
|
// matrix translation into the host. The C3 still handles Alt+B's
|
|
// backlight toggle; suppress its character exactly as key mode does.
|
|
if (physical_alt && col == 3 && row == 4) {
|
|
symbol_.consumeForKey();
|
|
continue;
|
|
}
|
|
if (physical_alt && col == 2 && row == 5) {
|
|
symbol_.consumeForKey();
|
|
emit(0x0C);
|
|
continue;
|
|
}
|
|
if (col == 3 && row == 3) {
|
|
symbol_.consumeForKey(); alt_.consumeForKey(); emit('\r'); continue;
|
|
}
|
|
if (col == 4 && row == 3) {
|
|
symbol_.consumeForKey(); alt_.consumeForKey(); emit('\b'); continue;
|
|
}
|
|
|
|
const bool use_symbols = modifiers_enabled && (symbol_.active() || alt_.latched());
|
|
const char key = use_symbols ? symbols[col][row] : base[col][row];
|
|
if (modifiers_enabled) {
|
|
symbol_.consumeForKey();
|
|
if (!physical_alt) alt_.consumeForKey();
|
|
}
|
|
if (key == '\0') continue;
|
|
char resolved = key;
|
|
if (!use_symbols && shift && resolved >= 'a' && resolved <= 'z') resolved -= 32;
|
|
emit((uint8_t)resolved);
|
|
}
|
|
}
|
|
|
|
for (size_t col = 0; col < COLS; ++col) previous_[col] = current[col] & 0x7F;
|
|
return written;
|
|
}
|
|
|
|
void baseline(const uint8_t current[COLS]) {
|
|
symbol_.baseline((current[0] & (uint8_t)(1U << 2)) != 0);
|
|
alt_.baseline((current[0] & (uint8_t)(1U << 4)) != 0);
|
|
for (size_t col = 0; col < COLS; ++col) previous_[col] = current[col] & 0x7F;
|
|
}
|
|
|
|
void discardModifiers() {
|
|
symbol_.discard();
|
|
alt_.discard();
|
|
}
|
|
|
|
private:
|
|
uint8_t previous_[COLS] = {};
|
|
LatchedModifier symbol_;
|
|
LatchedModifier alt_;
|
|
}; |