152 Commits
Author SHA1 Message Date
Robin Anderson 391b6d41d9 Merge pull request #35 from VioletTides/idea-template-clearer
Make the idea template quicker to fill in
2026-10-17 01:47:51 -04:00
Robin Anderson ffc5aa022a Make the idea template quicker to fill in
Add a short intro with a link to Discussions, a dropdown for what the
idea is about, example answers in each box, and an optional pick of
the knock kinds the person uses.
2026-10-17 01:43:11 -04:00
Robin Anderson 7898749942 Merge pull request #34 from VioletTides/feature-template
Add an idea template and link issues to Discussions
2026-10-16 20:58:55 -04:00
Robin Anderson 1a7485c8fa Merge pull request #33 from VioletTides/room-view-tests
Test RoomView against a fake Steam debug port
2026-10-16 20:58:43 -04:00
Robin Anderson f55869acf2 Merge pull request #32 from VioletTides/surface-leg-wording
Mention the leg in the surface knock hints
2026-10-16 20:58:30 -04:00
Robin Anderson 086ca05af0 Add an idea template and link issues to Discussions 2026-10-16 20:37:13 -04:00
Robin Anderson f977454de6 Test RoomView against a fake Steam debug port
The fake port serves the bar and popup targets and runs each script in Node
against a fake dashboard bar. The test skips when node is not on PATH.
2026-10-16 20:36:56 -04:00
Robin Anderson b1b217bcbc Say "a surface, like your leg" in the hints 2026-10-16 20:29:29 -04:00
Robin Anderson 616d1d4308 Mention the leg in the surface knock hints 2026-10-16 20:27:50 -04:00
Robin Anderson 8a90745e25 Merge pull request #31 from VioletTides/release-1.0.2
Number the release 1.0.2
v1.0.2
2026-10-16 20:05:21 -04:00
Robin Anderson ff3f150e00 Number the release 1.0.2 2026-10-16 20:03:12 -04:00
Robin Anderson c6a7f8c2cc Merge pull request #30 from VioletTides/leg-knocks
Count knocks on a leg
2026-10-16 20:03:03 -04:00
Robin Anderson ab331f0a85 Say that surface knocks work on a leg 2026-10-16 19:59:18 -04:00
Robin Anderson 9a0d044d3c Let leg knocks in a pair land up to 6 cm apart
Two knocks on a leg spread wider than two knocks on a desk. In a run of
about 40 leg doubles, 7 pairs landed 3.5 to 8.3 cm apart, and the 3 cm
same-spot rule dropped them. At 6 cm, 25 doubles count instead of 20.
play, noise, and straps still give no actions at twice that distance.

tests/data/leg-doubles.csv.gz holds that run.
2026-10-16 19:42:32 -04:00
Robin Anderson e01afc9833 Count knocks on a leg as surface knocks
Knocks on a leg come in faster than knocks on a desk. Most right-hand
leg knocks moved faster than 1.8 m/s 30 ms before the spike, so the
detector threw them out as arm swings. Surface knocks now get their own
limit of 2.2 m/s. Together and headset knocks keep 1.8 m/s, because at
2.2 m/s a together calibration counted one knock in the noise recording.

tests/data/leg.csv.gz holds doubles and triples knocked on a leg with
each hand, headset worn. It gives 16 actions at 2.2 m/s and 9 at 1.8 m/s.
2026-10-16 19:32:42 -04:00
Robin Anderson fae097477b Merge pull request #29 from VioletTides/release-1.0.1
Number the release 1.0.1
v1.0.1
2026-10-16 16:32:38 -04:00
Robin Anderson de976ad256 Number the release 1.0.1 2026-10-16 16:29:04 -04:00
Robin Anderson f880edc51b Merge pull request #28 from VioletTides/test-hook
Add a test hook that drives the app over SSH
2026-10-16 16:25:22 -04:00
Robin Anderson abe798d798 Add a test hook that drives the app over SSH
Development builds read commands appended to
~/.config/knockthru/test-commands: open or close the panel, click a
panel pixel, press a button by name, feed a knock or a double or triple
knock, and save the panel as a PNG. Releases leave it out:
build-arm64.sh adds it only with KNOCKTHRU_TEST_HOOK=1, and the release
workflow never sets that. The host build always has it, so CI compiles it.

