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