1 /*
2 * KCemu -- The emulator for the KC85 homecomputer series and much more.
3 * Copyright (C) 1997-2010 Torsten Paul
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include <iostream>
21 #include <iomanip>
22
23 #include "kc/system.h"
24
25 #include "kc/z80.h"
26 #include "kc/keys.h"
27 #include "kc/keyb1.h"
28 #include "kc/keyb1k.h"
29
30 #include "libdbg/dbg.h"
31
Keyboard1(void)32 Keyboard1::Keyboard1(void)
33 {
34 init();
35 z80->register_ic(this);
36 }
37
38
~Keyboard1(void)39 Keyboard1::~Keyboard1(void)
40 {
41 z80->unregister_ic(this);
42 }
43
44 void
init(void)45 Keyboard1::init(void)
46 {
47 int a;
48
49 _shift = false;
50 _control = false;
51 _in_callback = false;
52 for (a = 0;a < MAX_KEYS;a++)
53 {
54 _keybuf[a].sym = -1;
55 _keybuf[a].code = -1;
56 }
57 }
58
59 int
decode_key(int keysym,bool press)60 Keyboard1::decode_key(int keysym, bool press)
61 {
62 return keysym;
63 }
64
65 void
keyPressed(int keysym,int keycode)66 Keyboard1::keyPressed(int keysym, int keycode)
67 {
68 /*
69 * ignore repeated key press events (e.g. generated by
70 * GTK that reports key repeat as keypress/keypress/keypress/...
71 * without the possibility to switch that off :-( )
72 */
73 for (int a = 0;a < MAX_KEYS;a++)
74 if (_keybuf[a].code == keycode)
75 return;
76
77 int k = decode_key(keysym, true);
78 if (k == -1)
79 return;
80
81 switch (keysym)
82 {
83 case KC_KEY_SHIFT:
84 _shift = __keys[k];
85 k = 0;
86 break;
87 case KC_KEY_CONTROL:
88 _control = __keys[k];
89 k = 0;
90 break;
91 default:
92 k = __keys[k];
93 break;
94 }
95
96 byte_t c1 = 0;
97 byte_t r1 = 0;
98 byte_t c2 = 0;
99 byte_t r2 = 0;
100
101 for (int a = 0;a < MAX_KEYS;a++)
102 {
103 if (_keybuf[a].code != -1)
104 {
105 /*
106 * row/column values of already pressed keys
107 */
108 r1 |= 1 << (((__keys[_keybuf[a].sym] >> 4) & 0x0f) - 1);
109 c1 |= 1 << (((__keys[_keybuf[a].sym] ) & 0x0f) - 1);
110 }
111 if (k != 0)
112 if (_keybuf[a].code == -1)
113 {
114 _keybuf[a].sym = k;
115 _keybuf[a].code = keycode;
116 /*
117 * row/column values of new pressed keys
118 */
119 r2 |= 1 << (((k >> 4) & 0x0f) - 1);
120 c2 |= 1 << (((k ) & 0x0f) - 1);
121 /*
122 * check for 2nd key (this generates duplicate entries for shift,
123 * ctrl, ... -- but with the keycode of the key itself)
124 */
125 k >>= 8;
126 }
127 }
128
129 DBG(2, form("KCemu/keyboard/1/key_press",
130 "##### Keyboard: keyPressed [%03x/%02x] {%c%c} "
131 "r/c: [%02x/%02x]=>[%02x/%02x] -",
132 keysym, keycode,
133 _shift > 0 ? 'S' : 's',
134 _control > 0 ? 'C' : 'c',
135 r1, c1, r1 | r2, c1 | c2));
136
137 for (int a = 0;a < MAX_KEYS;a++)
138 if (_keybuf[a].code != -1)
139 DBG(2, form("KCemu/keyboard/1/key_press",
140 " {%02d:%02x}", a, _keybuf[a].code));
141
142 DBG(2, form("KCemu/keyboard/1/key_press",
143 "\n"));
144
145 callback_B_in();
146 }
147
148 void
keyReleased(int keysym,int keycode)149 Keyboard1::keyReleased(int keysym, int keycode)
150 {
151 int a;
152
153 if (keysym == -1)
154 {
155 for (a = 0;a < MAX_KEYS;a++)
156 _keybuf[a].code = -1;
157 return;
158 }
159
160 if (keysym == KC_KEY_SHIFT)
161 _shift = 0;
162
163 if (keysym == KC_KEY_CONTROL)
164 _control = 0;
165
166 /*
167 * remove (maybe multiple) entries from keyboard buffer
168 */
169 for (a = 0;a < MAX_KEYS;a++)
170 if (_keybuf[a].code == keycode)
171 _keybuf[a].code = -1;
172
173 DBG(2, form("KCemu/keyboard/1/key_release",
174 "##### Keyboard: keyReleased [%03x/%02x] {%c%c} "
175 " -",
176 keysym, keycode,
177 _shift > 0 ? 'S' : 's',
178 _control > 0 ? 'C' : 'c'));
179
180 for (a = 0;a < MAX_KEYS;a++)
181 if (_keybuf[a].code != -1)
182 DBG(2, form("KCemu/keyboard/1/key_release",
183 " {%02d:%02x}", a, _keybuf[a].code));
184
185 DBG(2, form("KCemu/keyboard/1/key_release",
186 "\n"));
187
188 callback_B_in();
189 }
190
191 void
replayString(const char * text)192 Keyboard1::replayString(const char *text)
193 {
194 }
195
196 void
callback(void * data)197 Keyboard1::callback(void *data)
198 {
199 }
200
201 int
callback_A_in(void)202 Keyboard1::callback_A_in(void)
203 {
204 if (_in_callback)
205 return -1;
206
207 _in_callback = true;
208 byte_t b = ~pio2->in_B_DATA();
209
210 byte_t c = 0;
211 int count = 0;
212 for (int a = 0;a < MAX_KEYS;a++)
213 {
214 if (_keybuf[a].code == -1)
215 continue;
216
217 if (b & (1 << (((_keybuf[a].sym >> 4) & 0x0f) - 1)))
218 {
219 c |= 1 << (((_keybuf[a].sym) & 0x0f) - 1);
220 count++;
221 }
222 }
223
224 /*
225 * The shift key itself is only asserted when no other key is pressed.
226 * Otherwise this breaks the key handling for keys that are shifted
227 * in the pc layout but not shifted in the kc layout (like the ':' key
228 * that must not have the shift key pressed on the kc).
229 */
230 if ((count == 0) && (_shift > 0))
231 if (b & (1 << (((_shift >> 4) & 0x0f) - 1)))
232 c |= 1 << ((_shift & 0x0f) - 1);
233
234 if (_control > 0)
235 if (b & (1 << (((_control >> 4) & 0x0f) - 1)))
236 c |= 1 << (((_control) & 0x0f) - 1);
237
238 c = ~c;
239 #if 0
240 cout.form("##### Keyboard: Port A: new ext val: %02x [x = %d] -", c, x);
241 for (a = 0;a < MAX_KEYS;a++)
242 if (_keybuf[a].code != -1)
243 cout.form(" {%04x}", _keybuf[a].sym);
244 cout.form("\n");
245 #endif
246 pio2->set_A_EXT(0xff, c);
247 _in_callback = false;
248
249 return -1;
250 }
251
252 int
callback_B_in(void)253 Keyboard1::callback_B_in(void)
254 {
255 if (_in_callback)
256 return -1;
257
258 _in_callback = true;
259 byte_t b = ~pio2->in_A_DATA();
260
261 byte_t c = 0;
262 int count = 0;
263 for (int a = 0;a < MAX_KEYS;a++)
264 {
265 if (_keybuf[a].code == -1)
266 continue;
267
268 if (b & (1 << (((_keybuf[a].sym) & 0x0f) - 1)))
269 {
270 c |= 1 << (((_keybuf[a].sym >> 4) & 0x0f) - 1);
271 count++;
272 }
273 }
274
275 if ((count == 0) && (_shift > 0))
276 if (b & (1 << ((_shift & 0x0f) - 1)))
277 c |= 1 << (((_shift >> 4) & 0x0f) - 1);
278
279 if (_control > 0)
280 if (b & (1 << ((_control & 0x0f) - 1)))
281 c |= 1 << (((_control >> 4) & 0x0f) - 1);
282
283 c = ~c;
284 #if 0
285 cout.form("##### Keyboard: Port B: new ext val: %02x [x = %d] -", c, x);
286 for (a = 0;a < MAX_KEYS;a++)
287 if (_keybuf[a].code != -1)
288 cout.form(" {%04x}", _keybuf[a].sym);
289 cout.form("\n");
290 #endif
291 pio2->set_B_EXT(0xff, c);
292 _in_callback = false;
293
294 return -1;
295 }
296
297 void
reset(bool power_on)298 Keyboard1::reset(bool power_on)
299 {
300 init();
301 }
302
303 void
reti(void)304 Keyboard1::reti(void)
305 {
306 }
307