MIPS Input controller

What the Input controller is

The Input controller reports key presses and releases, held keys, mouse buttons, pointer position and wheel turns. Unlike the keyboard registers, which provide typed characters, it also reports keys such as the arrows, Shift and the function keys.

This editor adds the device to MARS, alongside the Synth. Its memory registers start at 0xffff0300, after the Synth's. In MARS these addresses read 0 and provide no input. Check the ID register before using the controller, as the first program below does.

Click the Screen panel to send keyboard and mouse input to the program. While the Screen has focus, keys go to the program, including Escape. Press Shift+Tab, or click outside the Screen, to return keyboard control to the editor. Losing focus releases all held keys and mouse buttons: their state bits clear and release events enter the queue. This also happens when the browser window loses focus.

A first program

This program prints a letter for each arrow key you press, R, L, D or U, and ends when you press Escape. Build it and press Run, then click the Screen and press the arrows.

        .text
main:   li      $s0, 0xffff0300 # the Input controller
        lw      $t0, 0($s0)     # ID: 0x494E5001 when it is there
        srl     $t0, $t0, 8
        li      $t1, 0x494E50   # "INP"
        bne     $t0, $t1, absent
poll:   lw      $t0, 8($s0)     # Status: how many events wait
        beqz    $t0, idle
        lw      $t2, 12($s0)    # Event: take the oldest one
        srl     $t3, $t2, 8
        andi    $t3, $t3, 7     # its kind
        andi    $t4, $t2, 0xff  # its code
        li      $t5, 1          # kind 1: a key went down
        bne     $t3, $t5, poll
        li      $t5, 0x29       # Escape
        beq     $t4, $t5, done
        addi    $t5, $t4, -0x4F # the arrows are 0x4F to 0x52
        sltiu   $t6, $t5, 4
        beqz    $t6, poll       # another key
        la      $t6, arrows
        add     $t6, $t6, $t5
        lb      $a0, 0($t6)     # R, L, D or U
        li      $v0, 11
        syscall
        j       poll
idle:   li      $a0, 16         # nothing waits: sleep a frame
        li      $v0, 32
        syscall
        j       poll
absent: la      $a0, missing
        li      $v0, 4
        syscall
done:   li      $v0, 10
        syscall
        .data
arrows: .ascii  "RLDU"
missing:.asciiz "This simulator has no Input controller.\n"

The program uses three registers:

  1. It reads the ID register once, to make sure the Input controller is there.
  2. It reads Status, which says how many events are waiting. If there are none, it sleeps for 16 milliseconds and looks again.
  3. Each read of Event takes the oldest waiting event, one word. The program takes it apart: the kind in bits 10–8, and the code in bits 7–0.

The registers

Offsets below are from 0xffff0300. Each register is one 32-bit word, except Keys, which occupies 32 bytes. Read registers with lw. Read individual bytes of Keys with lbu.

OffsetRegisterIn CAccessWhat it holds
0x00IdSIM_INPUT_IDreadReads 0x494E5001 ("INP", version 1) when the Input controller is available. Reads 0 in MARS and RARS, which do not provide this device
0x04ControlSIM_INPUT_CONTROLwriteReads 0. Bit 1 is reserved: setting it stops the program because the Input controller does not support interrupts. Leave it clear and poll Status for events. Other bits are ignored
0x08StatusSIM_INPUT_STATUSreadBits 6–0 hold the number of queued events, 0 to 127. Reading Status does not remove events
0x0CEventSIM_INPUT_EVENTread, takes an eventReading removes and returns the oldest queued event, or 0 if the queue is empty. Read once with lw and keep the result
0x10PointerSIM_INPUT_POINTERreadPointer position and held mouse buttons: y in bits 30–21, x in bits 20–11, buttons in bits 2–0
0x14–0x1FReservedReads 0
0x20KeysSIM_INPUT_KEYSread256 bits indicating held keys, one per HID usage code. For code u, test bit u & 7 of the byte at KEYS + (u >> 3)

