1 /*
2 * PROPRIETARY INFORMATION. This software is proprietary to POWDER
3 * Development, and is not to be reproduced, transmitted, or disclosed
4 * in any way without written permission.
5 *
6 * Produced by: Jeff Lait
7 *
8 * POWDER Development
9 *
10 * NAME: input.cpp ( POWDER Library, C++ )
11 *
12 * COMMENTS:
13 * Routines to accept input...
14 */
15
16 #include "input.h"
17
18 #include "assert.h"
19 #include "gfxengine.h"
20 #include "input.h"
21 #include "control.h"
22 #include "rand.h"
23 #include "stylus.h"
24
25 #define KEYWIDTH 14
26 #define KEYHEIGHT 5
27 #define KEYTOP 6
28 #define KEYLEFT 1
29
30 #ifdef USING_SDL
31 #define TILEWIDTH (gfx_gettilewidth())
32 #define TILEHEIGHT (gfx_gettileheight())
33 #else
34 #define TILEWIDTH 8
35 #define TILEHEIGHT 8
36 #endif
37
38
39 // Given the direction, this determines the character...
40 char
input_getstatechar(int dx,int dy,bool shifted)41 input_getstatechar(int dx, int dy, bool shifted)
42 {
43 int code = 0;
44 int bits;
45
46 UT_ASSERT(dx || dy);
47
48 if (dx)
49 code = (dx < 0) ? 0 : 1;
50 else
51 code = (dy < 0) ? 2 : 3;
52
53 // Now, we could just have a bit field for the additional buttons,
54 // but that would make priority calculations difficult. Instead,
55 // we go:
56 // , A, B, L, | R, L+R, A+L, A+R,
57 // A+L+R, B+L, B+R, B+L+R,| A+B, A+B+L, A+B+R, A+B+L+R
58 static const int bitlut[16] =
59 // , A, B, A+B, L, L+A, L+B, L+A+B,
60 { 0, 1, 2, 12, 3, 6, 9, 13,
61 // R, R+A, R+B, R+A+B, R+L, R+L+A, R+L+B, R+L+B+A
62 4, 7, 10, 14, 5, 8, 11, 15 };
63
64 // 65 so we have the null terminator.
65 static const char charlut[65] =
66 "\b \t\n"
67 "abcd" "efgh" "ijkl" "mnop" "qrst" "uvwx" "yz'\""
68 "0123" "4567" "89!#"
69 "+-/*" "|_^&"
70 "()[]" "{}<>"
71 ".,:;";
72
73 static const char charlutshift[65] =
74 "\b \t\n"
75 "ABCD" "EFGH" "IJKL" "MNOP" "QRST" "UVWX" "YZ'\""
76 "0123" "4567" "89!#"
77 "+-/*" "|_^&"
78 "()[]" "{}<>"
79 ".,:;";
80
81 bits = (ctrl_rawpressed(BUTTON_A)) |
82 (ctrl_rawpressed(BUTTON_B) << 1) |
83 (ctrl_rawpressed(BUTTON_L) << 2) |
84 (ctrl_rawpressed(BUTTON_R) << 3);
85
86 // Mix in the X & Y so DS users have it even easier.
87 bits |= (ctrl_rawpressed(BUTTON_X) << 3);
88 bits |= (ctrl_rawpressed(BUTTON_Y) << 2);
89
90 code = code | (bitlut[bits] << 2);
91
92 if (shifted)
93 return charlutshift[code];
94 else
95 return charlut[code];
96 }
97
98 void
input_updategnomon(int gx,int gy,bool shifted)99 input_updategnomon(int gx, int gy, bool shifted)
100 {
101 int dx, dy;
102
103 for (dy = -1; dy <= 1; dy++)
104 {
105 for (dx = -1; dx <= 1; dx++)
106 {
107 if ((!dx) ^ (!dy))
108 {
109 gfx_printchar(gx+dx, gy+dy, input_getstatechar(dx, dy, shifted));
110 }
111 }
112 }
113 }
114
115 const char glbKeyboard[KEYWIDTH * KEYHEIGHT + 1] =
116 "=1234567890-\b\b"
117 " qwertyuiop\\ " SYMBOLSTRING_TRIDUDE
118 " asdfghjkl;' \n"
119 " zxcvbnm,./ \n"
120 "\t`\\ \b \n []\t ";
121
122 const char glbKeyboardShift[KEYWIDTH * KEYHEIGHT + 1] =
123 "+!@#$%^&*()_ \b"
124 " QWERTYUIOP| " SYMBOLSTRING_TRIDUDE
125 " ASDFGHJKL:\" \n"
126 " ZXCVBNM<>? \n"
127 "\t~| \b \n {}\t ";
128
129 char
input_lookupkey(int x,int y,bool shifted)130 input_lookupkey(int x, int y, bool shifted)
131 {
132 if (x < 0 || x >= KEYWIDTH)
133 return 0;
134 if (y < 0 || y >= KEYHEIGHT)
135 return 0;
136
137 if (shifted)
138 return glbKeyboardShift[x + y * KEYWIDTH];
139 else
140 return glbKeyboard[x + y * KEYWIDTH];
141 }
142
143 void
input_drawkeyboard(bool shifted)144 input_drawkeyboard(bool shifted)
145 {
146 // GBA has no stylus so gets no keyboard. They are stuck
147 // with the one true input method.
148 // That is, until the fateful day we decided to abandon
149 // the one true input method.
150 int x, y;
151 const char *key;
152
153 if (shifted)
154 key = glbKeyboardShift;
155 else
156 key = glbKeyboard;
157 for (y = 0; y < KEYHEIGHT; y++)
158 {
159 for (x = 0; x < KEYWIDTH; x++)
160 {
161 gfx_printchar(KEYLEFT+x*2, KEYTOP+y*2, *key);
162 key++;
163
164 gfx_setabsoverlay(x, 3+y, TILE_EMPTYSLOT);
165 }
166 }
167 }
168
169 void
input_erasecursor(int kx,int ky)170 input_erasecursor(int kx, int ky)
171 {
172 gfx_printchar(kx*2 + KEYLEFT-1, ky*2 + KEYTOP, ' ');
173 gfx_printchar(kx*2 + KEYLEFT+1, ky*2 + KEYTOP, ' ');
174 gfx_printchar(kx*2 + KEYLEFT, ky*2 + KEYTOP-1, ' ');
175 gfx_printchar(kx*2 + KEYLEFT, ky*2 + KEYTOP+1, ' ');
176 }
177
178 void
input_drawcursor(int kx,int ky)179 input_drawcursor(int kx, int ky)
180 {
181 gfx_printcolourchar(kx*2 + KEYLEFT-1, ky*2 + KEYTOP, SYMBOL_RIGHT, COLOUR_RED);
182 gfx_printcolourchar(kx*2 + KEYLEFT+1, ky*2 + KEYTOP, SYMBOL_LEFT, COLOUR_RED);
183 gfx_printcolourchar(kx*2 + KEYLEFT, ky*2 + KEYTOP-1, SYMBOL_DOWN, COLOUR_RED);
184 gfx_printcolourchar(kx*2 + KEYLEFT, ky*2 + KEYTOP+1, SYMBOL_UP, COLOUR_RED);
185 }
186
187 int
input_getchar(int gx,int gy,bool shifted)188 input_getchar(int gx, int gy, bool shifted)
189 {
190 STYLUSLOCK styluslock(REGION_KEYBOARD);
191 int sx, sy;
192
193 styluslock.setRange(KEYLEFT, KEYTOP,
194 KEYLEFT+2*KEYWIDTH-1, KEYTOP+2*KEYHEIGHT-1);
195
196 #ifdef HAS_KEYBOARD
197 while (1)
198 {
199 int key;
200
201 // We do a random just to keep things ticking...
202 rand_choice(3);
203 hamfake_rebuildScreen();
204 hamfake_awaitEvent();
205 key = hamfake_getKeyPress(false);
206
207 // Ignore mouse keys as we want the stylus lock to work.
208 if (key == GFX_KEYLMB || key == GFX_KEYMMB || key == GFX_KEYRMB)
209 key = 0;
210
211 if (key)
212 return key;
213
214 // Check stylus.
215 if (styluslock.getchartile(sx, sy))
216 {
217 key = input_lookupkey(sx, sy, shifted);
218 if (key)
219 return key;
220 }
221 }
222 #else
223 int dx, dy, key = 0;
224 // I have no idea what character this is!
225 static int key_x = 5, key_y = 2;
226
227 input_drawcursor(key_x, key_y);
228 while (1)
229 {
230 // We do a random just to keep things ticking...
231 rand_choice(3);
232
233 if (hamfake_forceQuit())
234 return '\n';
235
236 #ifdef USE_VIRTUAL_SCREEN
237 if (hamfake_hasbeenshaken())
238 {
239 return GFX_KEYF3;
240 }
241 #endif
242
243 hamfake_rebuildScreen();
244 hamfake_awaitEvent();
245
246 ctrl_getdir(dx, dy);
247 if (dx || dy)
248 {
249 // Move the current key.
250 input_erasecursor(key_x, key_y);
251 key_x += dx;
252 key_y += dy;
253 key_x %= KEYWIDTH;
254 key_y %= KEYHEIGHT;
255 if (key_x < 0)
256 key_x += KEYWIDTH;
257 if (key_y < 0)
258 key_y += KEYHEIGHT;
259
260 input_drawcursor(key_x, key_y);
261 }
262
263 if (ctrl_hit(BUTTON_A))
264 {
265 key = input_lookupkey(key_x, key_y, shifted);
266 if (key)
267 break;
268 }
269
270 // Other buttons are tied to certain built in keypresses.
271 if (ctrl_hit(BUTTON_L))
272 {
273 key = '\b';
274 break;
275 }
276
277 if (ctrl_hit(BUTTON_R))
278 {
279 key = ' ';
280 break;
281 }
282
283 if (ctrl_hit(BUTTON_B))
284 {
285 // This should be an Escape and thus quit without
286 // actually saving a line of text, except we don't support
287 // that option in general and it is much more useful to be
288 // able to hit enter without fiddling with our key position.
289 key = '\n';
290 break;
291 }
292
293 // Start makes sense to start the game so select your text
294 if (ctrl_hit(BUTTON_START))
295 {
296 key = '\n';
297 break;
298 }
299
300 // Select is for toggling shift - selecting the font?
301 if (ctrl_hit(BUTTON_SELECT))
302 {
303 key = '\t';
304 break;
305 }
306
307 // Check stylus.
308 if (styluslock.getchartile(sx, sy))
309 {
310 key = input_lookupkey(sx, sy, shifted);
311 if (key)
312 {
313 // Also adjust our button press location
314 input_erasecursor(key_x, key_y);
315 key_x = sx;
316 key_y = sy;
317 break;
318 }
319 }
320 }
321
322 input_erasecursor(key_x, key_y);
323
324 return key;
325 #endif
326 }
327
328 void
input_getline(char * text,int len,int lx,int ly,int gx,int gy,const char * initialtext)329 input_getline(char *text, int len, int lx, int ly, int gx, int gy,
330 const char *initialtext)
331 {
332 int pos = 0;
333 int c;
334 bool shifted = false;
335
336 #ifdef USE_VIRTUAL_SCREEN
337 // Ensure the latest text is on screen.
338 hamfake_rebuildScreen();
339 if (initialtext)
340 strcpy(glbInputData.myText, initialtext);
341 else
342 glbInputData.myText[0] = '\0';
343 glbInputData.myMaxLen = len;
344 glbInputData.myX = lx;
345 glbInputData.myY = ly;
346 hamfake_buttonreq(7, 0);
347
348 // On return we have our string!
349 int i;
350 for (i = 0; i < len; i++)
351 {
352 // Yes, I trust no one, not even myself.
353 text[i] = glbInputData.myText[i];
354 if (!text[i])
355 break;
356 }
357 text[i] = '\0';
358 return;
359 #else
360
361 // Wait for the person to release the a button...
362 #ifndef HAS_KEYBOARD
363 while (ctrl_anyrawpressed())
364 {
365 hamfake_awaitEvent();
366 }
367 #endif
368
369 // Clear any keyboard buffer.
370 hamfake_clearKeyboardBuffer();
371
372 // Input the initial text.
373 if (initialtext)
374 {
375 while (*initialtext)
376 {
377 c = *initialtext++;
378 if (pos < len)
379 {
380 text[pos] = c;
381 gfx_printchar(lx+pos, ly, c);
382 pos++;
383 }
384 }
385 }
386
387 gfx_nudgecenter(-TILEWIDTH/2, TILEHEIGHT/2);
388 input_drawkeyboard(shifted);
389
390 #ifdef USE_VIRTUAL_SCREEN
391 hamfake_hasbeenshaken();
392 #endif
393
394 while (1)
395 {
396 gfx_printchar(lx+pos, ly, SYMBOL_CURSOR);
397 c = input_getchar(gx, gy, shifted);
398
399 if (hamfake_forceQuit())
400 {
401 c = '\n';
402 }
403
404 switch (c)
405 {
406 case '\r':
407 case '\n':
408 text[pos] = '\0';
409 // Our absolute tiles need to be reset.
410 gfx_nudgecenter(0, 0);
411 gfx_refreshtiles();
412 return;
413
414 case '\b':
415 if (pos)
416 {
417 gfx_printchar(lx+pos, ly, ' ');
418 pos--;
419 }
420 break;
421
422 case '\t':
423 shifted = !shifted;
424 input_drawkeyboard(shifted);
425 break;
426
427 case GFX_KEYF3: // F3 because it is a tridude.
428 case SYMBOL_TRIDUDE:
429 while (pos)
430 {
431 gfx_printchar(lx+pos, ly, ' ');
432 pos--;
433 }
434 rand_name(text, len);
435 while (text[pos])
436 {
437 gfx_printchar(lx+pos, ly, text[pos]);
438 pos++;
439 }
440 break;
441
442 default:
443 if (pos < len && c < 256)
444 {
445 text[pos] = c;
446 gfx_printchar(lx+pos, ly, c);
447 pos++;
448 }
449 break;
450 }
451 hamfake_rebuildScreen();
452 }
453
454 // Our absolute tiles need to be reset.
455 gfx_nudgecenter(0, 0);
456 gfx_refreshtiles();
457 #endif
458 }
459
460