diff --git a/README.md b/README.md
index 48798e3..2c85c9a 100644
--- a/README.md
+++ b/README.md
@@ -9,13 +9,390 @@
### EMARS 4.7
* Switched to Gradle build system with Kotlin support
-* Added `--open` option to open a file on start
+* Added `--open` command-line option to open a file on start
+* Added **Keyboard++**: Enhanced keyboard events
+* Refactored many classes in Kotlin
## FAQ
**How to run:** Install Java JDK >11 and double-click on the jar.
**How to compile:** `gradle shadowJar`
+## Keyboard++
+
+
+
+Mars' MMIO Keyboard can only send one key event at any given time, and key repeats are handled by the operating system running Java, which is very bad for controlling a game because of the delay and inconsistency introduced.
+
+So I developed the enhanced **Keyboard++** with additional features:
+
+* **14 simultaneous key events!**
+(MARS 4.5 can read only 1 key at a time)
+* **Fine control of separate key-down and key-up events**
+(MARS 4.5 can only read keys typed)
+* **Use 2-byte key code** instead of 1-byte ASCII char
+(Non-character keys like arrows & F1-F12 can now be read)
+* **Filter out system key repeats**
+(Pressing a key for longer will not repeat any event)
+* **Use "clear byte"** to indicate if the events should be cleared
+(MARS 4.5 clears the key byte whenever it is read)
+
+### Specification
+
+
+
+From the initial address, the first 4 words (16 bytes) represents key-down events (when a key is first pressed). The next 4 words (16 bytes) represent key-up events.
+
+For each event type, the 0x0 byte stores an unsigned integer `n`, ranging from `0` to `7`, representing how many key events are pooled.
+
+The 0x1 byte tells the keyboard handler whether the events are read by your MIPS program and should be reset. If 1 is written to the 1st byte, then all keys in the current event cycle will be cleared to 0.
+
+From the 0x2 byte to the 0xF byte stores `n` unsigned 2-byte key codes received, in chronological order. (e.g. the 0x2 half-word stores the first key that's pressed after the last reset). The keycodes are the same with the keycodes used in Java's KeyEvent class. I've attached a list of keycodes extracted from the class below.
+
+### Sample
+
+Here's a sample MIPS code that reads events from Keyboard++:
+
+
+ Example MIPS Program using Keyboard++
+
+```asm
+.data
+
+# The addresses of Keyboard++
+ADDR_KEY_DOWN: .word 0xffff0010
+ADDR_KEY_UP: .word 0xffff0020
+
+# Example variables
+PAUSED: .word 1
+KEY_MOVE_DIRECTION: .byte 0
+
+.text
+
+# """
+# read_keyboard()
+#
+# Listen to keyboard events
+# """
+read_keyboard:
+
+ # Save items onto the stack: ra, s0, s1
+ sw $ra, -4($sp)
+ sw $s0, -8($sp)
+ sw $s1, -12($sp)
+ addi $sp, $sp, -12
+
+ # 1. Check for key down event
+ lw $s0, ADDR_KEY_DOWN
+ lbu $s1, 0($s0)
+ beq $s1, 0, key_down_none
+
+ # In a loop, read the keys that are down (pressed)
+ # while (s1 > 0)
+ while_1_0:
+ sub $t9, $s1, $zero
+ blez $t9, while_done_1_0
+ # {
+ # Move offset to the next half-word
+ addiu $s0, $s0, 2
+
+ # Read half-word keycode
+ lhu $t2, 0($s0)
+
+ # if (t2 == 0x51): Q, quit
+ bne $t2, 0x51, else_2_0
+ li $v0, 10
+ syscall
+ else_2_0:
+
+ # if (t2 == 0x20): Space, lauch ball
+ bne $t2, 0x20, else_2_2
+ # if (PAUSED == 1)
+ lw $t9, PAUSED
+ bne $t9, 1, else_2_2
+ jal launch
+ else_2_2:
+
+ # if (t2 == 0x25): Left arrow, set flag that we're moving left
+ bne $t2, 0x25, else_2_3
+ li $t9, -1
+ sw $t9, KEY_MOVE_DIRECTION
+ else_2_3:
+
+ # if (t2 == 0x27): Right arrow, set flag that we're moving right
+ bne $t2, 0x27, else_2_4
+ li $t9, 1
+ sw $t9, KEY_MOVE_DIRECTION
+ else_2_4:
+
+ # Next iteration
+ addi $s1, $s1, -1
+ # }
+ j while_1_0
+ while_done_1_0:
+
+ # When we're done, write 1 to offset 1 to clear events
+ lw $s0, ADDR_KEY_DOWN
+ li $s1, 1
+ sb $s1, 1($s0)
+
+ key_down_none:
+
+ # 2. Check for key up event
+ lw $s0, ADDR_KEY_UP
+ lbu $s1, 0($s0)
+ beq $s1, 0, key_up_none
+
+ # In a loop, read the keys that are up (released)
+ # while (s1 > 0)
+ while_1_1:
+ sub $t9, $s1, $zero
+ blez $t9, while_done_1_1
+ # {
+ addiu $s0, $s0, 2
+ lhu $t2, 0($s0)
+
+ # Left arrow released, unset flag
+ # if (t2 == 0x25 && KEY_MOVE_DIRECTION == -1)
+ bne $t2, 0x25, else_2_5
+ lw $t9, KEY_MOVE_DIRECTION
+ bne $t9, -1, else_2_5
+ li $t9, 0
+ sw $t9, KEY_MOVE_DIRECTION
+ else_2_5:
+
+ # Right arrow released, unset flag
+ # if (t2 == 0x27 && KEY_MOVE_DIRECTION == 1)
+ bne $t2, 0x27, else_2_6
+ lw $t9, KEY_MOVE_DIRECTION
+ bne $t9, 1, else_2_6
+ li $t9, 0
+ sw $t9, KEY_MOVE_DIRECTION
+ else_2_6:
+
+ addi $s1, $s1, -1
+ # }
+ j while_1_1
+ while_done_1_1:
+
+ # When we're done, write 1 to offset 1 to clear events
+ lw $s0, ADDR_KEY_UP
+ li $s1, 1
+ sb $s1, 1($s0)
+
+ key_up_none:
+
+ # Retrieve items from the stack: ra, s0, s1
+ lw $s1, 0($sp)
+ lw $s0, 4($sp)
+ lw $ra, 8($sp)
+ addi $sp, $sp, 12
+ jr $ra
+```
+
+
+
+### List of Keycodes
+
+
+ List of all key codes
+
+```python
+ENTER = 0xA
+BACK_SPACE = 0x8
+VK_TAB = 0x9
+
+# Regex used to extract keys: (?<=VK_)([A-Z0-9_]+) += +?([0-9A-Fa-fx]+)(?=;)
+CANCEL = 0x03
+CLEAR = 0x0C
+SHIFT = 0x10
+CONTROL = 0x11
+ALT = 0x12
+PAUSE = 0x13
+CAPS_LOCK = 0x14
+ESCAPE = 0x1B
+SPACE = 0x20
+PAGE_UP = 0x21
+PAGE_DOWN = 0x22
+END = 0x23
+HOME = 0x24
+LEFT = 0x25
+UP = 0x26
+RIGHT = 0x27
+DOWN = 0x28
+COMMA = 0x2C
+MINUS = 0x2D
+PERIOD = 0x2E
+SLASH = 0x2F
+0 = 0x30
+1 = 0x31
+2 = 0x32
+3 = 0x33
+4 = 0x34
+5 = 0x35
+6 = 0x36
+7 = 0x37
+8 = 0x38
+9 = 0x39
+SEMICOLON = 0x3B
+EQUALS = 0x3D
+A = 0x41
+B = 0x42
+C = 0x43
+D = 0x44
+E = 0x45
+F = 0x46
+G = 0x47
+H = 0x48
+I = 0x49
+J = 0x4A
+K = 0x4B
+L = 0x4C
+M = 0x4D
+N = 0x4E
+O = 0x4F
+P = 0x50
+Q = 0x51
+R = 0x52
+S = 0x53
+T = 0x54
+U = 0x55
+V = 0x56
+W = 0x57
+X = 0x58
+Y = 0x59
+Z = 0x5A
+OPEN_BRACKET = 0x5B
+BACK_SLASH = 0x5C
+CLOSE_BRACKET = 0x5D
+NUMPAD0 = 0x60
+NUMPAD1 = 0x61
+NUMPAD2 = 0x62
+NUMPAD3 = 0x63
+NUMPAD4 = 0x64
+NUMPAD5 = 0x65
+NUMPAD6 = 0x66
+NUMPAD7 = 0x67
+NUMPAD8 = 0x68
+NUMPAD9 = 0x69
+MULTIPLY = 0x6A
+ADD = 0x6B
+SEPARATER = 0x6C
+SUBTRACT = 0x6D
+DECIMAL = 0x6E
+DIVIDE = 0x6F
+DELETE = 0x7F
+NUM_LOCK = 0x90
+SCROLL_LOCK = 0x91
+F1 = 0x70
+F2 = 0x71
+F3 = 0x72
+F4 = 0x73
+F5 = 0x74
+F6 = 0x75
+F7 = 0x76
+F8 = 0x77
+F9 = 0x78
+F10 = 0x79
+F11 = 0x7A
+F12 = 0x7B
+F13 = 0xF000
+F14 = 0xF001
+F15 = 0xF002
+F16 = 0xF003
+F17 = 0xF004
+F18 = 0xF005
+F19 = 0xF006
+F20 = 0xF007
+F21 = 0xF008
+F22 = 0xF009
+F23 = 0xF00A
+F24 = 0xF00B
+PRINTSCREEN = 0x9A
+INSERT = 0x9B
+HELP = 0x9C
+META = 0x9D
+BACK_QUOTE = 0xC0
+QUOTE = 0xDE
+KP_UP = 0xE0
+KP_DOWN = 0xE1
+KP_LEFT = 0xE2
+KP_RIGHT = 0xE3
+DEAD_GRAVE = 0x80
+DEAD_ACUTE = 0x81
+DEAD_CIRCUMFLEX = 0x82
+DEAD_TILDE = 0x83
+DEAD_MACRON = 0x84
+DEAD_BREVE = 0x85
+DEAD_ABOVEDOT = 0x86
+DEAD_DIAERESIS = 0x87
+DEAD_ABOVERING = 0x88
+DEAD_DOUBLEACUTE = 0x89
+DEAD_CARON = 0x8a
+DEAD_CEDILLA = 0x8b
+DEAD_OGONEK = 0x8c
+DEAD_IOTA = 0x8d
+DEAD_VOICED_SOUND = 0x8e
+DEAD_SEMIVOICED_SOUND = 0x8f
+AMPERSAND = 0x96
+ASTERISK = 0x97
+QUOTEDBL = 0x98
+LESS = 0x99
+GREATER = 0xa0
+BRACELEFT = 0xa1
+BRACERIGHT = 0xa2
+AT = 0x0200
+COLON = 0x0201
+CIRCUMFLEX = 0x0202
+DOLLAR = 0x0203
+EURO_SIGN = 0x0204
+EXCLAMATION_MARK = 0x0205
+INVERTED_EXCLAMATION_MARK = 0x0206
+LEFT_PARENTHESIS = 0x0207
+NUMBER_SIGN = 0x0208
+PLUS = 0x0209
+RIGHT_PARENTHESIS = 0x020A
+UNDERSCORE = 0x020B
+WINDOWS = 0x020C
+CONTEXT_MENU = 0x020D
+FINAL = 0x0018
+CONVERT = 0x001C
+NONCONVERT = 0x001D
+ACCEPT = 0x001E
+MODECHANGE = 0x001F
+KANA = 0x0015
+KANJI = 0x0019
+ALPHANUMERIC = 0x00F0
+KATAKANA = 0x00F1
+HIRAGANA = 0x00F2
+FULL_WIDTH = 0x00F3
+HALF_WIDTH = 0x00F4
+ROMAN_CHARACTERS = 0x00F5
+ALL_CANDIDATES = 0x0100
+PREVIOUS_CANDIDATE = 0x0101
+CODE_INPUT = 0x0102
+JAPANESE_KATAKANA = 0x0103
+JAPANESE_HIRAGANA = 0x0104
+JAPANESE_ROMAN = 0x0105
+KANA_LOCK = 0x0106
+INPUT_METHOD_ON_OFF = 0x0107
+CUT = 0xFFD1
+COPY = 0xFFCD
+PASTE = 0xFFCF
+UNDO = 0xFFCB
+AGAIN = 0xFFC9
+FIND = 0xFFD0
+PROPS = 0xFFCA
+STOP = 0xFFC8
+COMPOSE = 0xFF20
+ALT_GRAPH = 0xFF7E
+BEGIN = 0xFF58
+UNDEFINED = 0x0
+```
+
+
+
+
## License
[MIT][2]. Chech the [LICENSE][3] file. All the credits go to the original developers.
diff --git a/img/bitmap_display_plus_plus.png b/img/bitmap_display_plus_plus.png
new file mode 100644
index 0000000..d1b9853
Binary files /dev/null and b/img/bitmap_display_plus_plus.png differ
diff --git a/img/img.png b/img/img.png
new file mode 100644
index 0000000..155f1b8
Binary files /dev/null and b/img/img.png differ