mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-09-26 04:36:40 +00:00
feat(sim): long-press context menu + pixel-perfect real font rendering
Two prototype polish fixes ahead of the website embed work: 1. Holding Enter (the sim's main way into "the rest of the options") did nothing -- the JS bridge's sim_enqueue_key() went straight to enqueueKey(), bypassing UITask::handleLongPress() entirely, so KEY_CONTEXT_MENU could never be reached. Add injectSimKeyLongPress()/ sim_enqueue_key_longpress(), which does route through the real handleLongPress() (same code a real MomentaryButton(pin, 1000, ...) reaches), and wire up press-and-hold (buttons + Enter/Space key) in both web harnesses with the same 1000ms threshold real hardware uses. 2. SimDisplayDriverCanvas::print() drew text with the browser's own system font (ctx.fillText, '8px monospace') instead of the real bitmap font a MeshCore-Solo board renders with OLED_MISC_FIXED_FONT=1 (see solo/heltec_v3/platformio.ini). Vendor the real Adafruit_GFX (unmodified, from the same PlatformIO registry package a real board build pulls) into variants/sim/thirdparty/gfx/, and render print() through the real, shared src/helpers/ui/MiscFixedRenderer.h + MiscFixedFont.h -- byte- identical glyphs to real hardware, not a look-alike. Verified in a real Chromium (Playwright): short Enter -> "CLOCK TOOLS", held Enter -> "CLOCK FIELDS" (gotoDashboardConfig(), proving KEY_CONTEXT_MENU is really reached); font renders as hard square pixels, inverse/selected-row text still punches correctly through a filled bar. Full regression re-run clean: all 3 native envs, wasm companion_radio, and the two-instance + repeater mesh demo (relay routing, DM delivery). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -252,6 +252,14 @@
|
||||
function sendKey(inst, code) {
|
||||
inst.mod.ccall('sim_enqueue_key', null, ['number'], [code]);
|
||||
}
|
||||
function sendKeyLongPress(inst, code) {
|
||||
inst.mod.ccall('sim_enqueue_key_longpress', null, ['number'], [code]);
|
||||
}
|
||||
// Same 1000ms MomentaryButton hold threshold as the single-instance
|
||||
// harness (web/index.html) -- see that file's comment for why holding
|
||||
// OK/Enter matters (real context-menu access via
|
||||
// UITask::handleLongPress()).
|
||||
const LONG_PRESS_MS = 1000;
|
||||
|
||||
async function main() {
|
||||
log('booting instance A (companion_radio)...');
|
||||
@@ -298,10 +306,21 @@
|
||||
setInterval(() => pollRelay(R), 100);
|
||||
|
||||
document.querySelectorAll('button[data-instance]').forEach((btn) => {
|
||||
btn.addEventListener('click', () => {
|
||||
const inst = btn.dataset.instance === 'A' ? A : B;
|
||||
sendKey(inst, Number(btn.dataset.key));
|
||||
const inst = btn.dataset.instance === 'A' ? A : B;
|
||||
const code = Number(btn.dataset.key);
|
||||
let timer = null, longFired = false;
|
||||
btn.addEventListener('pointerdown', (e) => {
|
||||
e.preventDefault();
|
||||
longFired = false;
|
||||
timer = setTimeout(() => { longFired = true; sendKeyLongPress(inst, code); }, LONG_PRESS_MS);
|
||||
});
|
||||
btn.addEventListener('pointerup', () => {
|
||||
if (timer) { clearTimeout(timer); timer = null; }
|
||||
if (!longFired) sendKey(inst, code);
|
||||
});
|
||||
const cancel = () => { if (timer) { clearTimeout(timer); timer = null; } };
|
||||
btn.addEventListener('pointerleave', cancel);
|
||||
btn.addEventListener('pointercancel', cancel);
|
||||
});
|
||||
|
||||
document.getElementById('btn-advert-a').addEventListener('click', () => {
|
||||
|
||||
Reference in New Issue
Block a user