Status normally ranges from 0 to 64, the queue's capacity. Undo can restore additional events, so Status can exceed 64. It reports at most 127, even if more events are waiting.

Reading Event removes an event. Even a byte read with lbu removes it. Read it once with lw and keep the result. Reads of the other registers remove nothing.

Writes do not change the controller's state or the values later reads return. One write causes an error: setting bit 1 of Control stops the program, because this controller does not support interrupts. Leave that bit clear and poll Status.

Events

Key presses, repeats and releases, mouse button presses and releases, and wheel turns produce events, one word each. Events wait in a queue, oldest first. Two key presses between reads are both kept in order, unless the queue is full.

BitsFieldWhat it holds
31always 0
30–21ythe pointer’s row when the event happened, 0 to 1023
20–11xthe pointer’s column, 0 to 1023
10–8kindwhat happened, from the table below
7–0codewhich key or button, or how far the wheel turned

Bit 31 of an Event word is always 0. Logical and arithmetic right shifts therefore give the same result when extracting its fields.

KindIn CMeaning
0No event: the queue was empty
1SIM_INPUT_KEY_DOWNA key went down; the code is its HID usage
2SIM_INPUT_KEY_UPA key came up; the code is its HID usage
3SIM_INPUT_KEY_REPEATA held key repeats, as it does when typing; the code is its HID usage
4SIM_INPUT_BUTTON_DOWNA mouse button went down; the code is 1 left, 2 right or 3 middle
5SIM_INPUT_BUTTON_UPA mouse button came up; the code is 1 left, 2 right or 3 middle
6SIM_INPUT_WHEELThe wheel turned; the code is a signed count of notches, positive away from the user
7SIM_INPUT_DROPPEDThe queue was full and events were lost here: read the state registers again
  • A key's code is its USB HID number. It identifies a physical key position rather than its printed character. For example, the position labelled S on a US keyboard is KeyS (0x16), regardless of the active layout. The table at the end lists the supported keys.
  • Holding a key sends one key-down event, then repeats at the keyboard's typing repeat rate, then one key-up event on release. To move something while a key is held, read the keys held now instead of counting repeats.
  • A button's code is 1 for the left button, 2 for the right and 3 for the middle one.
  • The wheel's code is a signed number of notches: positive away from you, negative towards you. Consecutive unread wheel turns in the same direction merge into one event while their sum fits from −127 to 127. The merged event uses the latest pointer position.
  • Every event carries the pointer's position at the moment it happened, so a click event says where the click was.

Taking an event apart:

        lw      $t0, 12($s0)    # one event
        srl     $t1, $t0, 8
        andi    $t1, $t1, 7     # kind, bits 10-8
        andi    $t2, $t0, 0xff  # code, bits 7-0
        srl     $t3, $t0, 11
        andi    $t3, $t3, 0x3ff # x, bits 20-11
        srl     $t4, $t0, 21    # y, bits 30-21: bit 31 is 0
        sll     $t5, $t0, 24
        sra     $t5, $t5, 24    # a wheel's code as a signed number of notches

Keys held now

From offset 0x20, 32 bytes hold one bit per key code. A bit is 1 while its key is held. For code k, read byte 0x20 + k / 8, bit k % 8, using integer division. Reads with lbu or lw leave the state unchanged.

This checks whether the left arrow, code 0x50, is held. 0x50 / 8 is 10 and 0x50 % 8 is 0, so the bit is bit 0 of the byte at offset 0x20 + 10:

        lbu     $t0, 0x2a($s0)  # keys 0x50 to 0x57
        andi    $t0, $t0, 1     # bit 0: the left arrow, 0x50
        bnez    $t0, left       # held: move left this frame

A game can read held keys once per frame and use events for single presses such as Escape. The two views answer different questions: a key pressed and released between frames is no longer held, but both events remain queued.

The pointer

The Pointer word holds y in bits 30–21, x in bits 20–11, and held buttons in bits 2–0: bit 0 left, bit 1 right and bit 2 middle.

