Repository navigation
Add double-click Back gesture and per-app SDK control over it - #1
Conversation
Settings > Controls now lets the user pick Hold or Double-click as the CENTER Back trigger; native apps can additionally suppress delivery (jpp_sdk_set_back_gesture_enabled) or force Hold semantics for themselves regardless of the system preference (jpp_sdk_set_force_hold_back_gesture), so apps that overload CENTER as a primary action button aren't disrupted by accidental long-holds or double-taps.
4f4dd97 to
ccb3be3
Compare
|
@copilot review it |
I reviewed the current PR changes (including keypad behavior, SDK bridge calls, app_main handling, settings persistence, and symbol exports) and didn’t find any high-confidence bugs or security issues. I also reran the host-side checks ( |
set_back_gesture_enabled and set_force_hold_back_gesture were native-C only; add the jppsdk bindings (qstr + module table entries) so MicroPython apps get the same control, and update the docs and testapp_mp accordingly.
Resolves the stale base: apps/testapp_native and apps/testapp_mp were removed from this repo by the apps-repo-split and now live in the sibling jppdos-apps repo, so the PR's edits to them are dropped here and will be re-applied there against the final SDK surface.
Builds on NovaStream2030's double-click Back gesture, keeping the feature
and the Settings > Controls preference intact while moving where the
decision is made.
jpp_keypad_core goes back to being a pure detector: it no longer knows
what "Back" is. It always reports CENTER_SHORT / CENTER_LONG /
CENTER_DOUBLE and carries a single timing knob, detect_double_click,
replacing the back_gesture policy enum in jpp_keypad_config_t. Two
consequences fall out: a hold is now detected in both modes (previously
selecting Double-click meant a hold produced no event at all), and a
short click still in flight when the mode changes is flushed rather than
stranded or replayed.
keypad_task in main/app_main.c becomes the one place that knows both the
user's preference and what the foreground app wants, and turns raw
gestures into a Back action, a raw app key, or nothing.
On the SDK side, jpp_sdk_set_back_gesture_enabled and
jpp_sdk_set_force_hold_back_gesture are replaced by a single
jpp_sdk_claim_center(ctx, mask). Both setters described a mechanism the
app had to reason about — one suppressed delivery, the other overrode
the detector — and neither let an app write code that was blind to the
user's setting. A claim describes intent instead:
claim nothing -> JPP_SDK_KEY_CENTER + JPP_SDK_KEY_BACK, with the
firmware deciding which gesture is Back
claim anything -> the claimed gestures arrive as CENTER_HOLD/_DOUBLE,
BACK stops being delivered, and the app owns its exit
Claiming only HOLD also keeps the short click instant, because nothing
then needs to tell a double-click apart — which is what the force-hold
setter existed to achieve, now as a consequence rather than a flag.
JPP_SDK_KEY_BACK is an alias of the existing JPP_SDK_KEY_CENTER_LONG, so
apps and already-built binaries are unaffected. The new key values and
the center_claim field are appended, never inserted: native apps are
separately-built ELFs loaded from SD and read jpp_sdk_context_t fields
directly (apps/demoscene and apps/games both read canvas_fullscreen), so
inserting into the struct would silently shift every offset they were
compiled against.
Also keeps NovaStream2030's jpp_sdk_confirm symtab fix, which is
unrelated to this feature but a real one: without it any native app
calling jpp_sdk_confirm dies at launch with UNRESOLVED_SYM.
jpp_keypad_poll() takes one ADC sample and derives its clock from
sample_index * poll_interval_ms, so the firmware source compiles natively
and can be stepped a poll at a time. tests/keypad_harness.py builds it
with cc and drives it over ctypes; tests/test_keypad.py covers the timing
that is easy to get wrong and impossible to eyeball:
- a short click is released immediately when nothing needs to tell a
double-click apart, and withheld for double_click_ms when something does
- a second click inside the window reports CENTER_DOUBLE and neither
click leaks an OK; outside the window they stay two separate clicks
- a hold reports CENTER_LONG exactly once, in both modes
- a click already withheld when the mode changes is flushed rather than
dropped or replayed
- direction keys are untouched throughout
Both of the behaviours this branch changed are covered by a test that
fails if the change is reverted, checked by mutating the source and
re-running.
…rule
Rewrites the Key input section of docs/sdk-reference.md around
claim_center, documents JPP_SDK_KEY_BACK / _CENTER_HOLD / _CENTER_DOUBLE
and the CENTER_CLAIM_* constants, and leads with the property that
matters to app authors: an app that claims nothing never reads the user's
Back preference.
AGENTS.md gets the reworked jpp_keypad_core and jpp_sdk_bridge rows, plus
two conventions that did not exist before and cost this branch time:
- CENTER gesture policy lives only in keypad_task(), because it is the
only code that sees both the user preference and the app's claim.
Says explicitly not to push it back into the detector or into
jpp_ui_normalize_action().
- SDK-visible types are append-only. Native apps are separately-built
ELFs that read jpp_sdk_context_t fields directly, so a field inserted
mid-struct shifts offsets in already-deployed .bin files with no
load-time error. This is what the original PR did with its two bools.
Drops the reference to "DOOM-lite" as the reference user for the removed
calls — no such app exists in BUILTIN APPS or under apps/.
Also records the keypad harness in the tests row as the pattern to copy
for other pure jpp_core state machines, and adds a user-facing CHANGELOG
entry for both halves of the feature.
|
(The following was written by Claude Opus 5) The SDK surface
jpp_sdk_claim_center(ctx, JPP_SDK_CENTER_CLAIM_HOLD);Both setters described a mechanism the app author had to reason about — one suppressed delivery, the other overrode the detector — and with either of them an app still had to think about what the user's Back preference was doing to it. A claim describes intent instead:
Claiming only The layering
Two bugs fall out of the restructure:
One thing worth flagging for next timeThe two Also in these commits
Verification
Not yet verified on hardware — worth a pass on a real unit before this lands, particularly the double-click feel with the 300 ms window and hold-to-pause in a claiming app. |
Summary
jpp_keypad_core.jpp_sdk_set_back_gesture_enabled()to suppress delivery of the gesture entirely, orjpp_sdk_set_force_hold_back_gesture()to force Hold semantics for themselves regardless of the system-wide preference — for apps that overload CENTER as a primary action button (e.g. a "fire" button) so accidental long-holds/double-taps aren't misread as Back.testapp_nativeexercises the newjpp_sdk_set_back_gesture_enabledcall from its System test menu.AGENTS.md(keypad core, settings screen, SDK bridge, conventions) anddocs/sdk-reference.md(new Key input entries).Test plan
idf.py buildvia Docker — clean build, verified on hardware (ESP32-C6)jpp_sdk_set_back_gesture_enabled/jpp_sdk_set_force_hold_back_gesturesymbol table entries are picked up correctly by any downstream native app builds