On the Frame it drove calibration, the bug report and its recording,
the factory reset and tour, and an update from 1.0.1 to a local
1.0.2-test release through Install and Restart.
2026-10-16 16:23:52 -04:00
Robin Anderson 5ddc7c4787 Merge pull request #27 from VioletTides/review-cleanup
Cut idle CPU, speed up the panel, and split the resident app out of main.cpp
2026-10-16 16:04:45 -04:00
Robin Anderson 5d0ac36d02 Remove scripts/analyze.py
Nothing referenced it, and it read only uncompressed CSV files while the
recordings are gzipped. detector_test with KNOCKTHRU_TEST_VERBOSE=1 prints
every knock in a recording.
2026-10-16 16:00:14 -04:00
Robin Anderson a8a1e50f00 Share the test check helper in tests/check.hpp
Three test programs each defined the same check() and failure count.
update_test now prints the same summary as the other two.
2026-10-16 15:54:26 -04:00
Robin Anderson 0e1fd2afe1 Remove two stray blank lines in overlay_texture.cpp 2026-10-16 15:53:53 -04:00
Robin Anderson fce4b03b29 Parse the true or false settings from one table
Five settings repeated the same three lines. A test now loads each of
them and rejects a value that is not true or false. The test that named
the update check weekly now says daily, which is what the app does.
2026-10-16 15:53:38 -04:00
Robin Anderson ec26507e7c Draw wrapped text in the panel through one helper
Ten places wrapped a string and drew its lines one by one with the same
loop. Panel::paragraph does it once. All panel_preview images are
byte-identical.
2026-10-16 15:52:49 -04:00
Robin Anderson 8fdae6111f Keep the dashboard-changed flag in the app, not the panel state
The panel never read it. The app uses it to log a missing Room View
button once per change.
2026-10-16 15:51:07 -04:00
Robin Anderson cef1a82ac7 Split the resident app out of main.cpp
run() was one 721-line function whose 15 lambdas shared its locals. It is
now an App class in app.cpp with one method per job: slow checks, panel
clicks, knocks, background jobs, and drawing. The shared SteamVR helpers,
pose sampling, haptics, the bug report, and install commands move to
their own files. main.cpp keeps the command-line commands.

Behavior is unchanged. The order of steps in the main loop is the same,
except that a finished recording is collected after the knocks of that
loop instead of before.
2026-10-16 15:50:21 -04:00
Robin Anderson 4489a6334f Decode text once per draw
Canvas::text decoded the UTF-8 string inside measure() and again to draw
it.
2026-10-16 15:39:14 -04:00
Robin Anderson 1467a4af6f Keep the last lines of a log in a deque
tail() erased the front of a vector for every line past the limit, which
moved every kept line each time.
2026-10-16 15:39:14 -04:00
Robin Anderson d5ca7dbe42 Draw each panel icon once and keep it
The header, the bar icon row, and the tour welcome drew the logo from
its outlines on every frame. All panel_preview images are byte-identical.
2026-10-16 15:38:22 -04:00
Robin Anderson 126d97ee33 Fill the inside of rounded rectangles without per-pixel blending
An opaque color replaces the pixels under it, so each row's covered run
is now written directly. Most of a panel frame is tile fill. The main
screen renders in half the time on the PC, and all panel_preview images
are byte-identical.
2026-10-16 15:38:22 -04:00
Robin Anderson 67d6605385 Fold repeated style reads, update checks, and labels into one place each
run() read the Room View style and started the update check job in two
places each. calibrate() repeated the thresholds() format, and three
sites spelled out "double" or "triple".
2026-10-16 15:35:16 -04:00
Robin Anderson a3b12616d2 Share the pose, CSV row, and home folder helpers in main.cpp
The pose-to-vector extraction, the CSV row format, the device names, and
the HOME fallback each had two or three copies. Recordings keep the same
bytes: rows without angular velocity still end in 0,0,0.
2026-10-16 15:34:33 -04:00
Robin Anderson ba6d5cea29 Fetch poses only up to the highest device index in use
GetDeviceToAbsoluteTrackingPose filled all 64 slots every millisecond.
On the Frame the pose thread drops from 2.7% to 1.7% of one core.
2026-10-16 15:33:51 -04:00
Robin Anderson 5be8ee2baf Wake the resident loop every 5 ms while the panel is hidden
The detector judges knocks 50 ms after they happen, so a 1 ms loop gains
nothing while nobody looks at the panel. The pose thread still samples
every millisecond. On the Frame the main thread drops from 4.3% to 1.1%
of one core.
2026-10-16 15:33:51 -04:00
Robin Anderson 0862852cbd Find detector history windows by binary search
History is sorted by time, so poll() starts at the first unjudged sample
and the window helpers start at their window instead of scanning all
0.8 s of samples. Detector output is identical on every recording, and
detector_test runs in 2.2 s instead of 3.6 s.
2026-10-16 15:32:02 -04:00
Robin Anderson 361c270089 Merge pull request #26 from VioletTides/remove-docs
Remove the docs folder and CLAUDE.md
2026-10-16 15:23:23 -04:00
Robin Anderson 56833d5671 Remove the docs folder and CLAUDE.md from the repo
docs/calibration-plan.md was a working plan for local branches, and
docs/knock-signal.md was the tuning log. Both stay in git history.
The README and two code comments no longer point at them.