x and y count words of the bitmap display, from 0 at the top left. The word under the pointer is y × columns + x, where columns is the display's width in words. Dragging past an edge keeps the coordinates at the last word. Pointer movement updates this register without queuing an event.

Waiting for input

To wait for input, sleep for a few milliseconds with service 32, then read Status again, as the first program does. Sleeping costs no instructions. Polling continuously uses instructions, fills the Undo history and can reach the instruction limit.

When the queue is full

The normal queue holds 64 events, including any dropped markers. When it is full, new events are lost. Once space becomes available, a later arriving event first adds a dropped marker, kind 7. If only one slot is free, the marker fills it and that arriving event is lost too. Reading events alone does not add a marker.

On receiving a dropped marker, read Keys and Pointer to recover the current state. Held-key and button state still updates when events are lost. Undo can temporarily restore more than 64 events, as explained below.

Typed characters and keys

A press that produces a character feeds both the keyboard registers at 0xffff0000 and the Input controller. Non-character keys, such as arrows and Shift, and key releases feed only the Input controller.

  • Use the keyboard registers for text. They provide characters in the user's keyboard layout, including Shift and AltGr combinations, pasted text and Testcase input.
  • Use the Input controller for keys. It provides physical key codes. A program using it for text must convert those codes into characters itself.

The two queues are separate. Reading the Input controller leaves typed characters waiting in the keyboard receiver. A later character read, including a read through a service, gets those old characters first. To discard them, read receiver data until the receiver's Ready bit is clear.

Escape types character 27 at the keyboard registers.

When the Input controller hears nothing

  • Before the program starts and after it ends. Input is accepted from the program's first instruction until it ends. A click that focuses the Screen before Run is not queued. A key already held when the program starts appears at its next repeat as a key-down event.
  • In a Testcase. A Testcase has no keyboard and no mouse: no events, no keys held, and the pointer at 0, 0. A Testcase's input still reaches the keyboard registers as typed lines.
  • Under the bitmap display. A display whose base address is 0xffff0000, MARS's "memory map" base, can cover the Input controller's addresses. Its words are then pixels, and the Input controller writes none of them. Move the display, or make it smaller, to use both.

Undo

Undo restores events removed by the instruction being undone, at the front of the queue and in their original order. Running forward can read them again. Restored events are kept even if the queue grows past 64. Status reports at most 127.

Undo does not rewind held keys, held buttons or pointer position. Those registers show current input, so the restored queue may contain a key-down event for a key that is now released.

From C

<sim.h> names the Input controller's registers, the parts of an event and every key:

  • Registers: SIM_INPUT_ID, SIM_INPUT_CONTROL, SIM_INPUT_STATUS, SIM_INPUT_EVENT and SIM_INPUT_POINTER read a register, and SIM_INPUT_KEYS is the 32 bytes of keys held.
  • Helpers: sim_input_present() says whether the Input controller is there, sim_input_pending() how many events wait, sim_input_event() takes the oldest event, sim_input_key_down(key) says whether a key is held, and sim_input_pointer() reads the Pointer register.
  • Parts of a word: SIM_INPUT_KIND(event), SIM_INPUT_CODE(event) and SIM_INPUT_WHEEL_NOTCHES(event), which gives the wheel's notches as a signed number; SIM_INPUT_X(word) and SIM_INPUT_Y(word) for an event or the pointer, and SIM_INPUT_BUTTONS(pointer).
  • Kinds: SIM_INPUT_KEY_DOWN, SIM_INPUT_KEY_UP, SIM_INPUT_KEY_REPEAT, SIM_INPUT_BUTTON_DOWN, SIM_INPUT_BUTTON_UP, SIM_INPUT_WHEEL and SIM_INPUT_DROPPED.
  • Buttons, in two forms: SIM_INPUT_BUTTON_LEFT, SIM_INPUT_BUTTON_RIGHT and SIM_INPUT_BUTTON_MIDDLE (1, 2 and 3) are a button event's code, while SIM_INPUT_HELD_LEFT, SIM_INPUT_HELD_RIGHT and SIM_INPUT_HELD_MIDDLE (1, 2 and 4) are the Pointer register's bits.
  • Keys: SIM_KEY_ and the key's name from the table below, such as SIM_KEY_A, SIM_KEY_ARROW_LEFT and SIM_KEY_SPACE.

