Merge branch 'fix/arrows-http-backspace': held arrow keys, ludic build Http.* link, macOS Backspace
# Conflicts: # tools/ludic-cli/build.ludic
This commit is contained in:
commit
fb4d904ab6
10 changed files with 1071 additions and 990 deletions
9
changes/arrow-keys.md
Normal file
9
changes/arrow-keys.md
Normal file
|
|
@ -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.
|
||||
7
changes/backspace-key.md
Normal file
7
changes/backspace-key.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
bump: patch
|
||||
type: fix
|
||||
**Backspace fires on macOS** — the Delete key reports `Key.Backspace` (8).
|
||||
|
||||
AppKit gives the key marked delete (kVK_Delete, 51) the character `NSDeleteCharacter`, 127,
|
||||
which is what both the held-key set and the per-frame key received, so `Key.Backspace` never
|
||||
matched. `cocoa.ll` maps key code 51 to 8 in both.
|
||||
8
changes/ludic-build-http.md
Normal file
8
changes/ludic-build-http.md
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
bump: patch
|
||||
type: fix
|
||||
**`ludic build` links `Http.*`** — a program that uses the HTTP client builds through the CLI.
|
||||
|
||||
`compile_app` linked the OpenGL backend when a program named `@lgl_*` but never
|
||||
`runtime/native/http.ll` and Foundation for `@hs_*`, so a `Http.*` program failed to link
|
||||
under `ludic build` / `ludic run` while `ludicc -o` built it. It now links them the same way,
|
||||
windowed and headless.
|
||||
30
examples/library/input_arrows.ludic
Normal file
30
examples/library/input_arrows.ludic
Normal file
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -346,6 +346,7 @@ entry:
|
|||
i32 49, label %vspace
|
||||
i32 36, label %vret
|
||||
i32 53, label %vesc
|
||||
i32 51, label %vbksp
|
||||
]
|
||||
vw: ret i32 128
|
||||
vs: ret i32 129
|
||||
|
|
@ -354,6 +355,9 @@ vd: ret i32 131
|
|||
vspace: ret i32 32
|
||||
vret: ret i32 10
|
||||
vesc: ret i32 27
|
||||
; kVK_Delete (51), the key marked delete or backspace: AppKit reports its character as
|
||||
; NSDeleteCharacter (127), and Key.Backspace is 8
|
||||
vbksp: ret i32 8
|
||||
chars:
|
||||
%sel_ch = call ptr @sel_registerName(ptr @.s_chars)
|
||||
%sel_len = call ptr @sel_registerName(ptr @.s_length)
|
||||
|
|
@ -493,6 +497,7 @@ key:
|
|||
i32 49, label %k_space
|
||||
i32 36, label %k_ret
|
||||
i32 53, label %k_esc
|
||||
i32 51, label %k_bksp
|
||||
]
|
||||
k_w: store i32 119, ptr @W_key br label %forward
|
||||
k_s: store i32 115, ptr @W_key br label %forward
|
||||
|
|
@ -500,6 +505,7 @@ k_a: store i32 97, ptr @W_key br label %forward
|
|||
k_d: store i32 100, ptr @W_key br label %forward
|
||||
k_space: store i32 32, ptr @W_key br label %forward
|
||||
k_ret: store i32 10, ptr @W_key br label %forward
|
||||
k_bksp: store i32 8, ptr @W_key br label %forward
|
||||
k_esc:
|
||||
; Escape is delivered as key 27 and left to the game (pause menus etc.).
|
||||
; It used to force-quit the window, which a shipped game cannot tolerate.
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -48,7 +48,7 @@ function compile_app(src: pointer, out: pointer, mode: int, save: bool) -> bool
|
|||
|
||||
if mode == 2 {
|
||||
if not shq(`{ludicc()} --headless {src} --emit-llvm -o {ll}`) { return false }
|
||||
if not shq(`{cc()} -O2 {ll}{gl_link_flags(ll)}{pbf} -o {out}`) { return false }
|
||||
if not shq(`{cc()} -O2 {ll}{gl_link_flags(ll)}{http_link_flags(ll)}{pbf} -o {out}`) { return false }
|
||||
if not save { shell(`rm -f {ll}`) }
|
||||
return true
|
||||
}
|
||||
|
|
@ -58,7 +58,7 @@ function compile_app(src: pointer, out: pointer, mode: int, save: bool) -> bool
|
|||
# canonical `ludicc -o` path links it only when Audio.* is used.
|
||||
let cocoa = `{home}runtime/native/cocoa.ll`
|
||||
let audio = `{home}runtime/native/audio.ll`
|
||||
if not shq(`{cc()} -O2 {ll} {cocoa} {audio} -framework Cocoa -Wl,-needed_framework,GameController -Wl,-needed_framework,AVFoundation -Wl,-rpath,@loader_path{gl_link_flags(ll)}{pbf} -o {out}`) { return false }
|
||||
if not shq(`{cc()} -O2 {ll} {cocoa} {audio} -framework Cocoa -Wl,-needed_framework,GameController -Wl,-needed_framework,AVFoundation -Wl,-rpath,@loader_path{gl_link_flags(ll)}{http_link_flags(ll)}{pbf} -o {out}`) { return false }
|
||||
if not save { shell(`rm -f {ll}`) }
|
||||
return true
|
||||
}
|
||||
|
|
@ -71,6 +71,14 @@ function gl_link_flags(ll: pointer) -> pointer {
|
|||
return ` {home}runtime/native/gl.ll {home}runtime/native/gl_thunks.ll -framework OpenGL`
|
||||
}
|
||||
|
||||
# A program that uses Http.* calls the @hs_* transport; link http.ll and Foundation only
|
||||
# then, in both modes, as `ludicc -o` does (selfhost/main.ludic). Without it a Http.*
|
||||
# program built through `ludic build` failed to link on every hs_* symbol.
|
||||
function http_link_flags(ll: pointer) -> pointer {
|
||||
if not shq(`grep -q "@hs_" {ll}`) { return "" }
|
||||
return ` {ludic_home()}runtime/native/http.ll -Wl,-needed_framework,Foundation`
|
||||
}
|
||||
|
||||
# the directory part of a path, without the trailing '/' ("" when there is none)
|
||||
function dir_of_path(p: pointer) -> pointer {
|
||||
var last = -1
|
||||
|
|
|
|||
|
|
@ -679,6 +679,7 @@ function cmd_dev_test() -> int {
|
|||
feat_case("library/input_auto", "llq", "2", "input_auto.ludic (#83 the frame loop auto-commits the device layer: Input.active fires with no manual Input.poll)")
|
||||
feat_case("library/input_edge", "xkkxq", "0 11 1 100 0", "input_edge.ludic (#87 Input.key_pressed/key_released edges fire on the transition frame; no double-commit under the frame loop)")
|
||||
feat_case("library/input_movement", "", "1 0 -1 -1 0", "input_movement.ludic (#79 Input.axis_i turns WASD into a -1/0/1 movement intent, no bool->int glue)")
|
||||
feat_case("library/input_arrows", "", "128 129 130 131 1 0 -1 1 0", "input_arrows.ludic (Key.Up/Down/Left/Right are the held set's 128-131: key_down and move_i take the arrows)")
|
||||
feat_case("library/audio", "", "0 0 0 0 1", "audio.ludic (#22 Audio.* load/play/music/volume/pitch/stop/is_playing — headless no-op)")
|
||||
# #6 Http.* — the client links Foundation (macOS-only), so build it through the
|
||||
# canonical `ludicc -o` path (which wires the framework) and gate on Darwin. The
|
||||
|
|
@ -689,6 +690,13 @@ function cmd_dev_test() -> int {
|
|||
if (got == "200 1 5 hello 42 text/plain 404 0") { ok("http.ludic (#6 Http.parse/status/ok/text/header — pure response parser)") }
|
||||
else { bad2("http.ludic", `got [{got}]`) }
|
||||
} else { bad2("http.ludic build", capture_line(`tail -1 {tmp_dir()}/http.out`)) }
|
||||
# and through `ludic build`, which is how a project builds: compile_app used to link
|
||||
# gl.ll when a program named @lgl_* but never http.ll for @hs_*, so this failed to link
|
||||
if shq(`LUDIC_HOME=. bin/ludic build examples/library/http.ludic --headless -o {tmp_dir()}/http_lb > {tmp_dir()}/http_lb.out 2>&1`) {
|
||||
let got2 = capture_line(`{tmp_dir()}/http_lb < /dev/null`)
|
||||
if (got2 == "200 1 5 hello 42 text/plain 404 0") { ok("ludic build links http.ll for a program that uses Http.*") }
|
||||
else { bad2("http.ludic via ludic build", `got [{got2}]`) }
|
||||
} else { bad2("ludic build of an Http.* program", capture_line(`tail -1 {tmp_dir()}/http_lb.out`)) }
|
||||
}
|
||||
|
||||
feat_case("events/recurse", "", "16", "recurse.ludic (EV6: re-entrant emit is depth-bounded, no runaway cycle)")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue