Skip to content
Manuel Bilderbeek edited this page May 30, 2023 · 1 revision

Introduction

This document is about keyboard mappings in all its forms. The keyboard is an input device on the host, but also an important input device on the emulated (MSX) computer. There are several use cases where you want host input (keyboard or other) to have a certain effect on the MSX keyboard. This document attempts to make an overview of these and attempt to come to a design.

Definitions

Scancode

The scan code is based on the hardware position and independent of the keyboard layout selected in the OS. So, it's code that indicates a host key position. The identifiers are arbitrarily based on a US keyboard.

The scancode doesn't tell you which key is meant to be pressed, but the position of the key on the host keyboard. So for instance, the key next to the TAB key (Q on a QWERTY keyboard) will give the same scancode as the A key on an AZERTY keyboard, because it's on the same physical position. According to the SDL2 header file which defines the keycodes, it is based on the USB standard: https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf

Keycode

This is a code generated from the SDL2 library that indicates which key is pressed, not by key position, but by keycap.

MSX key (name)

The key as you find it on the actual MSX machines. When we use the MSX key (name), we intend that the user can identify a key on the MSX keyboard with this name. This is usually indicated by the key cap and the character it produces without any modifiers.

These keys are independent of their position on the keyboard.

Note that there are some variations, which we map to the same key name for convenience. Examples: RETURN, ENTER or <--|. Or TAB and -->.

There is also an exceptional case. For French (AZERTY) keyboards, the top row with the numbers are called the number keys, but to produce the actual numbers, SHIFT must be pressed together with these keys. Still, everyone calls them the number keys, so let's identify these keys with the numbers, instead with the symbols they produce when hitting them.

The key caps of the numpad must be distinguished from the other keys, as they overlap with them. Let's use a prefix like NUMPAD_.

MSX keyboard matrix

The MSX keyboard matrix consists of a variable number of rows and 8 columns (indicated with a byte, so 0-7).

  • rows 0-5 are usually the most varying amongst different keyboards. They contain the number and letter characters and several symbols They can also contain zero or more dead keys.
  • rows 6-8 are usually all the same (for MSX) and contain the RETURN, SELECT, BACKSPACE, STOP, TAB, ESCAPE, function keys, arrow keys and DEL, INS, HOME and SPACE keys.
  • rows 9-10 contain the numpad keys. These are optional.
  • row 9 can also contain the video keys of the Pioneer video computers.
  • row 11 contains the CANCEL and EXECUTE keys (also known as YES/NO keys) used on several Panasonic MSX2+ and the turboR machines. Note that the positions of keys on the Philips VG-8000/8010 machines in rows 0-5 is completely different than other international or European machines.

Is the keyboard matrix defined by the wiring of the keys into the PPI? I guess so. If that's the case, then the wiring is mostly very similar, except for the VG-8000/8010. Does this mean that POSITIONAL mode will break for these few machines?

The key positions in the matrix do not resemble the physical positions of the keys for any known keyboard matrix.

Character set mapping

We have mapping files for different character sets on how the character set index (the byte in VRAM in a text mode) maps to a unicode character.

This is a strict 1-to-1 mapping, except for indices that do not map to a character, like 0xFF on most MSX machines (is the cursor shape).

This information is used to transform VRAM content to unicode text.

Unicode mapping

This is the current mechanism in openMSX to store which keyboard matrix positions and modifiers need to be triggered together to generate a certain unicode character. So, this is a convolution of keyboard matrix information, key information (which key is where on the matrix), and character set information (which character is generated for a key).

This information is used for the CHARACTER keyboard mapping mode (see definition), but also for the type command ("paste text into the MSX") or for file name conversion from host to MSX characters.

Existing keyboard mapping modes: CHARACTER, KEY, POSITIONAL.

The existing modes attempt to do the following:

  • CHARACTER: use the unicode mapping information to press the unicode character that belongs to the user input. Goal is to make typing on the emulated MSX independent of the used host keyboard layout and the emulated MSX keyboard layout. "You just get typed on the MSX what you typed on the host PC."
  • KEY: map the host keycode to an MSX keycode. Except that MSX keycodes do not exist, so they map directly to a fixed table of keyboard matrix positions. This works quite badly for varying international MSX keyboard layouts, as the table doesn't take these into account.
  • POSITIONAL: map the host scancode to an MSX matrix position. "Type (blindly) on your host keyboard as if it's the emulated MSX keyboard."

General goal of these mapping modes is to trigger the proper MSX keyboard matrix positions, dependent on the goal of the user.