See Using C and C++ for compiling. This program moves a dot with the arrow keys, draws where you click, and ends on Escape:

#include <sim.h>

SIM_SCREEN(screen, 64, 64, 1);

int main(void) {
    if (!sim_input_present()) {
        sim_print_string("This simulator has no Input controller.\n");
        return 1;
    }
    unsigned x = 32, y = 32;
    for (;;) {
        while (sim_input_pending()) {
            unsigned event = sim_input_event();
            unsigned kind = SIM_INPUT_KIND(event);
            if (kind == SIM_INPUT_KEY_DOWN && SIM_INPUT_CODE(event) == SIM_KEY_ESCAPE)
                return 0;
            /* a left click paints the word under the pointer */
            if (kind == SIM_INPUT_BUTTON_DOWN && SIM_INPUT_CODE(event) == SIM_INPUT_BUTTON_LEFT)
                screen[SIM_INPUT_Y(event) * 64 + SIM_INPUT_X(event)] = sim_rgb(255, 255, 0);
        }
        screen[y * 64 + x] = 0;
        if (sim_input_key_down(SIM_KEY_ARROW_LEFT) && x > 0) x--;
        if (sim_input_key_down(SIM_KEY_ARROW_RIGHT) && x < 63) x++;
        if (sim_input_key_down(SIM_KEY_ARROW_UP) && y > 0) y--;
        if (sim_input_key_down(SIM_KEY_ARROW_DOWN) && y < 63) y++;
        screen[y * 64 + x] = sim_rgb(0, 200, 255);
        sim_sleep(16);
    }
}

Key codes

Each key is named after the browser's name for it, written in capitals with underscores: ArrowLeft is SIM_KEY_ARROW_LEFT in C. Left and right Shift, Control, Alt and Meta (the Windows or Command key) are different keys. The keypad's keys are their own and do not depend on Num Lock. Keys that a USB keyboard has no code for, such as volume and media keys and Fn, send nothing.

Letters and digits

KeyCodeIn C
KeyA0x04SIM_KEY_A
KeyB0x05SIM_KEY_B
KeyC0x06SIM_KEY_C
KeyD0x07SIM_KEY_D
KeyE0x08SIM_KEY_E
KeyF0x09SIM_KEY_F
KeyG0x0ASIM_KEY_G
KeyH0x0BSIM_KEY_H
KeyI0x0CSIM_KEY_I
KeyJ0x0DSIM_KEY_J
KeyK0x0ESIM_KEY_K
KeyL0x0FSIM_KEY_L
KeyM0x10SIM_KEY_M
KeyN0x11SIM_KEY_N
KeyO0x12SIM_KEY_O
KeyP0x13SIM_KEY_P
KeyQ0x14SIM_KEY_Q
KeyR0x15SIM_KEY_R
KeyS0x16SIM_KEY_S
KeyT0x17SIM_KEY_T
KeyU0x18SIM_KEY_U
KeyV0x19SIM_KEY_V
KeyW0x1ASIM_KEY_W
KeyX0x1BSIM_KEY_X
KeyY0x1CSIM_KEY_Y
KeyZ0x1DSIM_KEY_Z
Digit10x1ESIM_KEY_DIGIT_1
Digit20x1FSIM_KEY_DIGIT_2
Digit30x20SIM_KEY_DIGIT_3
Digit40x21SIM_KEY_DIGIT_4
Digit50x22SIM_KEY_DIGIT_5
Digit60x23SIM_KEY_DIGIT_6
Digit70x24SIM_KEY_DIGIT_7
Digit80x25SIM_KEY_DIGIT_8
Digit90x26SIM_KEY_DIGIT_9
Digit00x27SIM_KEY_DIGIT_0

Typing keys

