diff --git a/changes/arrow-keys.md b/changes/arrow-keys.md new file mode 100644 index 00000000..70a2e589 --- /dev/null +++ b/changes/arrow-keys.md @@ -0,0 +1,9 @@ +bump: patch +type: fix +**Held arrow keys register** — `Key.Up`, `Key.Down`, `Key.Left` and `Key.Right` are 128-131. + +They folded to the codes of w, s, a and d, which is what the single per-frame key +(`Input.key`) reports for an arrow. The held-key set has always stored an arrow under +128-131, so `Input.key_down(Key.Up)` tested the W bit and `Input.move_i`'s arrow half never +moved anything. `Input.key` keeps its WASD alias: a game comparing it with `'w'` still +takes the arrows. diff --git a/examples/library/input_arrows.ludic b/examples/library/input_arrows.ludic new file mode 100644 index 00000000..30ec8947 --- /dev/null +++ b/examples/library/input_arrows.ludic @@ -0,0 +1,30 @@ +# input_arrows.ludic — the arrow keys in the held-key set. Key.Up/Down/Left/Right are +# 128-131, the codes the platform stores an arrow under; they used to fold to w/s/a/d, +# so Input.key_down(Key.Up) read the W bit and Input.move_i ignored the arrows. Driven +# headless by injection, the same way the #50 device tests are. +# +# Deterministic; a full run prints: 128 129 130 131 1 0 -1 1 0 +program InputArrows { + function bi(b: bool) -> int { if b { return 1 }; return 0 } + + entry { + print(Key.Up) + print(Key.Down) + print(Key.Left) + print(Key.Right) + + Input.press(Key.Up) # hold the up arrow + Input.poll() + print(bi(Input.key_down(Key.Up))) # 1 — the arrow is held + print(bi(Input.key_down('w'))) # 0 — and it is not W + let m = Input.move_i() + print(m.y) # -1 — move_i takes the arrows as well as WASD + + Input.release(Key.Up) + Input.press(Key.Right) + Input.poll() + let r = Input.move_i() + print(r.x) # 1 + print(bi(Input.key_down(Key.Up))) # 0 — released + } +} diff --git a/selfhost/backend/stdlib/emit_key.ludic b/selfhost/backend/stdlib/emit_key.ludic index a238bb95..626e0f58 100644 --- a/selfhost/backend/stdlib/emit_key.ludic +++ b/selfhost/backend/stdlib/emit_key.ludic @@ -1,7 +1,12 @@ # emit_key.ludic — `Key.Name` -> the key code the input layer delivers, folded at # compile time (like Color.*). Letters are the lowercase character (what the held-key -# set stores), digits their ASCII, plus the specials. Arrow keys alias WASD because the -# platform layer maps them that way; Escape is 27 (0.3, #88). +# set stores), digits their ASCII, plus the specials; Escape is 27 (0.3, #88). +# +# The arrows are 128-131, the codes the platform stores them under in the held-key set +# (cocoa.ll's ev_keyval). They used to fold to w/s/a/d, which is what the single +# per-frame key (Input.key) reports for an arrow - but the held set never had those bits +# for an arrow, so Input.key_down(Key.Up) and Input.move_i's arrow half never fired. +# Input.key keeps its WASD alias, so a game comparing it with 'w' still takes the arrows. function key_lookup(name: pointer) -> int { if (name == "Space") { return 32 } if (name == "Enter") { return 10 } @@ -11,10 +16,10 @@ function key_lookup(name: pointer) -> int { if (name == "Shift") { return 16 } if (name == "Tab") { return 9 } if (name == "Backspace") { return 8 } - if (name == "Up") { return 119 } - if (name == "Down") { return 115 } - if (name == "Left") { return 97 } - if (name == "Right") { return 100 } + if (name == "Up") { return 128 } + if (name == "Down") { return 129 } + if (name == "Left") { return 130 } + if (name == "Right") { return 131 } if (name == "Digit0") { return 48 } if (name == "Digit1") { return 49 } if (name == "Digit2") { return 50 } diff --git a/selfhost/ludicc.seed.ll b/selfhost/ludicc.seed.ll index ec54ad5b..04ff3bbb 100644 --- a/selfhost/ludicc.seed.ll +++ b/selfhost/ludicc.seed.ll @@ -61197,7 +61197,7 @@ ifend23: %t27 = icmp ne i32 %t26, 0 br i1 %t27, label %then24, label %ifend26 then24: - store i32 119, ptr %retval + store i32 128, ptr %retval br label %ret ifend26: %t28 = load ptr, ptr %t0 @@ -61205,7 +61205,7 @@ ifend26: %t30 = icmp ne i32 %t29, 0 br i1 %t30, label %then27, label %ifend29 then27: - store i32 115, ptr %retval + store i32 129, ptr %retval br label %ret ifend29: %t31 = load ptr, ptr %t0 @@ -61213,7 +61213,7 @@ ifend29: %t33 = icmp ne i32 %t32, 0 br i1 %t33, label %then30, label %ifend32 then30: - store i32 97, ptr %retval + store i32 130, ptr %retval br label %ret ifend32: %t34 = load ptr, ptr %t0 @@ -61221,7 +61221,7 @@ ifend32: %t36 = icmp ne i32 %t35, 0 br i1 %t36, label %then33, label %ifend35 then33: - store i32 100, ptr %retval + store i32 131, ptr %retval br label %ret ifend35: %t37 = load ptr, ptr %t0