Requirements

  • all three keyboard mapping modes have their own strengths, from high to low level they should in principle be like this:
    • CHARACTER: when there is a unicode character to be associated with the host keyboard input, make sure the MSX keyboard matrix is triggered to produce the same character. So, this is a mostly automatic mapping from host input to MSX input. If there is no unicode character, fallback to the KEY mode mechanism, see next bullet.
    • KEY: a mapping between host key codes to MSX key names. The key names are then translated to keyboard matrix positions. This requires to have a definition which key names exist on the emulated MSX keyboard and with which keyboard matrix position they are linked.
    • POSITIONAL: a mapping between host key scan codes and MSX key names (and with these back to keyboard matrix positions like in the KEY mode). This means the input-side is positional. But it would also be nice to make the MSX-side positional. For that special MSX key names could be used that just point out a matrix position (like: MATRIXr,c)
  • The configuration we will offer is about a host input event (of a property that has only 2 states like pressed and non-pressed) that can be mapped to an MSX key name. That is, a map of MSX key name with 0 or more host events that trigger the pressing/releasing of that key.
  • By default, the mapping will remain as is (so, for example, the MSX key name STOP will be triggered if host key name F8 is triggered).
    • The default mapping for CHARACTER mode is the same as for KEY mode.
    • The default mapping for POSITIONAL mode as the same as for KEY mode.
    • A host keyboard input that maps to an MSX key (real or MATRIXr,c) can be a host scancode or a host keycode.
    • TODO: can we use that MATRIXr,c also as destination for mappings in KEY mode? That would make the host side KEY based but the MSX-side POSITIONAL based. It might be confusing, but why forbid it, if we already define the MATRIXr,c as 'fake MSX key names' anyway?
  • Current hardcoded mappings (e.g. F7SELECT, F8STOP) must be configurable as well, with the same mechanism.
  • The user defined mapping for host keyboard input, is not applicable in CHARACTER mode where there is unicode information, because in that mode, the user expressed the wish for a mostly automatic mapping. Only for the other modes, or cases where no unicode information is present (including host input like host joypad buttons).
  • The user must be able to save and load a mapping set. This is useful to load different mappings applicable for different games, for instance.

Use cases fulfilled by these requirements

  • The user desires to map host joypad input to MSX function keys (very useful for playing Konami games with host joypad).
  • The user desires to map host joypad input the keys used in Spectrum port (typical letter keys like Q, A, O and P).
  • The user desires to map host keyboard input (cursor keys) to the keys used in Spectrum port (typical letter keys like Q, A, O and P).
  • The user wants to type with his US English QWERTY host keyboard on a French (AZERTY) MSX keyboard, without having to worry about the different keyboard layout. (This is the main feature of the CHARACTER mode.)
  • The mapping must also be possible to be offered on a GUI (OSD menu, or different) which requires:
    • A way to list current bindings: list all current MSX keys and which input maps to them
    • A way to change a current binding
    • A way to tell whether the host input is mappable to the MSX key (it must be an input with a discrete pressed/released state). (Could this be just a hardcoded list?)
  • The user wants to save mappings for one game and load them for another game.

Special cases

  • A Japanese keyboard does not have a backslash key. It doesn't even exist in the character set. Instead, there is a Yen key and character. It would be comfortable when inputting a backslash with a host keyboard, a Yen-character would be produced on a Japanese MSX. (This is currently realized by having both in the unicode map file, with the same key presses.)
  • The Colecovision doesn't have a keyboard, but its input controllers (2 are supported) each contain a set of number input keys and a few symbols.

Design

Required changes in the current code

  • Both host scan codes and key codes are transformed into a single enum type in openMSX with key codes. This causes some information to get lost in translation, see also for instance the analysis in #1465 . The openMSX enum was made to be independent of SDL. If we want to maintain that, we should split it into two enums (one for scan codes and one for key codes). Alternatively, we directly use the SDL definitions and lose the independence. In the worst case, we could also just copy the SDL definitions. The scancode definitions are based on a 'standard' document (https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf), the keycode definitions seem to be a choice of SDL itself.
    • Decision is needed on how to proceed here: use SDL definitions (directly or copied) or make our own. → for now, let's just use the SDL definitions only and ditch our own enum.
  • To clean up the keyboard code in combination with replays/savestates, we need to stop storing commands in replays and only store the effect of the commands. In this context (keyboard stuff): only keyboard matrix changes should be recorded, not the way they were created (like: type command, keymatrixdown/up commands, etc.) See also #902 for a similar issue.
    • I'm not sure how much this is in the way when we refactor the Keyboard class.
  • The keyTab table(s) in Keyboard.cc is now used to map an openMSX key name (internal enum) to a keyboard matrix position in a hardcoded way, when there is no unicode field. It seems obvious that this table must be changed:
    • it must not map to keyboard matrix positions, but to MSX keys (let's not store matrix positions for now, as it makes a lot more sense to abstract matrix positions away here, I think).
    • it must become configurable, with multiple possible host events mapping to a single MSX key (so, change table into map).
    • while we're at it: there are several hardcoded keyboard matrix positions in Keyboard.cc, which isn't necessary anymore: the data is available in the new mapping files in the branch.
  • Design needed how to save the mapping. It could be done in settings.xml, but we must be careful that it must be possible to remove a default mapping as well. (With other settings, removing a setting from the file means you set it to default.) Perhaps it can be done like how we handle the bind settings.

Other open items/details/exceptions:

  • how do we handle bindings to MSX keys that aren't existing in the current MSX model? We must ignore when they're triggered, I guess. Is it OK if we don't list these when showing the current bindings?
    • This is probably quite exceptional, most mappings will be done to common MSX keys like the function keys.
  • How does keyjoystick fit into this? Does it have a relation, even?