KeyCodeIn C
Enter0x28SIM_KEY_ENTER
Escape0x29SIM_KEY_ESCAPE
Backspace0x2ASIM_KEY_BACKSPACE
Tab0x2BSIM_KEY_TAB
Space0x2CSIM_KEY_SPACE
Minus0x2DSIM_KEY_MINUS
Equal0x2ESIM_KEY_EQUAL
BracketLeft0x2FSIM_KEY_BRACKET_LEFT
BracketRight0x30SIM_KEY_BRACKET_RIGHT
Backslash0x31SIM_KEY_BACKSLASH
Semicolon0x33SIM_KEY_SEMICOLON
Quote0x34SIM_KEY_QUOTE
Backquote0x35SIM_KEY_BACKQUOTE
Comma0x36SIM_KEY_COMMA
Period0x37SIM_KEY_PERIOD
Slash0x38SIM_KEY_SLASH
CapsLock0x39SIM_KEY_CAPS_LOCK

Function keys

KeyCodeIn C
F10x3ASIM_KEY_F1
F20x3BSIM_KEY_F2
F30x3CSIM_KEY_F3
F40x3DSIM_KEY_F4
F50x3ESIM_KEY_F5
F60x3FSIM_KEY_F6
F70x40SIM_KEY_F7
F80x41SIM_KEY_F8
F90x42SIM_KEY_F9
F100x43SIM_KEY_F10
F110x44SIM_KEY_F11
F120x45SIM_KEY_F12
F130x68SIM_KEY_F13
F140x69SIM_KEY_F14
F150x6ASIM_KEY_F15
F160x6BSIM_KEY_F16
F170x6CSIM_KEY_F17
F180x6DSIM_KEY_F18
F190x6ESIM_KEY_F19
F200x6FSIM_KEY_F20
F210x70SIM_KEY_F21
F220x71SIM_KEY_F22
F230x72SIM_KEY_F23
F240x73SIM_KEY_F24

Navigation

KeyCodeIn C
PrintScreen0x46SIM_KEY_PRINT_SCREEN
ScrollLock0x47SIM_KEY_SCROLL_LOCK
Pause0x48SIM_KEY_PAUSE
Insert0x49SIM_KEY_INSERT
Home0x4ASIM_KEY_HOME
PageUp0x4BSIM_KEY_PAGE_UP
Delete0x4CSIM_KEY_DELETE
End0x4DSIM_KEY_END
PageDown0x4ESIM_KEY_PAGE_DOWN
ArrowRight0x4FSIM_KEY_ARROW_RIGHT
ArrowLeft0x50SIM_KEY_ARROW_LEFT
ArrowDown0x51SIM_KEY_ARROW_DOWN
ArrowUp0x52SIM_KEY_ARROW_UP
ContextMenu0x65SIM_KEY_CONTEXT_MENU
Help0x75SIM_KEY_HELP

Keypad

KeyCodeIn C
NumLock0x53SIM_KEY_NUM_LOCK
NumpadDivide0x54SIM_KEY_NUMPAD_DIVIDE
NumpadMultiply0x55SIM_KEY_NUMPAD_MULTIPLY
NumpadSubtract0x56SIM_KEY_NUMPAD_SUBTRACT
NumpadAdd0x57SIM_KEY_NUMPAD_ADD
NumpadEnter0x58SIM_KEY_NUMPAD_ENTER
Numpad10x59SIM_KEY_NUMPAD_1
Numpad20x5ASIM_KEY_NUMPAD_2
Numpad30x5BSIM_KEY_NUMPAD_3
Numpad40x5CSIM_KEY_NUMPAD_4
Numpad50x5DSIM_KEY_NUMPAD_5
Numpad60x5ESIM_KEY_NUMPAD_6
Numpad70x5FSIM_KEY_NUMPAD_7
Numpad80x60SIM_KEY_NUMPAD_8
Numpad90x61SIM_KEY_NUMPAD_9
Numpad00x62SIM_KEY_NUMPAD_0
NumpadDecimal0x63SIM_KEY_NUMPAD_DECIMAL
NumpadEqual0x67SIM_KEY_NUMPAD_EQUAL
NumpadComma0x85SIM_KEY_NUMPAD_COMMA
NumpadParenLeft0xB6SIM_KEY_NUMPAD_PAREN_LEFT
NumpadParenRight0xB7SIM_KEY_NUMPAD_PAREN_RIGHT
NumpadBackspace0xBBSIM_KEY_NUMPAD_BACKSPACE

Modifiers

KeyCodeIn C
ControlLeft0xE0SIM_KEY_CONTROL_LEFT
ShiftLeft0xE1SIM_KEY_SHIFT_LEFT
AltLeft0xE2SIM_KEY_ALT_LEFT
MetaLeft0xE3SIM_KEY_META_LEFT
ControlRight0xE4SIM_KEY_CONTROL_RIGHT
ShiftRight0xE5SIM_KEY_SHIFT_RIGHT
AltRight0xE6SIM_KEY_ALT_RIGHT
MetaRight0xE7SIM_KEY_META_RIGHT

International

KeyCodeIn C
IntlBackslash0x64SIM_KEY_INTL_BACKSLASH
IntlRo0x87SIM_KEY_INTL_RO
KanaMode0x88SIM_KEY_KANA_MODE
IntlYen0x89SIM_KEY_INTL_YEN
Convert0x8ASIM_KEY_CONVERT
NonConvert0x8BSIM_KEY_NON_CONVERT
Lang10x90SIM_KEY_LANG_1
Lang20x91SIM_KEY_LANG_2
Lang30x92SIM_KEY_LANG_3
Lang40x93SIM_KEY_LANG_4
Lang50x94SIM_KEY_LANG_5

On Windows, AltGr arrives as two keys at once: Control Left and Alt Right.

For assembly, these lines give the common keys names, ready to paste at the top of a program:

