Help: Fn+h lists the keys of the screen you're on, and no screen names its keys any more (#69)
CI / build (pull_request) Successful in 7m22s
Site / build (pull_request) Successful in 14s

Fn+h on any screen, text fields included, and ? outside Text Entry, open a
panel over the content area: the screen's own keys, then the ones that work
everywhere. Every App declares its keys for the state it is in (pages,
viewers, dialogs and text fields answer for themselves); the App manager
opens the panel and takes every key while it is open.

About 30 hint lines are gone, from every App. What stays on a screen is
state. The first-start Setup keeps its hints and teaches the key; a device
set up before gets one Toast, once. The guide and the FAQ open with it.
`key help` over the consoles.

476 host tests (8 new). Checked on the device with key help and screenshots:
the Launcher, all nine Apps and several of their states. 8.5 KB of flash and
40 bytes of static RAM. Decisions Q196 to Q203 in docs/milestones/U1.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
This commit is contained in:
2026-10-07 01:29:51 +02:00
co-authored by Claude Opus 5.5
parent 1c6ae0e04f
commit 7fe8b3d22a
62 changed files with 855 additions and 81 deletions
+39
View File
@@ -220,6 +220,42 @@ void test_shifted_arrow_keys_type_their_symbols_when_not_typing() {
TEST_ASSERT_EQUAL(':', press(m, r)[0].ch);
}
// Issue #69, Q196: Fn+h everywhere, ? when it wouldn't be typed.
void test_fn_h_is_help_in_both_modes() {
for (bool typing : {true, false}) {
KeyMapper m;
m.setTextEntry(typing);
auto ev = press(m, withFn({'h'}));
TEST_ASSERT_EQUAL(1, ev.size());
TEST_ASSERT_EQUAL(static_cast<int>(Key::Help), static_cast<int>(ev[0].key));
}
}
void test_plain_h_still_types() {
for (bool typing : {true, false}) {
KeyMapper m;
m.setTextEntry(typing);
auto ev = press(m, chars({'h'}));
TEST_ASSERT_EQUAL(1, ev.size());
TEST_ASSERT_EQUAL(static_cast<int>(Key::Char), static_cast<int>(ev[0].key));
TEST_ASSERT_EQUAL('h', ev[0].ch);
}
}
void test_question_mark_is_help_only_when_not_typing() {
KeyMapper m;
m.setTextEntry(false);
auto ev = press(m, chars({'?'}));
TEST_ASSERT_EQUAL(1, ev.size());
TEST_ASSERT_EQUAL(static_cast<int>(Key::Help), static_cast<int>(ev[0].key));
release(m);
m.setTextEntry(true);
ev = press(m, chars({'?'}));
TEST_ASSERT_EQUAL(1, ev.size());
TEST_ASSERT_EQUAL(static_cast<int>(Key::Char), static_cast<int>(ev[0].key));
TEST_ASSERT_EQUAL('?', ev[0].ch);
}
int main() {
UNITY_BEGIN();
RUN_TEST(test_plain_character);
@@ -241,5 +277,8 @@ int main() {
RUN_TEST(test_fn_arrows_work_in_both_modes);
RUN_TEST(test_other_characters_still_type_when_not_typing);
RUN_TEST(test_shifted_arrow_keys_type_their_symbols_when_not_typing);
RUN_TEST(test_fn_h_is_help_in_both_modes);
RUN_TEST(test_plain_h_still_types);
RUN_TEST(test_question_mark_is_help_only_when_not_typing);
return UNITY_END();
}