view src/pcjoy.c @ 0:c84446dfb3f5

initial add
author paulo@localhost
date Fri, 13 Mar 2009 00:39:12 -0700
parents
children
line source
1 /* PC joystick code
3 Copyright (C) 2006 Damian Yerrick <tepples+lj@spamcop.net>
5 This work 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.
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.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 Original game concept and design by Alexey Pajitnov.
20 The Software is not sponsored or endorsed by Alexey Pajitnov, Elorg,
21 or The Tetris Company LLC.
23 */
25 #include "pcjoy.h"
26 #include <allegro.h>
27 #include <string.h>
28 #include "ljpath.h"
30 extern const FONT *aver32, *aver16;
31 extern int bgColor, fgColor, hiliteColor;
33 static volatile int lastScancodePressed = -1;
34 static void (*oldKeyListener)(int scancode);
35 volatile int wantsClose = 0;
36 void ezPlaySample(const char *filename, int vol);
38 static void ljpcKeyListener(int scancode) {
39 if (!(scancode & 0x80)) {
40 lastScancodePressed = scancode;
41 }
42 if (oldKeyListener) {
43 oldKeyListener(scancode);
44 }
45 } END_OF_FUNCTION(ljpcKeyListener);
48 /**
49 * Presses the escape key when the user clicks the close box.
50 */
51 static void setWantsClose() {
52 wantsClose = 1;
53 }
55 static int withJoystick = 0;
57 #define N_VKEYS 14
58 #define N_PLAYERS 2
60 static const char keysFileName[] = "lj-keys.043";
62 static const struct pkeyMapping defaultKeymappings[N_PLAYERS][N_VKEYS] = {
63 {
64 // [0]: player 1
65 {-1, -1, KEY_UP},
66 {-1, -1, KEY_DOWN},
67 {-1, -1, KEY_LEFT},
68 {-1, -1, KEY_RIGHT},
69 {-1, -1, KEY_Z},
70 {-1, -1, KEY_X},
71 {-1, -1, KEY_S},
72 {-1, -1, KEY_SPACE},
73 {-1, -1, KEY_C},
74 {-1, -1, KEY_W},
75 {-1, -1, KEY_Q},
76 {-1, -1, KEY_E},
77 {-1, -1, KEY_ENTER},
78 {-1, -1, KEY_D}
79 },
80 {
81 // [1]: player 2
82 {-1, -1, KEY_UP},
83 {-1, -1, KEY_DOWN},
84 {-1, -1, KEY_LEFT},
85 {-1, -1, KEY_RIGHT},
86 {-1, -1, KEY_Z},
87 {-1, -1, KEY_X},
88 {-1, -1, KEY_S},
89 {-1, -1, KEY_SPACE},
90 {-1, -1, KEY_C},
91 {-1, -1, KEY_W},
92 {-1, -1, KEY_Q},
93 {-1, -1, KEY_E},
94 {-1, -1, KEY_ENTER},
95 {-1, -1, KEY_D}
96 }
97 };
99 static struct pkeyMapping keymappings[N_PLAYERS][N_VKEYS];
101 void getPkeyName(char *dst, int j, int s, int a) {
102 if (j < 0) {
103 if (a >= 0 && a < KEY_MAX) {
104 usprintf(dst, "Key %d (%s)", a, scancode_to_name(a));
105 } else {
106 usprintf(dst, "Key %d (???"")", a);
107 }
108 } else if (s < 0) {
109 usprintf(dst,
110 "Joy %d button %s",
111 j,
112 joy[j].button[a].name);
113 } else if (a < 0) {
114 usprintf(dst,
115 "Joy %d stick %s axis %s -",
116 j,
117 joy[j].stick[s].name,
118 joy[j].stick[s].axis[~a].name);
119 } else {
120 usprintf(dst,
121 "Joy %d stick %s axis %s +",
122 j,
123 joy[j].stick[s].name,
124 joy[j].stick[s].axis[a].name);
125 }
126 }
128 static int getPkeyState(int j, int s, int a) {
129 int k;
130 if (j < 0) {
131 k = key[a];
132 } else if (s < 0) {
133 k = joy[j].button[a].b;
134 } else if (a < 0) {
135 k = joy[j].stick[s].axis[~a].d1;
136 } else {
137 k = joy[j].stick[s].axis[a].d2;
138 }
139 return k;
140 }
142 const char *const vkeyNames[] = {
143 "Hard Drop (Up)",
144 "Soft Drop (Down)",
145 "Left",
146 "Right",
147 "Rotate Left",
148 "Rotate Right",
149 "Hold",
150 "Item (unused)",
151 "Alt. Rotate Left",
152 "Rotate Left Twice",
153 "Far Left",
154 "Far Right",
155 "Alt. Firm Drop",
156 "Alt. Hold",
157 "Macro G",
158 "Macro H"
159 };
161 static int getVkeyState(int player, int vkey) {
162 int j = keymappings[player][vkey].joy;
163 int s = keymappings[player][vkey].stick;
164 int a = keymappings[player][vkey].axis;
166 return getPkeyState(j, s, a);
167 }
169 LJBits readPad(unsigned int player) {
170 int keys = 0;
171 poll_joystick();
173 for (int i = 0;
174 i < N_VKEYS;
175 ++i) {
176 if (getVkeyState(player, i)) {
177 keys |= 1 << i;
178 }
179 }
180 return keys;
181 }
183 LJBits menuReadPad(void) {
184 if (key[KEY_ENTER]) {
185 return VKEY_ROTR | VKEY_START;
186 } else if (key[KEY_ESC]) {
187 return VKEY_ROTL;
188 } else if (key[KEY_UP]) {
189 return VKEY_UP;
190 } else if (key[KEY_DOWN]) {
191 return VKEY_DOWN;
192 } else if (key[KEY_LEFT]) {
193 return VKEY_LEFT;
194 } else if (key[KEY_RIGHT]) {
195 return VKEY_RIGHT;
196 } else {
197 return readPad(0) | readPad(1);
198 }
199 }
201 // These contain the states of ALL buttons on ALL
202 // joysticks
203 static LJBits lastConfigButtons[8];
204 static LJBits lastConfigStickAxis[8];
206 static int newButton(int *outJ, int *outS, int *outA) {
207 poll_joystick();
208 int found = 0;
210 if (lastScancodePressed >= 0) {
211 *outJ = -1;
212 *outS = -1;
213 *outA = lastScancodePressed;
214 lastScancodePressed = -1;
215 return 1;
216 }
218 for (int j = 0;
219 j < num_joysticks;
220 ++j) {
221 LJBits cur = 0;
223 for (int b = 0; b < joy[j].num_buttons; ++b) {
224 if (joy[j].button[b].b) {
225 if (!(lastConfigButtons[j] & (1 << b)) && !found) {
226 *outJ = j;
227 *outS = -1;
228 *outA = b;
229 found = 1;
230 }
231 cur |= 1 << b;
232 }
233 }
234 lastConfigButtons[j] = cur;
235 }
236 if (found) {
237 return 1;
238 }
240 for (int j = 0;
241 j < num_joysticks;
242 ++j) {
243 LJBits cur = 0;
244 LJBits mask = 1;
246 for (int s = 0; s < joy[j].num_sticks; ++s) {
247 for (int a = 0; a < joy[j].stick[s].num_axis; ++a) {
248 if (joy[j].stick[s].axis[a].d1) {
249 if (!(lastConfigStickAxis[j] & mask) && !found) {
250 *outJ = j;
251 *outS = s;
252 *outA = ~a;
253 found = 1;
254 }
255 cur |= mask;
256 }
257 mask <<= 1;
258 if (joy[j].stick[s].axis[a].d2) {
259 if (!(lastConfigStickAxis[j] & mask) && !found) {
260 *outJ = j;
261 *outS = s;
262 *outA = a;
263 found = 1;
264 }
265 cur |= mask;
266 }
267 mask <<= 1;
268 }
269 }
270 lastConfigStickAxis[j] = cur;
271 }
272 return found;
273 }
275 static void clearNewButton(void) {
276 int j, s, a;
277 while (newButton(&j, &s, &a));
278 }
280 void loadKeys(const char *filename) {
281 FILE *fp = ljfopen(filename, "rb");
283 memcpy(keymappings, defaultKeymappings, sizeof(keymappings));
284 if (fp) {
285 for (unsigned int player = 0; player < 2; ++player) {
286 for (unsigned int vkey = 0;
287 vkey < N_VKEYS;
288 ++vkey) {
289 int j = fgetc(fp);
290 int s = fgetc(fp);
291 int a = fgetc(fp);
293 if (a == EOF) {
294 break;
295 }
296 keymappings[player][vkey].joy = j;
297 keymappings[player][vkey].stick = s;
298 keymappings[player][vkey].axis = a;
299 }
300 }
301 fclose(fp);
302 }
303 }
305 void saveKeys(const char *filename) {
306 FILE *fp = ljfopen(filename, "wb");
308 if (fp) {
309 for (unsigned int player = 0; player < 2; ++player) {
310 for (unsigned int vkey = 0;
311 vkey < N_VKEYS && !feof(fp);
312 ++vkey) {
313 fputc(keymappings[player][vkey].joy, fp);
314 fputc(keymappings[player][vkey].stick, fp);
315 fputc(keymappings[player][vkey].axis, fp);
316 }
317 }
318 fclose(fp);
319 }
320 }
322 #define VKEY_ROWHT 24
323 #define VKEY_TOP 120
325 void drawVkeyRow(int vkey, int hilite) {
326 char name[256];
327 int y = VKEY_TOP + vkey * VKEY_ROWHT;
329 rectfill(screen,
330 16, y, 719, y + VKEY_ROWHT - 1,
331 hilite ? hiliteColor : bgColor);
332 textout_ex(screen, aver16, vkeyNames[vkey], 24, y + 4, fgColor, -1);
333 for (int player = 0; player < N_PLAYERS; ++player) {
334 if (player + 1 == hilite) {
335 rect(screen,
336 240 + 240 * player, y,
337 479 + 240 * player, y + VKEY_ROWHT - 1,
338 fgColor);
339 }
340 getPkeyName(name,
341 keymappings[player][vkey].joy,
342 keymappings[player][vkey].stick,
343 keymappings[player][vkey].axis);
344 textout_ex(screen, aver16, name, 240 + 240 * player, y + 4, fgColor, -1);
345 }
346 }
348 /**
349 * Waits for a key or button press. If any key but Esc is pressed,
350 * reassigns the vkey. Otherwise, does nothing.
351 * @param vkey the index of the vkey to reassign
352 * @return 0 if key not changed; nonzero if key was changed
353 */
354 static int changeKey(int player, int vkey) {
355 int changed = 0;
356 int phase = 0;
358 clearNewButton();
359 while (!changed) {
360 int j, s, a;
362 if (phase == 5) {
363 drawVkeyRow(vkey, 0);
364 } else if (phase == 0) {
365 drawVkeyRow(vkey, player + 1);
366 phase = 15;
367 }
368 --phase;
370 if (keypressed()) {
371 int scancode;
372 ureadkey(&scancode);
373 if (scancode == KEY_ESC) {
374 changed = -1;
375 }
376 }
377 if (vkey < N_VKEYS && newButton(&j, &s, &a)) {
378 if (j >= 0 || s > 0 || a != KEY_ESC) {
379 keymappings[player][vkey].joy = j;
380 keymappings[player][vkey].stick = s;
381 keymappings[player][vkey].axis = a;
382 ezPlaySample("nextS_wav", 128);
383 changed = 1;
384 } else {
385 changed = -1;
386 }
387 }
388 if (wantsClose) {
389 changed = -1;
390 }
392 rest(30);
393 }
395 // Draw new vkey value
396 drawVkeyRow(vkey, 0);
397 return changed > 0;
398 }
400 void configureKeys(void) {
401 clear_to_color(screen, bgColor);
402 textout_ex(screen, aver32, "LOCKJAW > Game Keys", 16, 32, fgColor, -1);
403 textout_ex(screen, aver16,
404 "Use arrow keys to select a key. To reassign the selected key, press Enter",
405 40, 80, fgColor, -1);
406 textout_ex(screen, aver16,
407 "and then the key you want to use. When done, press Esc.",
408 40, 96, fgColor, -1);
410 // Draw each vkey's name
411 for (int vkey = 0; vkey < N_VKEYS; ++vkey) {
412 drawVkeyRow(vkey, 0);
413 }
415 clearNewButton();
416 int vkey = 0;
417 int player = 0;
419 drawVkeyRow(vkey, player + 1);
421 while (vkey >= 0 && !wantsClose) {
422 int scancode = 0;
424 rest(30);
425 if (keypressed()) {
426 ureadkey(&scancode);
427 }
429 switch (scancode) {
431 case KEY_RIGHT:
432 if (player < N_PLAYERS - 1) {
433 ezPlaySample("shift_wav", 128);
434 drawVkeyRow(vkey, 0);
435 ++player;
436 drawVkeyRow(vkey, player + 1);
437 }
438 break;
440 case KEY_LEFT:
441 if (player > 0) {
442 ezPlaySample("shift_wav", 128);
443 drawVkeyRow(vkey, 0);
444 --player;
445 drawVkeyRow(vkey, player + 1);
446 }
447 break;
449 case KEY_UP:
450 if (vkey > 0) {
451 ezPlaySample("shift_wav", 128);
452 drawVkeyRow(vkey, 0);
453 --vkey;
454 drawVkeyRow(vkey, player + 1);
455 }
456 break;
457 case KEY_DOWN:
458 if (vkey < N_VKEYS - 1) {
459 ezPlaySample("shift_wav", 128);
460 drawVkeyRow(vkey, 0);
461 ++vkey;
462 drawVkeyRow(vkey, player + 1);
463 }
464 break;
465 case KEY_ENTER:
466 ezPlaySample("rotate_wav", 96);
467 while (vkey < N_VKEYS && changeKey(player, vkey)) {
468 rest(150);
469 ++vkey;
470 }
471 if (vkey >= N_VKEYS) {
472 ezPlaySample("land_wav", 128);
473 vkey = N_VKEYS - 1;
474 } else {
475 ezPlaySample("nextO_wav", 128);
476 }
477 drawVkeyRow(vkey, player + 1);
478 break;
479 case KEY_ESC:
480 vkey = -1;
481 break;
482 }
483 }
484 saveKeys(keysFileName);
485 ezPlaySample("line_wav", 128);
486 }
489 void initKeys(void) {
490 LOCK_FUNCTION(ljpcKeyListener);
491 LOCK_VARIABLE(lastScancodePressed);
492 LOCK_VARIABLE(oldKeyListener);
493 LOCK_FUNCTION(setWantsClose);
494 LOCK_VARIABLE(wantsClose);
496 oldKeyListener = keyboard_lowlevel_callback;
497 keyboard_lowlevel_callback = ljpcKeyListener;
498 withJoystick = !install_joystick(JOY_TYPE_AUTODETECT);
499 loadKeys(keysFileName);
500 set_close_button_callback(setWantsClose);
501 }