1 /** 2 Copyright: Copyright (c) 2013-2014 Andrey Penechko. 3 License: a$(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 4 Authors: Andrey Penechko. 5 */ 6 7 8 module emulator.dcpu.devices.generickeyboard; 9 10 import std.array; 11 import std.bitmanip; 12 import std.stdio; 13 14 import anchovy.core.input; 15 import anchovy.graphics.bitmap; 16 17 import emulator.dcpu.devices.idevice; 18 import emulator.dcpu.emulator; 19 import emulator.dcpu.dcpu; 20 import emulator.utils.ringbuffer; 21 22 @trusted nothrow: 23 24 /++ 25 + Generic keyboard (compatible) v1.0 26 + See 'docs/generic keyboard.txt' for specification. 27 +/ 28 29 class GenericKeyboard(Cpu) : IDevice!Cpu 30 { 31 protected: 32 Emulator!Cpu _emulator; 33 ushort interruptMessage; 34 RingBuffer!(ushort, 256) buffer; 35 BitArray pressedKeys; 36 37 /// 38 bool triggeredInterrupt = false; 39 40 public: 41 42 this() 43 { 44 pressedKeys.length = 0x91 + 1; // control + 1. total keys 45 } 46 47 override void attachEmulator(Emulator!Cpu emulator) 48 { 49 _emulator = emulator; 50 reset(); 51 } 52 53 override uint handleInterrupt() 54 { 55 ushort aRegister = _emulator.dcpu.regs.a; // A register 56 ushort bRegister = _emulator.dcpu.regs.b; // B register 57 58 switch(aRegister) 59 { 60 // Clear keyboard buffer 61 case 0: 62 buffer.clear(); 63 return 0; 64 65 // Get next key from key buffer 66 case 1: 67 if (buffer.length > 0) 68 { 69 _emulator.dcpu.regs.c = buffer.front; 70 buffer.popFront; 71 } 72 else 73 { 74 _emulator.dcpu.regs.c = 0; 75 } 76 //if (_emulator.dcpu.reg[2])writeln("next key ", _emulator.dcpu.reg[2]); 77 return 0; 78 79 // Is key pressed 80 case 2: 81 if (bRegister <= 0x91) 82 _emulator.dcpu.regs.c = pressedKeys[bRegister]; 83 else 84 _emulator.dcpu.regs.c = 0; 85 //writeln("is key pressed ", _emulator.dcpu.reg_c); 86 return 0; 87 88 // Set interrupt message 89 case 3: 90 interruptMessage = bRegister; 91 return 0; 92 93 default: 94 break; 95 } 96 97 return 0; 98 } 99 100 void onKey(KeyCode keyCode, uint modifiers, bool pressed) 101 { 102 ushort code = 0; 103 104 if (keyCode <= 348) 105 { 106 107 if (modifiers & KeyModifiers.SHIFT) 108 { 109 code = shiftScancodes[keyCode]; 110 } 111 else 112 { 113 code = bareScancodes[keyCode]; 114 } 115 } 116 117 if (code != 0) 118 { 119 if (code >= 0x09 && code <= 0x91) //valid keys 120 { 121 pressedKeys[code] = pressed; 122 123 if (pressed) 124 { 125 buffer.pushBack(code); 126 } 127 } 128 129 if (!triggeredInterrupt && interruptMessage > 0) 130 { 131 triggerInterrupt(_emulator.dcpu, interruptMessage); 132 triggeredInterrupt = true; 133 } 134 } 135 } 136 137 bool isPrintableChar(ushort charCode) 138 { 139 return (charCode >= 0x20 && charCode <= 0x7f) || charCode == 0x09; 140 } 141 142 /// Called when application does rendering 143 override void updateFrame() 144 { 145 triggeredInterrupt = false; 146 } 147 148 /// Returns: 32 bit word identifying the hardware id. 149 override uint hardwareId() @property 150 { 151 return 0x30cf7406; 152 } 153 154 /// Returns: 16 bit word identifying the hardware version. 155 override ushort hardwareVersion() @property 156 { 157 return 1; 158 } 159 160 /// Returns: 32 bit word identifying the manufacturer 161 override uint manufacturer() @property 162 { 163 return 0; 164 } 165 166 override void commitFrame(ulong frameNumber) 167 { 168 169 } 170 171 override void discardFrame() 172 { 173 174 } 175 176 override void undoFrames(ulong numFrames) 177 { 178 179 } 180 181 override void discardUndoStack() 182 { 183 184 } 185 186 override size_t undoStackSize() @property 187 { 188 return 0; 189 } 190 191 protected: 192 void reset() 193 { 194 pressedKeys.length = 0; 195 pressedKeys.length = 0x91 + 1; // control + 1. total keys 196 buffer.clear(); 197 } 198 } 199 200 // Mapped from anchovy.core.input.KeyCode to generic keyboard codes. (Mostly ASCII) 201 // On 0x09 TAB mapping added. 202 203 // When shift key IS NOT pressed. From 0 to 348 204 static immutable ushort[] bareScancodes = [ 205 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 206 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0, 44, 45, 46, 47, 48, 49, 50, 207 51, 52, 53, 54, 55, 56, 57, 0, 59, 0, 61, 0, 0, 0, 97, 98, 99, 100, 101, 102, 103, 208 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 209 120, 121, 122, 91, 210 92, 93, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 211 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 212 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 213 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 214 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 215 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 216 0, 0, 0, 0, 0x11, 0x9, 0x10, 0x12, 0x13, 0x83, 0x82, 0x81, 0x80, 0, 0, 0, 0, 0, 217 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 218 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 49, 50, 219 51, 52, 53, 54, 55, 56, 57, 46, 47, 42, 45, 43, 0x11, 61, 0, 0, 0, 0x90, 0x91, 220 0, 0, 0x90, 0x91, 0, 0, 0, 221 ]; 222 223 // When shift key IS pressed. From 0 to 348 224 static immutable ushort[] shiftScancodes = [ 225 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 226 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 0, 60, 95, 62, 63, 41, 33, 64, 227 35, 36, 37, 94, 38, 42, 40, 0, 58, 0, 43, 0, 0, 0, 65, 66, 67, 68, 69, 70, 71, 228 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123, 229 124, 125, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 231 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 233 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 234 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 235 0, 0, 0, 0, 0, 0x11, 0x9, 0x10, 0x12, 0x13, 0x83, 0x82, 0x81, 0x80, 0, 0, 0, 0, 236 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 237 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 49, 50, 238 51, 52, 53, 54, 55, 56, 57, 46, 47, 42, 45, 43, 0x11, 61, 0, 0, 0, 0x90, 0x91, 239 0, 0, 0x90, 0x91, 0, 0, 0, 240 ];