CLAUDE.md is now in .gitignore, so it stays as a local file only.
2026-10-16 15:17:09 -04:00
Robin Anderson 2e6f1a37c8 Merge pull request #25 from VioletTides/release-1.0.0
Number the first public release 1.0.0
v1.0.0
2026-10-16 14:00:23 -04:00
Robin Anderson 28c22a1b93 Number the first public release 1.0.0
The version defaults in CMakeLists.txt, build-arm64.sh, and package.mjs
say 1.0.0, and so do the README's manual install and build examples.
The README's update GIF goes from 1.0.0 to 1.1.0, not 0.1.0 to 0.2.0.
2026-10-16 13:59:30 -04:00
Robin Anderson 3d05983651 Merge pull request #24 from VioletTides/restart-child
Restart from Settings without taking KnockThru's app key
2026-10-16 13:48:30 -04:00
Robin Anderson 5c3c8e7920 Restart from Settings without taking KnockThru's app key
SteamVR starts the resident app with STEAMVR_APPKEY=local.knockthru.
Restart in Settings starts knockthru-ctl --install, which inherited it,
so SteamVR filed the restarter as KnockThru itself. It then found its
own PID, stopped nothing, and failed with ApplicationAlreadyRunning.

Management commands now clear STEAMVR_APPKEY, find the resident app
through /proc, and write their errors to application.log.
2026-10-16 13:47:12 -04:00
Robin Anderson 681bbbe750 Merge pull request #23 from VioletTides/restart-race
Restart reliably after an update, and switch the bar icon without a lag
2026-10-16 13:33:16 -04:00
Robin Anderson eee50cc118 Restyle the bar icon as soon as Classic bar icon changes
The switch swapped the icon image at once, but the bar's tint followed
only at the next 2 s check. For up to 2 s the old tint showed over the
new icon.
2026-10-16 13:31:53 -04:00
Robin Anderson 2b948965de Wait for SteamVR to clear the old PID before restarting
An update with --update on the Frame stopped KnockThru 0.1.0 at
13:22:12.599, then failed to start 0.1.1 with ApplicationAlreadyRunning.
SteamVR cleared the old PID at 12.635, after the launch call. Restarts
now wait up to 3 s for SteamVR to clear it.
2026-10-16 13:25:38 -04:00
Robin Anderson 8bb5e29674 Merge pull request #22 from VioletTides/tour-enabled-kinds
Show only the knock kinds left on in the tour's knock steps
2026-10-16 13:13:26 -04:00
Robin Anderson 524cb41165 Merge pull request #21 from VioletTides/report-gif-red
Keep the red Reset label red in the README GIFs
2026-10-16 13:09:33 -04:00
Robin Anderson c40dba8de4 Show only the knock kinds left on in the tour's knock steps
The double and triple knock steps cycled through all three kinds, so a
card listing only together and table knocks still showed a headset
knock. With every kind off, the steps still show all three.
2026-10-16 13:08:37 -04:00
Robin Anderson 2dcbea85f6 Merge pull request #20 from VioletTides/triple-knock-doc
Say where a triple knock goes while passthrough is off
2026-10-16 13:06:07 -04:00
Robin Anderson cfea5e0bf4 Keep the red Reset label red in the README GIFs
The Reset label is too small to win an entry in the 127-color GIF palette,
so it came out mustard. An extra solid frame of the error red, seen only
by palettegen, gives it its own entry.
2026-10-16 13:05:35 -04:00