.eqv KEY_A 0x04
.eqv KEY_B 0x05
.eqv KEY_C 0x06
.eqv KEY_D 0x07
.eqv KEY_E 0x08
.eqv KEY_F 0x09
.eqv KEY_G 0x0A
.eqv KEY_H 0x0B
.eqv KEY_I 0x0C
.eqv KEY_J 0x0D
.eqv KEY_K 0x0E
.eqv KEY_L 0x0F
.eqv KEY_M 0x10
.eqv KEY_N 0x11
.eqv KEY_O 0x12
.eqv KEY_P 0x13
.eqv KEY_Q 0x14
.eqv KEY_R 0x15
.eqv KEY_S 0x16
.eqv KEY_T 0x17
.eqv KEY_U 0x18
.eqv KEY_V 0x19
.eqv KEY_W 0x1A
.eqv KEY_X 0x1B
.eqv KEY_Y 0x1C
.eqv KEY_Z 0x1D
.eqv KEY_DIGIT_1 0x1E
.eqv KEY_DIGIT_2 0x1F
.eqv KEY_DIGIT_3 0x20
.eqv KEY_DIGIT_4 0x21
.eqv KEY_DIGIT_5 0x22
.eqv KEY_DIGIT_6 0x23
.eqv KEY_DIGIT_7 0x24
.eqv KEY_DIGIT_8 0x25
.eqv KEY_DIGIT_9 0x26
.eqv KEY_DIGIT_0 0x27
.eqv KEY_ENTER 0x28
.eqv KEY_ESCAPE 0x29
.eqv KEY_BACKSPACE 0x2A
.eqv KEY_TAB 0x2B
.eqv KEY_SPACE 0x2C
.eqv KEY_MINUS 0x2D
.eqv KEY_EQUAL 0x2E
.eqv KEY_BRACKET_LEFT 0x2F
.eqv KEY_BRACKET_RIGHT 0x30
.eqv KEY_BACKSLASH 0x31
.eqv KEY_SEMICOLON 0x33
.eqv KEY_QUOTE 0x34
.eqv KEY_BACKQUOTE 0x35
.eqv KEY_COMMA 0x36
.eqv KEY_PERIOD 0x37
.eqv KEY_SLASH 0x38
.eqv KEY_CAPS_LOCK 0x39
.eqv KEY_F1 0x3A
.eqv KEY_F2 0x3B
.eqv KEY_F3 0x3C
.eqv KEY_F4 0x3D
.eqv KEY_F5 0x3E
.eqv KEY_F6 0x3F
.eqv KEY_F7 0x40
.eqv KEY_F8 0x41
.eqv KEY_F9 0x42
.eqv KEY_F10 0x43
.eqv KEY_F11 0x44
.eqv KEY_F12 0x45
.eqv KEY_PRINT_SCREEN 0x46
.eqv KEY_SCROLL_LOCK 0x47
.eqv KEY_PAUSE 0x48
.eqv KEY_INSERT 0x49
.eqv KEY_HOME 0x4A
.eqv KEY_PAGE_UP 0x4B
.eqv KEY_DELETE 0x4C
.eqv KEY_END 0x4D
.eqv KEY_PAGE_DOWN 0x4E
.eqv KEY_ARROW_RIGHT 0x4F
.eqv KEY_ARROW_LEFT 0x50
.eqv KEY_ARROW_DOWN 0x51
.eqv KEY_ARROW_UP 0x52
.eqv KEY_NUM_LOCK 0x53
.eqv KEY_NUMPAD_DIVIDE 0x54
.eqv KEY_NUMPAD_MULTIPLY 0x55
.eqv KEY_NUMPAD_SUBTRACT 0x56
.eqv KEY_NUMPAD_ADD 0x57
.eqv KEY_NUMPAD_ENTER 0x58
.eqv KEY_NUMPAD_1 0x59
.eqv KEY_NUMPAD_2 0x5A
.eqv KEY_NUMPAD_3 0x5B
.eqv KEY_NUMPAD_4 0x5C
.eqv KEY_NUMPAD_5 0x5D
.eqv KEY_NUMPAD_6 0x5E
.eqv KEY_NUMPAD_7 0x5F
.eqv KEY_NUMPAD_8 0x60
.eqv KEY_NUMPAD_9 0x61
.eqv KEY_NUMPAD_0 0x62
.eqv KEY_NUMPAD_DECIMAL 0x63
.eqv KEY_INTL_BACKSLASH 0x64
.eqv KEY_CONTEXT_MENU 0x65
.eqv KEY_NUMPAD_EQUAL 0x67
.eqv KEY_F13 0x68
.eqv KEY_F14 0x69
.eqv KEY_F15 0x6A
.eqv KEY_F16 0x6B
.eqv KEY_F17 0x6C
.eqv KEY_F18 0x6D
.eqv KEY_F19 0x6E
.eqv KEY_F20 0x6F
.eqv KEY_F21 0x70
.eqv KEY_F22 0x71
.eqv KEY_F23 0x72
.eqv KEY_F24 0x73
.eqv KEY_HELP 0x75
.eqv KEY_NUMPAD_COMMA 0x85
.eqv KEY_INTL_RO 0x87
.eqv KEY_KANA_MODE 0x88
.eqv KEY_INTL_YEN 0x89
.eqv KEY_CONVERT 0x8A
.eqv KEY_NON_CONVERT 0x8B
.eqv KEY_LANG_1 0x90
.eqv KEY_LANG_2 0x91
.eqv KEY_LANG_3 0x92
.eqv KEY_LANG_4 0x93
.eqv KEY_LANG_5 0x94
.eqv KEY_NUMPAD_PAREN_LEFT 0xB6
.eqv KEY_NUMPAD_PAREN_RIGHT 0xB7
.eqv KEY_NUMPAD_BACKSPACE 0xBB
.eqv KEY_CONTROL_LEFT 0xE0
.eqv KEY_SHIFT_LEFT 0xE1
.eqv KEY_ALT_LEFT 0xE2
.eqv KEY_META_LEFT 0xE3
.eqv KEY_CONTROL_RIGHT 0xE4
.eqv KEY_SHIFT_RIGHT 0xE5
.eqv KEY_ALT_RIGHT 0xE6
.eqv KEY_META_RIGHT 0xE7