Skip to content

Commit

Permalink
Merge pull request #170 from marcgurevitx/terminal-funcs
Browse files Browse the repository at this point in the history
Terminal funcs
  • Loading branch information
JoeStrout authored Jul 28, 2024
2 parents 15c1ca8 + 7784732 commit 81f923c
Show file tree
Hide file tree
Showing 6 changed files with 991 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ set(MINISCRIPT_HEADERS

set(MINICMD_HEADERS
MiniScript-cpp/src/DateTimeUtils.h
MiniScript-cpp/src/Key.h
MiniScript-cpp/src/OstreamSupport.h
MiniScript-cpp/src/ShellExec.h
MiniScript-cpp/src/ShellIntrinsics.h
Expand Down Expand Up @@ -92,6 +93,7 @@ endif()
add_executable(minicmd
MiniScript-cpp/src/main.cpp
MiniScript-cpp/src/DateTimeUtils.cpp
MiniScript-cpp/src/Key.cpp
MiniScript-cpp/src/OstreamSupport.cpp
MiniScript-cpp/src/ShellIntrinsics.cpp
MiniScript-cpp/src/ShellExec.cpp
Expand Down
67 changes: 67 additions & 0 deletions MiniScript-cpp/README-key.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Key module

`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.

| API | Description |
|---|---|
| `key.available` | compatible |
| `key.get` | compatible |
| `key.put(keyChar)` | compatible |
| `key.clear` | compatible |
| `key.pressed(keyName="space")` | (not ported) |
| `key.keyNames` | (not ported) |
| `key.axis(axis="Horizontal")` | (not ported) |
| `key._putInFront(keyChar)` | (non-standard) same as `key.put` but inserts its arg at the beginning of the input buffer |
| `key._echo` | (non-standard, only unixes) boolean property that controls whether typed characters are echoed in the terminal |
| `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) |

There's a small script that demonstrates the use of `key.available`, `key.get` and `key._echo`: `demo/tetris.ms`.


## Implementation of the input buffer

Functions of this module maintain a shared internal buffer where key presses are stored.

It's implemented as a `SimpleVector` of entries where each entry is structure of two fields:

| Field | Description |
|---|---|
| `c` | character code point of a regular (symbol) key |
| `scanCode` | a code of a special key |

Only one of these fields is non-zero at any times.

This data type was chosen to register key presses on various systems:
- On unixes only code points are used
- On Windows key presses may generate either a code point or a sequence of two integers: `0` and a scan code.


## Scan map

Terminals vary in how they report special keys' presses.

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)`.

*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.

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`.

So, to overcome the above \[Arrow up\] problem one could define `key._scanMap` as

```c
key._scanMap = {
char(27) + "[A": char(19),
72: char(19),
}
```

There is already a predefined scan map in the `key` module that covers certain special keys (including arrow keys) for each platform.


## Scan map optimization

In games, handling the user input is tipically a part of a game loop and thus needs to be fast.

To avoid converting strings into code points on each frame inside `key.get`, the scan map gets populated with optimized keys.

This optimization happens on assignment to the `_scanMap` property via the `*AssignOverride` trick.
Loading

0 comments on commit 81f923c

Please sign in to comment.