feat: every key on the keyboard is bindable - the F-row, the six-pack, Caps Lock and the numpad
The platform gave these keys no code at all, so a game's rebinding screen could not take one and nothing said why. Windows asked the active layout what they type and got nothing (w_vk_char answers 0 for a key with no character); macOS let them fall through to charactersIgnoringModifiers, which reports NSF1FunctionKey and its neighbours at 0xF704 and up - outside the 256-bit held set either way. w_keyval and ev_keyval now name them, with the same codes on both: 132-143 F1-F12, 144-149 Home / End / PageUp / PageDown / Insert / Delete, 150 Caps Lock, 152-161 the numpad digits, 162-166 its * + - . and /. The numpad's Enter is Enter. Key.F1, Key.Home, Key.Numpad0 and the rest fold at compile time, and Input.key_label names them without asking the layout - a key that types nothing is called the same thing on every layout. examples/library/input_typeless_keys.ludic covers the codes, the names, the held set and the press edge; 150 passed in ludic-dev test, 33 in selfhost-test. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
9dfa2951f6
commit
4979cc0c94
11 changed files with 21327 additions and 20462 deletions
19
changes/typeless-keys.md
Normal file
19
changes/typeless-keys.md
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
bump: minor
|
||||||
|
type: feat
|
||||||
|
**Every key on the keyboard is bindable** — the F-row, Home/End/PageUp/PageDown,
|
||||||
|
Insert/Delete, Caps Lock and the numpad reach a game as codes 132-166.
|
||||||
|
|
||||||
|
Until now the platform gave them no code at all, so a game's rebinding screen could
|
||||||
|
not take one and nothing said why. Windows asked the active layout what they type and
|
||||||
|
got nothing back (`w_vk_char` answers 0 for a key with no character); macOS let them
|
||||||
|
fall through to `charactersIgnoringModifiers`, which reports `NSF1FunctionKey` and its
|
||||||
|
neighbours at 0xF704 and up - outside the 256-bit held set either way.
|
||||||
|
|
||||||
|
- **The codes are the same on both platforms**: 132-143 are F1-F12, 144-149 are Home,
|
||||||
|
End, PageUp, PageDown, Insert and Delete, 150 is Caps Lock, 152-161 are the numpad
|
||||||
|
digits and 162-166 its `*`, `+`, `-`, `.` and `/`. The numpad's Enter is Enter.
|
||||||
|
- **`Key.F1`, `Key.Home`, `Key.Numpad0`** and the rest fold at compile time like the
|
||||||
|
other named keys.
|
||||||
|
- **`Input.key_label`** names them - "F1", "Home", "CapsLock", "Num 0", "Num /" - and
|
||||||
|
does *not* ask the layout, because a key that types nothing is called the same thing
|
||||||
|
on every layout.
|
||||||
|
|
@ -11,7 +11,7 @@ ns: Input
|
||||||
member: key_down
|
member: key_down
|
||||||
---
|
---
|
||||||
|
|
||||||
Returns whether a physical <code>key</code> is held this frame — from the platform when windowed, from the polled key when headless, and from <a href="input-press.html"><code>Input.press</code></a> injection on any target. Unlike the single-key <a href="input-down.html"><code>Input.down</code></a>, several keys can be held at once (move left <em>and</em> jump).
|
Returns whether a physical <code>key</code> is held this frame — from the platform when windowed, from the polled key when headless, and from <a href="input-press.html"><code>Input.press</code></a> injection on any target. Unlike the single-key <a href="input-down.html"><code>Input.down</code></a>, several keys can be held at once (move left <em>and</em> jump). Every key on the keyboard has a code: letters, digits and punctuation are their US-layout character, Space, Enter, Esc, Tab, Backspace, Shift, Ctrl and Alt their usual ones, the arrows 128-131, and the keys that type nothing 132-166 - F1-F12 at 132, Home, End, PageUp, PageDown, Insert and Delete at 144, Caps Lock at 150, the numpad digits at 152 and its <code>*</code>, <code>+</code>, <code>-</code>, <code>.</code> and <code>/</code> at 162. <code>Key.F1</code>, <code>Key.Home</code> and <code>Key.Numpad0</code> name them.
|
||||||
|
|
||||||
```ludic
|
```ludic
|
||||||
program Demo {
|
program Demo {
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ ns: Input
|
||||||
member: key_label
|
member: key_label
|
||||||
---
|
---
|
||||||
|
|
||||||
Returns the name to show for <code>key</code>. The letter, digit and punctuation codes that <a href="input-key_down.html"><code>Input.key_down</code></a> reads are <em>physical</em> keys, named for what they type on a US layout: <code>'w'</code> is the key above <code>'s'</code> on every keyboard, whatever layout, language, input method or Caps Lock state the player has. So WASD is always under the left hand, and the label is what that key types in the player's layout - <code>"W"</code> on QWERTY, <code>"Z"</code> on AZERTY. Space, Enter, Esc, Tab, Backspace, Shift, Ctrl, Alt and the arrows get words, and a code with no name returns <code>""</code>.
|
Returns the name to show for <code>key</code>. The letter, digit and punctuation codes that <a href="input-key_down.html"><code>Input.key_down</code></a> reads are <em>physical</em> keys, named for what they type on a US layout: <code>'w'</code> is the key above <code>'s'</code> on every keyboard, whatever layout, language, input method or Caps Lock state the player has. So WASD is always under the left hand, and the label is what that key types in the player's layout - <code>"W"</code> on QWERTY, <code>"Z"</code> on AZERTY. Space, Enter, Esc, Tab, Backspace, Shift, Ctrl, Alt and the arrows get words, and a code with no name returns <code>""</code>. The keys that type no character - F1-F12, Home, End, PageUp, PageDown, Insert, Delete, Caps Lock and the numpad, codes 132-166 - are named <code>"F1"</code>, <code>"Home"</code>, <code>"CapsLock"</code>, <code>"Num 0"</code>, <code>"Num /"</code> and so on, and the layout is <em>not</em> asked: a key that types nothing is called the same thing on every layout.
|
||||||
|
|
||||||
On Windows the label is read from the active layout. Headless, on macOS and in the browser it is the US character, upper case.
|
On Windows the label is read from the active layout. Headless, on macOS and in the browser it is the US character, upper case.
|
||||||
|
|
||||||
|
|
|
||||||
38
examples/library/input_typeless_keys.ludic
Normal file
38
examples/library/input_typeless_keys.ludic
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
# input_typeless_keys.ludic — the keys that type no character: the F-row, the six-pack,
|
||||||
|
# Caps Lock and the numpad. Until 0.22 the platform gave them no code at all - Windows
|
||||||
|
# asked the layout what they type and got nothing, macOS got NSF1FunctionKey (0xF704 and
|
||||||
|
# up, outside the 256-bit held set) - so a game could not bind one and nothing said why.
|
||||||
|
# They are codes 132-166 now, the same on both, with a name that is not asked of the
|
||||||
|
# layout because it is the same on every layout.
|
||||||
|
#
|
||||||
|
# Deterministic; a full run prints: 132 143 144 149 150 152 161 F1 F12 Home Delete CapsLock Num 0 Num / 1 0 1
|
||||||
|
program InputTypelessKeys {
|
||||||
|
function bi(b: bool) -> int { if b { return 1 }; return 0 }
|
||||||
|
|
||||||
|
entry {
|
||||||
|
print(Key.F1)
|
||||||
|
print(Key.F12)
|
||||||
|
print(Key.Home)
|
||||||
|
print(Key.Delete)
|
||||||
|
print(Key.CapsLock)
|
||||||
|
print(Key.Numpad0)
|
||||||
|
print(Key.Numpad9)
|
||||||
|
|
||||||
|
print(Input.key_label(Key.F1))
|
||||||
|
print(Input.key_label(Key.F12))
|
||||||
|
print(Input.key_label(Key.Home))
|
||||||
|
print(Input.key_label(Key.Delete))
|
||||||
|
print(Input.key_label(Key.CapsLock))
|
||||||
|
print(Input.key_label(Key.Numpad0))
|
||||||
|
print(Input.key_label(Key.NumpadDivide))
|
||||||
|
|
||||||
|
Input.press(Key.F5) # hold F5
|
||||||
|
Input.poll()
|
||||||
|
print(bi(Input.key_down(Key.F5))) # 1 — it is in the held set like any other key
|
||||||
|
print(bi(Input.key_down(Key.F6))) # 0 — and only that one
|
||||||
|
Input.release(Key.F5)
|
||||||
|
Input.press(Key.PageDown)
|
||||||
|
Input.poll()
|
||||||
|
print(bi(Input.key_pressed(Key.PageDown))) # 1 — the edge fires for it too
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -380,6 +380,45 @@ special:
|
||||||
i32 36, label %vret
|
i32 36, label %vret
|
||||||
i32 53, label %vesc
|
i32 53, label %vesc
|
||||||
i32 51, label %vbksp
|
i32 51, label %vbksp
|
||||||
|
; the keys that type nothing: charactersIgnoringModifiers answers them with
|
||||||
|
; NSF1FunctionKey and its neighbours, 0xF700 and up, which is outside the 256-bit held
|
||||||
|
; set - so a game could not bind an F-key, Home, Delete or the numpad at all. They get
|
||||||
|
; the same codes win32.ll's w_keyval gives them.
|
||||||
|
i32 122, label %vf1
|
||||||
|
i32 120, label %vf2
|
||||||
|
i32 99, label %vf3
|
||||||
|
i32 118, label %vf4
|
||||||
|
i32 96, label %vf5
|
||||||
|
i32 97, label %vf6
|
||||||
|
i32 98, label %vf7
|
||||||
|
i32 100, label %vf8
|
||||||
|
i32 101, label %vf9
|
||||||
|
i32 109, label %vf10
|
||||||
|
i32 103, label %vf11
|
||||||
|
i32 111, label %vf12
|
||||||
|
i32 115, label %vhome
|
||||||
|
i32 119, label %vend
|
||||||
|
i32 116, label %vpgup
|
||||||
|
i32 121, label %vpgdn
|
||||||
|
i32 114, label %vins
|
||||||
|
i32 117, label %vdel
|
||||||
|
i32 57, label %vcaps
|
||||||
|
i32 82, label %vnp0
|
||||||
|
i32 83, label %vnp1
|
||||||
|
i32 84, label %vnp2
|
||||||
|
i32 85, label %vnp3
|
||||||
|
i32 86, label %vnp4
|
||||||
|
i32 87, label %vnp5
|
||||||
|
i32 88, label %vnp6
|
||||||
|
i32 89, label %vnp7
|
||||||
|
i32 91, label %vnp8
|
||||||
|
i32 92, label %vnp9
|
||||||
|
i32 67, label %vnpmul
|
||||||
|
i32 69, label %vnpadd
|
||||||
|
i32 78, label %vnpsub
|
||||||
|
i32 65, label %vnpdec
|
||||||
|
i32 75, label %vnpdiv
|
||||||
|
i32 76, label %vret
|
||||||
]
|
]
|
||||||
vw: ret i32 128
|
vw: ret i32 128
|
||||||
vs: ret i32 129
|
vs: ret i32 129
|
||||||
|
|
@ -388,6 +427,40 @@ vd: ret i32 131
|
||||||
vspace: ret i32 32
|
vspace: ret i32 32
|
||||||
vret: ret i32 10
|
vret: ret i32 10
|
||||||
vesc: ret i32 27
|
vesc: ret i32 27
|
||||||
|
vf1: ret i32 132
|
||||||
|
vf2: ret i32 133
|
||||||
|
vf3: ret i32 134
|
||||||
|
vf4: ret i32 135
|
||||||
|
vf5: ret i32 136
|
||||||
|
vf6: ret i32 137
|
||||||
|
vf7: ret i32 138
|
||||||
|
vf8: ret i32 139
|
||||||
|
vf9: ret i32 140
|
||||||
|
vf10: ret i32 141
|
||||||
|
vf11: ret i32 142
|
||||||
|
vf12: ret i32 143
|
||||||
|
vhome: ret i32 144
|
||||||
|
vend: ret i32 145
|
||||||
|
vpgup: ret i32 146
|
||||||
|
vpgdn: ret i32 147
|
||||||
|
vins: ret i32 148
|
||||||
|
vdel: ret i32 149
|
||||||
|
vcaps: ret i32 150
|
||||||
|
vnp0: ret i32 152
|
||||||
|
vnp1: ret i32 153
|
||||||
|
vnp2: ret i32 154
|
||||||
|
vnp3: ret i32 155
|
||||||
|
vnp4: ret i32 156
|
||||||
|
vnp5: ret i32 157
|
||||||
|
vnp6: ret i32 158
|
||||||
|
vnp7: ret i32 159
|
||||||
|
vnp8: ret i32 160
|
||||||
|
vnp9: ret i32 161
|
||||||
|
vnpmul: ret i32 162
|
||||||
|
vnpadd: ret i32 163
|
||||||
|
vnpsub: ret i32 164
|
||||||
|
vnpdec: ret i32 165
|
||||||
|
vnpdiv: ret i32 166
|
||||||
; kVK_Delete (51), the key marked delete or backspace: AppKit reports its character as
|
; kVK_Delete (51), the key marked delete or backspace: AppKit reports its character as
|
||||||
; NSDeleteCharacter (127), and Key.Backspace is 8
|
; NSDeleteCharacter (127), and Key.Backspace is 8
|
||||||
vbksp: ret i32 8
|
vbksp: ret i32 8
|
||||||
|
|
|
||||||
|
|
@ -390,6 +390,22 @@ function input_key_label(k: int) -> string {
|
||||||
if k == 129 { return "Down" }
|
if k == 129 { return "Down" }
|
||||||
if k == 130 { return "Left" }
|
if k == 130 { return "Left" }
|
||||||
if k == 131 { return "Right" }
|
if k == 131 { return "Right" }
|
||||||
|
# the keys that type nothing on any layout, so there is no character to show: the name is
|
||||||
|
# the same everywhere, which is why it is not asked of the layout
|
||||||
|
if k >= 132 and k <= 143 { return "F" + string(k - 131) }
|
||||||
|
if k == 144 { return "Home" }
|
||||||
|
if k == 145 { return "End" }
|
||||||
|
if k == 146 { return "PageUp" }
|
||||||
|
if k == 147 { return "PageDown" }
|
||||||
|
if k == 148 { return "Insert" }
|
||||||
|
if k == 149 { return "Delete" }
|
||||||
|
if k == 150 { return "CapsLock" }
|
||||||
|
if k >= 152 and k <= 161 { return "Num " + string(k - 152) }
|
||||||
|
if k == 162 { return "Num *" }
|
||||||
|
if k == 163 { return "Num +" }
|
||||||
|
if k == 164 { return "Num -" }
|
||||||
|
if k == 165 { return "Num ." }
|
||||||
|
if k == 166 { return "Num /" }
|
||||||
var c = 0
|
var c = 0
|
||||||
if is_windowed() { c = win_key_char(k) }
|
if is_windowed() { c = win_key_char(k) }
|
||||||
if c <= 0 and k > 32 and k < 127 {
|
if c <= 0 and k > 32 and k < 127 {
|
||||||
|
|
|
||||||
|
|
@ -425,6 +425,42 @@ byvk:
|
||||||
i32 18, label %alt
|
i32 18, label %alt
|
||||||
i32 8, label %bksp
|
i32 8, label %bksp
|
||||||
i32 9, label %tab
|
i32 9, label %tab
|
||||||
|
; the keys that type nothing, so w_vk_char answers 0 for them and they had no code at
|
||||||
|
; all: a game could not bind an F-key, Home, Delete or the numpad, and nothing said why
|
||||||
|
i32 112, label %f1
|
||||||
|
i32 113, label %f2
|
||||||
|
i32 114, label %f3
|
||||||
|
i32 115, label %f4
|
||||||
|
i32 116, label %f5
|
||||||
|
i32 117, label %f6
|
||||||
|
i32 118, label %f7
|
||||||
|
i32 119, label %f8
|
||||||
|
i32 120, label %f9
|
||||||
|
i32 121, label %f10
|
||||||
|
i32 122, label %f11
|
||||||
|
i32 123, label %f12
|
||||||
|
i32 36, label %khome
|
||||||
|
i32 35, label %kend
|
||||||
|
i32 33, label %kpgup
|
||||||
|
i32 34, label %kpgdn
|
||||||
|
i32 45, label %kins
|
||||||
|
i32 46, label %kdel
|
||||||
|
i32 20, label %kcaps
|
||||||
|
i32 96, label %np0
|
||||||
|
i32 97, label %np1
|
||||||
|
i32 98, label %np2
|
||||||
|
i32 99, label %np3
|
||||||
|
i32 100, label %np4
|
||||||
|
i32 101, label %np5
|
||||||
|
i32 102, label %np6
|
||||||
|
i32 103, label %np7
|
||||||
|
i32 104, label %np8
|
||||||
|
i32 105, label %np9
|
||||||
|
i32 106, label %npmul
|
||||||
|
i32 107, label %npadd
|
||||||
|
i32 109, label %npsub
|
||||||
|
i32 110, label %npdec
|
||||||
|
i32 111, label %npdiv
|
||||||
]
|
]
|
||||||
up: ret i32 128
|
up: ret i32 128
|
||||||
down: ret i32 129
|
down: ret i32 129
|
||||||
|
|
@ -438,6 +474,40 @@ ctrl: ret i32 17
|
||||||
alt: ret i32 18
|
alt: ret i32 18
|
||||||
bksp: ret i32 8
|
bksp: ret i32 8
|
||||||
tab: ret i32 9
|
tab: ret i32 9
|
||||||
|
f1: ret i32 132
|
||||||
|
f2: ret i32 133
|
||||||
|
f3: ret i32 134
|
||||||
|
f4: ret i32 135
|
||||||
|
f5: ret i32 136
|
||||||
|
f6: ret i32 137
|
||||||
|
f7: ret i32 138
|
||||||
|
f8: ret i32 139
|
||||||
|
f9: ret i32 140
|
||||||
|
f10: ret i32 141
|
||||||
|
f11: ret i32 142
|
||||||
|
f12: ret i32 143
|
||||||
|
khome: ret i32 144
|
||||||
|
kend: ret i32 145
|
||||||
|
kpgup: ret i32 146
|
||||||
|
kpgdn: ret i32 147
|
||||||
|
kins: ret i32 148
|
||||||
|
kdel: ret i32 149
|
||||||
|
kcaps: ret i32 150
|
||||||
|
np0: ret i32 152
|
||||||
|
np1: ret i32 153
|
||||||
|
np2: ret i32 154
|
||||||
|
np3: ret i32 155
|
||||||
|
np4: ret i32 156
|
||||||
|
np5: ret i32 157
|
||||||
|
np6: ret i32 158
|
||||||
|
np7: ret i32 159
|
||||||
|
np8: ret i32 160
|
||||||
|
np9: ret i32 161
|
||||||
|
npmul: ret i32 162
|
||||||
|
npadd: ret i32 163
|
||||||
|
npsub: ret i32 164
|
||||||
|
npdec: ret i32 165
|
||||||
|
npdiv: ret i32 166
|
||||||
chars:
|
chars:
|
||||||
%c = call i32 @w_vk_char(i32 %vk)
|
%c = call i32 @w_vk_char(i32 %vk)
|
||||||
; the held set is keyed by the key, not the case: fold A-Z (Shift is its own code)
|
; the held set is keyed by the key, not the case: fold A-Z (Shift is its own code)
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,42 @@ function key_lookup(name: pointer) -> int {
|
||||||
if (name == "Down") { return 129 }
|
if (name == "Down") { return 129 }
|
||||||
if (name == "Left") { return 130 }
|
if (name == "Left") { return 130 }
|
||||||
if (name == "Right") { return 131 }
|
if (name == "Right") { return 131 }
|
||||||
|
# the keys that type nothing on any layout (0.22): the F-row, the six-pack, Caps Lock and
|
||||||
|
# the numpad. Before these the platform gave them no code at all, so nothing could bind one.
|
||||||
|
if (name == "F1") { return 132 }
|
||||||
|
if (name == "F2") { return 133 }
|
||||||
|
if (name == "F3") { return 134 }
|
||||||
|
if (name == "F4") { return 135 }
|
||||||
|
if (name == "F5") { return 136 }
|
||||||
|
if (name == "F6") { return 137 }
|
||||||
|
if (name == "F7") { return 138 }
|
||||||
|
if (name == "F8") { return 139 }
|
||||||
|
if (name == "F9") { return 140 }
|
||||||
|
if (name == "F10") { return 141 }
|
||||||
|
if (name == "F11") { return 142 }
|
||||||
|
if (name == "F12") { return 143 }
|
||||||
|
if (name == "Home") { return 144 }
|
||||||
|
if (name == "End") { return 145 }
|
||||||
|
if (name == "PageUp") { return 146 }
|
||||||
|
if (name == "PageDown") { return 147 }
|
||||||
|
if (name == "Insert") { return 148 }
|
||||||
|
if (name == "Delete") { return 149 }
|
||||||
|
if (name == "CapsLock") { return 150 }
|
||||||
|
if (name == "Numpad0") { return 152 }
|
||||||
|
if (name == "Numpad1") { return 153 }
|
||||||
|
if (name == "Numpad2") { return 154 }
|
||||||
|
if (name == "Numpad3") { return 155 }
|
||||||
|
if (name == "Numpad4") { return 156 }
|
||||||
|
if (name == "Numpad5") { return 157 }
|
||||||
|
if (name == "Numpad6") { return 158 }
|
||||||
|
if (name == "Numpad7") { return 159 }
|
||||||
|
if (name == "Numpad8") { return 160 }
|
||||||
|
if (name == "Numpad9") { return 161 }
|
||||||
|
if (name == "NumpadMultiply") { return 162 }
|
||||||
|
if (name == "NumpadAdd") { return 163 }
|
||||||
|
if (name == "NumpadSubtract") { return 164 }
|
||||||
|
if (name == "NumpadDecimal") { return 165 }
|
||||||
|
if (name == "NumpadDivide") { return 166 }
|
||||||
if (name == "Digit0") { return 48 }
|
if (name == "Digit0") { return 48 }
|
||||||
if (name == "Digit1") { return 49 }
|
if (name == "Digit1") { return 49 }
|
||||||
if (name == "Digit2") { return 50 }
|
if (name == "Digit2") { return 50 }
|
||||||
|
|
|
||||||
20766
selfhost/ludicc.seed.ll
20766
selfhost/ludicc.seed.ll
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -715,6 +715,7 @@ function cmd_dev_test() -> int {
|
||||||
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_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/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/input_key_label", "", "W A ; 1 Space Esc Shift Left Right 0 1", "input_key_label.ludic (Input.key_label names a physical key: the US character headless, words for the named keys and arrows)")
|
feat_case("library/input_key_label", "", "W A ; 1 Space Esc Shift Left Right 0 1", "input_key_label.ludic (Input.key_label names a physical key: the US character headless, words for the named keys and arrows)")
|
||||||
|
feat_case("library/input_typeless_keys", "", "132 143 144 149 150 152 161 F1 F12 Home Delete CapsLock Num 0 Num / 1 0 1", "input_typeless_keys.ludic (the F-row, the six-pack, Caps Lock and the numpad are codes 132-166: bindable, in the held set, and named without asking the layout)")
|
||||||
feat_case("library/audio", "", "0 0 0 0 1", "audio.ludic (#22 Audio.* load/play/music/volume/pitch/stop/is_playing — headless no-op)")
|
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
|
# #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
|
# canonical `ludicc -o` path (which wires the framework) and gate on Darwin. The
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue