|
| 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. |
0 commit comments