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 ];