Skip to content

Support level-coded SW input on hardware reporting KEY_1 (Stargate) - #107

Merged
RapierXbox merged 2 commits into
RapierXbox:mainfrom
phischmi:fix/sw-input-level-coded-key
Sep 22, 2026
Merged

RapierXbox merged 2 commits into
RapierXbox:mainfrom
phischmi:fix/sw-input-level-coded-key

Conversation

@phischmi

Copy link
Copy Markdown
Contributor

Problem

On a Wall Display Stargate (SAWD-0A1XX10EU1) the SW terminal does nothing: no switch_state on MQTT, no relay toggle, no JS event. The key event is delivered to the app — dumpsys input shows it reaching MainActivity — but it is dropped.

The cause is that the terminal is reported in a second scheme that the keymap does not know.

The implemented scheme is edge coded: each contact transition is a short key pulse whose keycode carries the direction (141/KEY_F11 rising, 142/KEY_F12 falling), verified on the X1i.

The Stargate's gpio_keys node declares exactly one code and nothing else:

N: Name="gpio_keys"
B: EV=3          (EV_SYN + EV_KEY, no EV_SW)
B: KEY=4         (bit 2 -> KEY_1, scan code 2, Android keycode 8)

Here the contact level is the key state — down while the line is active, up when it goes inactive, with Android auto-repeating the down while it is held:

action=0 keyCode=8 repeatCount=44..49   <- auto repeat while held (~3 s)
action=1 keyCode=8 repeatCount=0        <- release

levelForAndroidKey(8) returns null, so SwInputHandler declines the key, MainActivity falls through to super.dispatchKeyEvent() and the edge is lost.

Change

Decode both schemes in the keymap and handle them on both intake paths — the activity KeyEvents and the native input monitor including its getevent fallback. Everything downstream is unchanged: SwInputStateMachine applies the configured mode, publishSwitch() sends PRESS/RELEASE, the relay and JS paths are untouched.

No per-model flag. The two code sets are disjoint, so a model reporting either scheme works without a DeviceModel entry — including Atlantis and Pegasus, which I cannot verify for lack of hardware.

KEYCODE_1 is an ordinary digit on a real keyboard, so unlike the F11/F12 pulses it is only claimed when the model has an SW input and the reporting input device has no letter keys (hasKeys(KEYCODE_Q)). gpio_keys declares the one SW code; a USB or Bluetooth keyboard keeps its digit and passes through to the webview. The verdict is memoized per deviceId, so there is no lookup per auto-repeat.

Verification

On a Stargate, with the real wired push-button, swInputMode0=1 (Button):

14:54:35.395  input=false relay=false     <- baseline
14:55:04.981  input=false relay=true      <- relay toggles on the rising edge
14:55:05.112  input=true  relay=true      <- contact held
14:55:08.108  input=false relay=true      <- released ~3.0 s later, relay stays

GET /device/input?num=0 reports state: true for the full hold and false on release. Verified with the screensaver activity in front as well as MainActivity, since both route through SwInputHandler. Unit tests cover the extended keymap.

Note on the first commit

481a1f6 is unrelated to the SW input: 3d13d7f added a Build.VERSION.SDK_INT check to WakeWordDetector.buildInterpreter() without importing android.os.Build, which breaks compileDebugJavaWithJavac on main. It is in here because the branch does not build without it — happy to split it into its own PR if you prefer.

🤖 Generated with Claude Code

phischmi and others added 2 commits September 16, 2026 15:00
3d13d7f added a Build.VERSION.SDK_INT check to buildInterpreter() without
importing android.os.Build, which breaks compileDebugJavaWithJavac on main.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The SW terminal is reported in one of two schemes. The implemented one is
edge coded: each contact transition is a short key pulse whose keycode
carries the direction (141/KEY_F11 rising, 142/KEY_F12 falling), verified
on the X1i.

The Wall Display "Stargate" (SAWD-0A1XX10EU1) uses a second scheme. Its
gpio_keys node declares a single code, KEY_1 (scan code 2, Android keycode
8), and the contact level is the key state itself: down while the line is
active, up when it goes inactive, with Android auto-repeating the down
while it is held. levelForAndroidKey() returned null for that keycode, so
SwInputHandler declined it, MainActivity fell through to
super.dispatchKeyEvent() and the input was silently dropped - no
switch_state, no relay, no JS event.

Decode both schemes in the keymap and handle them on both intake paths
(activity KeyEvents and the native input monitor incl. the getevent
fallback). No per-model flag: the code sets are disjoint, so a model
reporting either one works without a DeviceModel entry.

KEYCODE_1 is an ordinary digit on a real keyboard, so unlike the F11/F12
pulses it is only claimed when the model has an SW input and the reporting
input device has no letter keys; anything that can type text keeps its
digit and passes through to the webview.

Verified on a Stargate: press toggles the relay on the rising edge,
GET /device/input reports state true for the full hold and false on
release, in the screensaver activity as well as MainActivity.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@RapierXbox RapierXbox closed this Sep 22, 2026
@RapierXbox RapierXbox reopened this Sep 22, 2026
@RapierXbox
RapierXbox merged commit 7269f2d into RapierXbox:main Sep 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants