Skip to content

Commit 81f923c

Browse files
authored
Merge pull request #170 from marcgurevitx/terminal-funcs
Terminal funcs
2 parents 15c1ca8 + 7784732 commit 81f923c

File tree

6 files changed

+991
-0
lines changed

6 files changed

+991
-0
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: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
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 inserts its arg at the beginning of the input buffer |
15+
| `key._echo` | (non-standard, only unixes) boolean 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 (`map` type) |
17+
18+
There's a small script that demonstrates the use of `key.available`, `key.get` and `key._echo`: `demo/tetris.ms`.
19+
20+
21+
## Implementation of the input buffer
22+
23+
Functions of this module maintain a 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+
| Field | Description |
28+
|---|---|
29+
| `c` | character code point of a regular (symbol) key |
30+
| `scanCode` | a code of a special key |
31+
32+
Only one of these fields is non-zero at any times.
33+
34+
This data type was chosen to register key presses on various systems:
35+
- On unixes only code points are used
36+
- On Windows key presses may generate either a code point or a sequence of two integers: `0` and a scan code.
37+
38+
39+
## Scan map
40+
41+
Terminals vary in how they report special keys' presses.
42+
43+
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)`.
44+
45+
*Scan maps* is a 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 facilitates portability of scripts.
46+
47+
Scan maps are MiniScript `map`s (stored as a `key._scanMap` property) 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`.
48+
49+
So, to overcome the above \[Arrow up\] problem one could define `key._scanMap` as
50+
51+
```c
52+
key._scanMap = {
53+
char(27) + "[A": char(19),
54+
72: char(19),
55+
}
56+
```
57+
58+
There is already a predefined scan map in the `key` module that covers certain special keys (including arrow keys) for each platform.
59+
60+
61+
## Scan map optimization
62+
63+
In games, handling the user input is tipically a part of a game loop and thus needs to be fast.
64+
65+
To avoid converting strings into code points on each frame inside `key.get`, the scan map gets populated with optimized keys.
66+
67+
This optimization happens on assignment to the `_scanMap` property via the `*AssignOverride` trick.

0 commit comments

Comments
 (0)