Initial revision
[ssr] / StraySrc / Libraries / Steel / c / akbd
1 /*
2 * akbd.c
3 *
4 * Really good keyboard handling
5 *
6 * © 1994-1998 Straylight
7 */
8
9 /*----- Licensing note ----------------------------------------------------*
10 *
11 * This file is part of Straylight's Steel library.
12 *
13 * Steel is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2, or (at your option)
16 * any later version.
17 *
18 * Steel is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with Steel. If not, write to the Free Software Foundation,
25 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 */
27
28 #include "os.h"
29 #include "akbd.h"
30 #include "bbc.h"
31
32 /*
33 * BOOL akbd_checkInternalKey(int ikey)
34 *
35 * Use
36 * Checks whether a given key is being pressed at the moment.
37 *
38 * Parameters
39 * int ikey == the internal key number of the key to check, as shown on page
40 * 1-849 of the RISC OS 3 Programmer's Reference Manual.
41 */
42
43 BOOL akbd_checkInternalKey(int ikey)
44 {
45 return (bbc_inkey(0xFF00 | (ikey ^ 0xFF)));
46 }
47
48 /*
49 * int akbd_translate(int chcode)
50 *
51 * Use
52 * Translates the given WIMP-type key number, as returned in a Key_Pressed
53 * (wimp_EKEY) event into a STEEL extended key number, which should
54 * distinguish almost every keypress available.
55 *
56 * Parameters
57 * int chcode == a WIMP-type keypress number
58 *
59 * Returns
60 * An extended keycode
61 */
62
63 #define akbd__WEIRDCTRL 0x000003BB
64
65 #define akbd__modify(a,b,c,d) \
66 switch (modifiers) \
67 { \
68 case 0: \
69 return (a); \
70 case 1: \
71 return (b); \
72 case 2: \
73 return (c); \
74 case 3: \
75 return (d); \
76 }
77
78 int akbd_translate(int chcode)
79 {
80 int modifiers;
81 int icode=0;
82 int base=0;
83
84 /* --- If it's a function key, the WIMP has translated it for us --- */
85
86 if ((chcode>=0x1CA) ||
87 (chcode>=0x180 && chcode<=0x1BF) ||
88 (chcode>='a' && chcode<='z') ||
89 (chcode>='A' && chcode<='Z') ||
90 (chcode>='[' && chcode<=']'))
91 return (chcode);
92
93 /* --- Work out the modifier status --- */
94
95 modifiers=0;
96 if (akbd_checkInternalKey(0))
97 modifiers|=1;
98 if (akbd_checkInternalKey(1))
99 modifiers|=2;
100
101 /* --- How many ways can you press Delete? --- */
102
103 if (chcode==0x7F)
104 {
105 switch (modifiers)
106 {
107 case 0:
108 return (0x7F);
109 case 1:
110 return (0x17F);
111 case 2:
112 return (0x01F);
113 case 3:
114 return (0x11F);
115 }
116 }
117
118 /* --- Check for variants of space --- */
119
120 if (chcode==' ')
121 akbd__modify(0x020,0x120,0x000,0x100);
122
123 /* --- The many faces of the Return key --- */
124
125 if (chcode==0x0D)
126 {
127 /* --- He pressed return (or maybe ^M, or even Enter...) --- */
128
129 if (akbd_checkInternalKey(60))
130 {
131 /* --- It was Enter, so return a variant of that --- */
132
133 akbd__modify(0x166,0x176,0x126,0x146);
134 }
135 else if (!akbd_checkInternalKey(101))
136 {
137 /* --- It *wasn't* ^M, so it must have been Return --- */
138
139 akbd__modify(0x01D,0x11D,0x13D,0x15D);
140 }
141 /* --- If it was ^M, the control key mashing will catch it --- */
142 }
143
144 /* --- Check for control keys --- */
145
146 if (chcode<0x1B)
147 {
148 if (akbd__WEIRDCTRL & (1<<chcode))
149 {
150 /* --- It's a control key, Jim, but not as we know it... --- */
151
152 static char intCodes[]={0,48,0,17,18,19,0,36,21,38};
153
154 if (chcode==0x008)
155 {
156 /* --- It's backspace, though it may be ^H --- */
157
158 if (!akbd_checkInternalKey(84) &&
159 !akbd_checkInternalKey(21))
160 {
161 /* --- It really is backspace, or a variant thereof --- */
162
163 akbd__modify(0x01C,0x11C,0x13C,0x15C);
164 }
165 }
166 if (chcode)
167 {
168 /* --- It's not a *really* weird key at least --- */
169
170 if (akbd_checkInternalKey(intCodes[chcode]))
171 {
172 /* --- It was a strange ^digit key press --- */
173
174 if (modifiers & 1)
175 return (chcode+0x150);
176 else
177 return (chcode+0x130);
178 }
179 }
180 else
181 {
182 /* --- The many things that return 0 --- */
183
184 if (akbd_checkInternalKey(39))
185 base=0;
186 else
187 base=2;
188 if (modifiers & 1)
189 return (0x150+base);
190 else
191 return (0x130+base);
192 }
193 }
194
195 /* --- Ok -- it's fairly sane then --- */
196
197 if (modifiers & 1)
198 return (chcode+0x100);
199 else
200 return (chcode);
201 }
202
203 /* --- Check for number key presses --- */
204
205 if (chcode>='0' && chcode<='9')
206 {
207 static char keypadTable[]={106,107,124,108,122,123,26,27,42,43};
208
209 if (akbd_checkInternalKey(keypadTable[chcode-'0']))
210 {
211 /* --- It was the keypad version, so we have to modify it --- */
212
213 return (chcode+(0x1C0-'0')+(modifiers<<4));
214 }
215 else
216 return (chcode);
217 }
218
219 /* --- Test for the rest of the keypad --- */
220
221 switch (chcode)
222 {
223 case '/': icode=74; base=0x161; break;
224 case '*': icode=91; base=0x162; break;
225 case '#': icode=90; base=0x163; break;
226 case '-': icode=59; base=0x164; break;
227 case '+': icode=58; base=0x165; break;
228 case '.': icode=76; base=0x167; break;
229 }
230 if (icode)
231 {
232 /* --- It could be a keypad key here, so check --- */
233
234 if (akbd_checkInternalKey(icode))
235 {
236 /* --- It is one of the other keypad keys, so return it modified --- */
237
238 akbd__modify(base,base+16,base-64,base-32);
239 }
240 }
241
242 /* --- The revolting gross (US-ism -- yuk) keys that are left --- */
243
244 switch (chcode)
245 {
246 case 0x01E:
247 /* --- Home, or maybe ^6 :-/ --- */
248
249 if (akbd_checkInternalKey(24))
250 {
251 if (modifiers & 1)
252 return (0x156);
253 else
254 return (0x136);
255 }
256 else
257 akbd__modify(0x01E,0x11E,0x13E,0x15E);
258 break;
259
260 case 0x01B:
261 /* --- Escape, or maybe ^[ :-/ --- */
262
263 if (akbd_checkInternalKey(56))
264 {
265 if (modifiers & 1)
266 return (0x14B);
267 else
268 return (0x12B);
269 }
270 else
271 akbd__modify(0x01B,0x11B,0x13B,0x15B);
272 break;
273
274 case 0x01C:
275 case 0x01D:
276 case 0x01F:
277 if (modifiers & 1)
278 return (chcode+0x130);
279 else
280 return (chcode+0x110);
281 break;
282 }
283
284 /* --- Hmm -- it seems sensible after all --- */
285
286 return (chcode);
287 }
288
289 /*
290 * BOOL akbd_pollsh(void)
291 *
292 * Use
293 * Returns whether the Shift key is pressed
294 */
295
296 BOOL akbd_pollsh(void)
297 {
298 return (akbd_checkInternalKey(0));
299 }
300
301 /*
302 * BOOL akbd_pollctl(void)
303 *
304 * Use
305 * Returns whether the Control key is pressed
306 */
307
308 BOOL akbd_pollctl(void)
309 {
310 return (akbd_checkInternalKey(1));
311 }
312
313 /*
314 * BOOL akbd_pollkey(int *code)
315 *
316 * Use
317 * Reports whether the user has typed ahead, and if so what the keypress
318 * was. Note that the keypresses returned are WIMP-type, not STEEL extended
319 * ones so you will have to use akbd_translate if you need the extended
320 * type.
321 *
322 * This call could be used to allow buffering of keypresses: on a
323 * Key_Pressed event you would call this routine until it returns FALSE
324 * and store the codes it returns in a buffer along with the code from the
325 * event.
326 */
327
328 BOOL akbd_pollkey(int *code)
329 {
330 int key;
331
332 /* --- Find out if there is a key waiting --- */
333
334 key=bbc_inkey(0);
335 if (key==-1)
336 return (FALSE);
337
338 /* --- Check for extended codes --- */
339
340 if (!key)
341 {
342 key=bbc_inkey(0);
343 if (key)
344 *code=key+0x100;
345 else
346 *code=0;
347 }
348 else
349 *code=key;
350
351 /* --- We found one --- */
352
353 return (TRUE);
354 }