Skip to content

Commit b6651bd

Browse files
committed
Porting (Linux)
1 parent 495ac9f commit b6651bd

File tree

6 files changed

+549
-103
lines changed

6 files changed

+549
-103
lines changed

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ set(MINISCRIPT_HEADERS
5252

5353
set(MINICMD_HEADERS
5454
MiniScript-cpp/src/DateTimeUtils.h
55+
MiniScript-cpp/src/Key.h
5556
MiniScript-cpp/src/OstreamSupport.h
5657
MiniScript-cpp/src/ShellExec.h
5758
MiniScript-cpp/src/ShellIntrinsics.h
@@ -92,6 +93,7 @@ endif()
9293
add_executable(minicmd
9394
MiniScript-cpp/src/main.cpp
9495
MiniScript-cpp/src/DateTimeUtils.cpp
96+
MiniScript-cpp/src/Key.cpp
9597
MiniScript-cpp/src/OstreamSupport.cpp
9698
MiniScript-cpp/src/ShellIntrinsics.cpp
9799
MiniScript-cpp/src/ShellExec.cpp

MiniScript-cpp/README-key.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Key module
2+
3+
`key` module is a port of a [module](https://miniscript.org/wiki/Key) by the same name from Mini Micro that adds keyboard functions for immediate input in the console.
4+
5+
| API | Description |
6+
|---|---|
7+
| `key.available` | compatible |
8+
| `key.get` | compatible |
9+
| `key.put(keyChar)` | compatible |
10+
| `key.clear` | compatible |
11+
| `key.pressed(keyName="space")` | not ported |
12+
| `key.keyNames` | not ported |
13+
| `key.axis(axis="Horizontal")` | not ported |
14+
| `key._putInFront(keyChar)` | (non-standard) same as `key.put` but instead of adding its arg at the end of the input buffer, inserts it at the beginning |
15+
| `key._echo` | (non-standard, only unixes) property that controls whether typed characters are echoed in the terminal |
16+
| `key._scanMap` | (non-standard) property that controls how scan codes and escape sequences are mapped to the values that `key.get` is expected to return |
17+
18+
There's a small demo that demonstrates the use of `key.available` and `key.get`: `demo/tetris.ms`.
19+
20+
21+
## Implementation of the input buffer
22+
23+
The functions of this module maintain their shared internal buffer where key presses are stored.
24+
25+
It's implemented as a `SimpleVector` of entries where each entry is structure of two fields:
26+
27+
| `c` | character code point of a regular (symbol) key |
28+
| `scanCode` | a code of a special key |
29+
30+
Only one of these fields is non-zero at any times.
31+
32+
This data type allows registering key presses on unixes where only code points are used, and Windows where key presses generate either a code point or a sequence of two integers: `0` and a scan code.
33+
34+
35+
## Scan map
36+
37+
Terminals vary in how they report special keys' presses.
38+
39+
For example this is what \[Arrow up\] becomes in the Linux terminal: `char(27) + "[A"` (3 ASCII characters). The same key press on Windows produces `0` followed by scan code `72`. Finally, on Mini Micro it's `char(19)`.
40+
41+
*Scan maps* is an internal mechanism of the `key` module that converts all various values into the same values that are returned by Mini Micro's `key.get` and hence should ensure portability of scripts.
42+
43+
Scan maps are stored in a `key._scanMap` property and are MiniScript maps where the keys are either `number` type (in case you're mapping a scan code) or `string` type (in case of a sequence of characters), and the values are what you want to be returned by `key.get`.
44+
45+
So, to overcome the above \[Arrow up\] problem one could define `key._scanMap` as
46+
47+
```c
48+
key._scanMap = {
49+
char(27) + "[A": char(19),
50+
72: char(19),
51+
}
52+
```
53+
54+
There is already a predefined scan map in the `key` module that covers certain special keys (including arrow keys) for each platform.
55+
56+
57+
## Scan map optimization
58+
59+
In games, handling the user input is tipically a part of a game loop.
60+
61+
So, to make `key.get` a bit faster and avoid converting strings into code points on each frame, the scan map gets populated with optimized keys.
62+
63+
This optimization happens on assignment to the `_scanMap` property via the `*AssignOverride` trick.

MiniScript-cpp/demo/tetris.ms

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
// This demo uses non-standard `kbGet()` and `kbEcho()`
1+
// TETRIS
2+
// This demo uses `key.available()` and `key.get()`
23

34
import "vt"
45

@@ -8,10 +9,10 @@ fieldHeight = 20
89
fieldWidth = 10
910
fieldLeft = 20
1011
fieldColor = vt.color.black
11-
kUp = char(27) + "[A"
12-
kDown = char(27) + "[B"
13-
kRight = char(27) + "[C"
14-
kLeft = char(27) + "[D"
12+
kUp = char(19)
13+
kDown = char(20)
14+
kRight = char(18)
15+
kLeft = char(17)
1516
anchorRow = fieldHeight + 2
1617
gameOverFG = vt.color.white
1718
gameOverBG = vt.color.teal
@@ -20,9 +21,9 @@ cell = {}
2021
cell.empty = null
2122
cell.I = vt.color.aqua
2223
cell.O = vt.color.yellow
23-
cell.T = vt.color.purple
24+
cell.T = vt.color.fuchsia
2425
cell.L = vt.color.orange
25-
cell.J = vt.color.navy
26+
cell.J = vt.color.blue
2627
cell.S = vt.color.lime
2728
cell.Z = vt.color.red
2829
_cell = cell
@@ -272,7 +273,7 @@ end function
272273

273274
initField
274275
drawField
275-
kbEcho false
276+
key._echo = false
276277
t = time
277278
while true
278279
yield
@@ -281,27 +282,27 @@ while true
281282
shape = initShape
282283
if shape == null then
283284
drawGameOver
284-
kbEcho true
285+
key._echo = true
285286
exit
286287
end if
287288
drawShape shape
288289
end if
289290

290291
s = shape
291292
moved = null
292-
k = kbGet
293-
k3 = k[:3]
294-
if k3 == kUp then
295-
moved = rotate(s)
296-
else if k3 == kDown then
297-
moved = fall(s)
298-
else if k3 == kLeft then
299-
moved = moveLeft(s)
300-
else if k3 == kRight then
301-
moved = moveRight(s)
302-
end if
303-
304-
if moved != null then s = moved
293+
while key.available
294+
k = key.get
295+
if k == kUp then
296+
moved = rotate(s)
297+
else if k == kDown then
298+
moved = fall(s)
299+
else if k == kLeft then
300+
moved = moveLeft(s)
301+
else if k == kRight then
302+
moved = moveRight(s)
303+
end if
304+
if moved != null then s = moved
305+
end while
305306

306307
if time > t then
307308
t = time + delay

0 commit comments

Comments
 (0)