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