1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
12 #include "libgame/libgame.h"
25 #define DEBUG_EVENTS 0
27 #define DEBUG_EVENTS_BUTTON (DEBUG_EVENTS * 0)
28 #define DEBUG_EVENTS_MOTION (DEBUG_EVENTS * 0)
29 #define DEBUG_EVENTS_WINDOW (DEBUG_EVENTS * 0)
30 #define DEBUG_EVENTS_FINGER (DEBUG_EVENTS * 0)
31 #define DEBUG_EVENTS_TEXT (DEBUG_EVENTS * 1)
32 #define DEBUG_EVENTS_KEY (DEBUG_EVENTS * 1)
35 static boolean cursor_inside_playfield = FALSE;
36 static int cursor_mode_last = CURSOR_DEFAULT;
37 static unsigned int special_cursor_delay = 0;
38 static unsigned int special_cursor_delay_value = 1000;
40 /* event filter especially needed for SDL event filtering due to
41 delay problems with lots of mouse motion events when mouse button
42 not pressed (X11 can handle this with 'PointerMotionHintMask') */
44 /* event filter addition for SDL2: as SDL2 does not have a function to enable
45 or disable keyboard auto-repeat, filter repeated keyboard events instead */
47 static int FilterEventsExt(const Event *event)
51 #if defined(TARGET_SDL2)
52 /* skip repeated key press events if keyboard auto-repeat is disabled */
53 if (event->type == EVENT_KEYPRESS &&
59 /* non-motion events are directly passed to event handler functions */
60 if (event->type != EVENT_MOTIONNOTIFY)
63 motion = (MotionEvent *)event;
64 cursor_inside_playfield = (motion->x >= SX && motion->x < SX + SXSIZE &&
65 motion->y >= SY && motion->y < SY + SYSIZE);
67 /* do no reset mouse cursor before all pending events have been processed */
68 if (gfx.cursor_mode == cursor_mode_last &&
69 ((effectiveGameStatus() == GAME_MODE_TITLE &&
70 gfx.cursor_mode == CURSOR_NONE) ||
71 (game_status == GAME_MODE_PLAYING &&
72 gfx.cursor_mode == CURSOR_PLAYFIELD)))
74 SetMouseCursor(CURSOR_DEFAULT);
76 DelayReached(&special_cursor_delay, 0);
78 cursor_mode_last = CURSOR_DEFAULT;
81 /* skip mouse motion events without pressed button outside level editor */
82 if (button_status == MB_RELEASED &&
83 game_status != GAME_MODE_EDITOR && game_status != GAME_MODE_PLAYING)
89 #if defined(TARGET_SDL2)
90 int FilterEvents(void *userdata, Event *event)
92 return FilterEventsExt(event);
95 int FilterEvents(const Event *event)
97 return FilterEventsExt(event);
101 /* to prevent delay problems, skip mouse motion events if the very next
102 event is also a mouse motion event (and therefore effectively only
103 handling the last of a row of mouse motion events in the event queue) */
105 boolean SkipPressedMouseMotionEvent(const Event *event)
107 /* nothing to do if the current event is not a mouse motion event */
108 if (event->type != EVENT_MOTIONNOTIFY)
111 /* only skip motion events with pressed button outside level editor */
112 if (button_status == MB_RELEASED ||
113 game_status == GAME_MODE_EDITOR || game_status == GAME_MODE_PLAYING)
120 PeekEvent(&next_event);
122 /* if next event is also a mouse motion event, skip the current one */
123 if (next_event.type == EVENT_MOTIONNOTIFY)
130 /* this is only really needed for non-SDL targets to filter unwanted events;
131 when using SDL with properly installed event filter, this function can be
132 replaced with a simple "NextEvent()" call, but it doesn't hurt either */
134 boolean NextValidEvent(Event *event)
136 while (PendingEvent())
138 boolean handle_this_event = FALSE;
142 if (FilterEventsExt(event))
143 handle_this_event = TRUE;
145 if (SkipPressedMouseMotionEvent(event))
146 handle_this_event = FALSE;
148 if (handle_this_event)
159 if (PendingEvent()) /* got event */
163 while (NextValidEvent(&event))
167 case EVENT_BUTTONPRESS:
168 case EVENT_BUTTONRELEASE:
169 HandleButtonEvent((ButtonEvent *) &event);
172 case EVENT_MOTIONNOTIFY:
173 HandleMotionEvent((MotionEvent *) &event);
176 #if defined(TARGET_SDL2)
177 case SDL_WINDOWEVENT:
178 HandleWindowEvent((WindowEvent *) &event);
181 case EVENT_FINGERPRESS:
182 case EVENT_FINGERRELEASE:
183 case EVENT_FINGERMOTION:
184 HandleFingerEvent((FingerEvent *) &event);
187 case EVENT_TEXTINPUT:
188 HandleTextEvent((TextEvent *) &event);
191 case SDL_APP_WILLENTERBACKGROUND:
192 case SDL_APP_DIDENTERBACKGROUND:
193 case SDL_APP_WILLENTERFOREGROUND:
194 case SDL_APP_DIDENTERFOREGROUND:
195 HandlePauseResumeEvent((PauseResumeEvent *) &event);
200 case EVENT_KEYRELEASE:
201 HandleKeyEvent((KeyEvent *) &event);
205 HandleOtherEvents(&event);
212 if (effectiveGameStatus() == GAME_MODE_TITLE)
214 /* when showing title screens, hide mouse pointer (if not moved) */
216 if (gfx.cursor_mode != CURSOR_NONE &&
217 DelayReached(&special_cursor_delay, special_cursor_delay_value))
219 SetMouseCursor(CURSOR_NONE);
222 else if (game_status == GAME_MODE_PLAYING && !tape.pausing)
224 /* when playing, display a special mouse pointer inside the playfield */
226 if (gfx.cursor_mode != CURSOR_PLAYFIELD &&
227 cursor_inside_playfield &&
228 DelayReached(&special_cursor_delay, special_cursor_delay_value))
230 SetMouseCursor(CURSOR_PLAYFIELD);
233 else if (gfx.cursor_mode != CURSOR_DEFAULT)
235 SetMouseCursor(CURSOR_DEFAULT);
238 /* this is set after all pending events have been processed */
239 cursor_mode_last = gfx.cursor_mode;
242 /* also execute after pending events have been processed before */
245 /* don't use all CPU time when idle; the main loop while playing
246 has its own synchronization and is CPU friendly, too */
248 if (game_status == GAME_MODE_PLAYING)
254 if (!PendingEvent()) /* delay only if no pending events */
258 /* refresh window contents from drawing buffer, if needed */
261 if (game_status == GAME_MODE_QUIT)
266 void HandleOtherEvents(Event *event)
271 HandleExposeEvent((ExposeEvent *) event);
274 case EVENT_UNMAPNOTIFY:
276 /* This causes the game to stop not only when iconified, but also
277 when on another virtual desktop, which might be not desired. */
278 SleepWhileUnmapped();
284 HandleFocusEvent((FocusChangeEvent *) event);
287 case EVENT_CLIENTMESSAGE:
288 HandleClientMessageEvent((ClientMessageEvent *) event);
291 #if defined(TARGET_SDL)
292 case SDL_JOYAXISMOTION:
293 case SDL_JOYBUTTONDOWN:
294 case SDL_JOYBUTTONUP:
295 HandleJoystickEvent(event);
299 HandleWindowManagerEvent(event);
308 void ClearEventQueue()
310 while (PendingEvent())
318 case EVENT_BUTTONRELEASE:
319 button_status = MB_RELEASED;
322 case EVENT_KEYRELEASE:
327 HandleOtherEvents(&event);
333 void ClearPlayerAction()
337 /* simulate key release events for still pressed keys */
338 key_joystick_mapping = 0;
339 for (i = 0; i < MAX_PLAYERS; i++)
340 stored_player[i].action = 0;
343 void SleepWhileUnmapped()
345 boolean window_unmapped = TRUE;
347 KeyboardAutoRepeatOn();
349 while (window_unmapped)
357 case EVENT_BUTTONRELEASE:
358 button_status = MB_RELEASED;
361 case EVENT_KEYRELEASE:
362 key_joystick_mapping = 0;
365 case EVENT_MAPNOTIFY:
366 window_unmapped = FALSE;
369 case EVENT_UNMAPNOTIFY:
370 /* this is only to surely prevent the 'should not happen' case
371 * of recursively looping between 'SleepWhileUnmapped()' and
372 * 'HandleOtherEvents()' which usually calls this funtion.
377 HandleOtherEvents(&event);
382 if (game_status == GAME_MODE_PLAYING)
383 KeyboardAutoRepeatOffUnlessAutoplay();
386 void HandleExposeEvent(ExposeEvent *event)
390 void HandleButtonEvent(ButtonEvent *event)
392 #if DEBUG_EVENTS_BUTTON
393 Error(ERR_DEBUG, "BUTTON EVENT: button %d %s, x/y %d/%d\n",
395 event->type == EVENT_BUTTONPRESS ? "pressed" : "released",
399 motion_status = FALSE;
401 if (event->type == EVENT_BUTTONPRESS)
402 button_status = event->button;
404 button_status = MB_RELEASED;
406 HandleButton(event->x, event->y, button_status, event->button);
409 void HandleMotionEvent(MotionEvent *event)
411 if (!PointerInWindow(window))
412 return; /* window and pointer are on different screens */
414 if (button_status == MB_RELEASED && game_status != GAME_MODE_EDITOR)
417 motion_status = TRUE;
419 #if DEBUG_EVENTS_MOTION
420 Error(ERR_DEBUG, "MOTION EVENT: button %d moved, x/y %d/%d\n",
421 button_status, event->x, event->y);
424 HandleButton(event->x, event->y, button_status, button_status);
427 #if defined(TARGET_SDL2)
429 void HandleWindowEvent(WindowEvent *event)
431 #if DEBUG_EVENTS_WINDOW
432 int subtype = event->event;
435 (subtype == SDL_WINDOWEVENT_SHOWN ? "SDL_WINDOWEVENT_SHOWN" :
436 subtype == SDL_WINDOWEVENT_HIDDEN ? "SDL_WINDOWEVENT_HIDDEN" :
437 subtype == SDL_WINDOWEVENT_EXPOSED ? "SDL_WINDOWEVENT_EXPOSED" :
438 subtype == SDL_WINDOWEVENT_MOVED ? "SDL_WINDOWEVENT_MOVED" :
439 subtype == SDL_WINDOWEVENT_SIZE_CHANGED ? "SDL_WINDOWEVENT_SIZE_CHANGED" :
440 subtype == SDL_WINDOWEVENT_RESIZED ? "SDL_WINDOWEVENT_RESIZED" :
441 subtype == SDL_WINDOWEVENT_MINIMIZED ? "SDL_WINDOWEVENT_MINIMIZED" :
442 subtype == SDL_WINDOWEVENT_MAXIMIZED ? "SDL_WINDOWEVENT_MAXIMIZED" :
443 subtype == SDL_WINDOWEVENT_RESTORED ? "SDL_WINDOWEVENT_RESTORED" :
444 subtype == SDL_WINDOWEVENT_ENTER ? "SDL_WINDOWEVENT_ENTER" :
445 subtype == SDL_WINDOWEVENT_LEAVE ? "SDL_WINDOWEVENT_LEAVE" :
446 subtype == SDL_WINDOWEVENT_FOCUS_GAINED ? "SDL_WINDOWEVENT_FOCUS_GAINED" :
447 subtype == SDL_WINDOWEVENT_FOCUS_LOST ? "SDL_WINDOWEVENT_FOCUS_LOST" :
448 subtype == SDL_WINDOWEVENT_CLOSE ? "SDL_WINDOWEVENT_CLOSE" :
451 Error(ERR_DEBUG, "WINDOW EVENT: '%s', %ld, %ld",
452 event_name, event->data1, event->data2);
455 if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED ||
456 event->event == SDL_WINDOWEVENT_RESIZED ||
457 event->event == SDL_WINDOWEVENT_EXPOSED)
460 if (event->event == SDL_WINDOWEVENT_RESIZED && !video.fullscreen_enabled)
462 int new_window_width = event->data1;
463 int new_window_height = event->data2;
465 // if window size has changed after resizing, calculate new scaling factor
466 if (new_window_width != video.window_width ||
467 new_window_height != video.window_height)
469 int new_xpercent = (100 * new_window_width / video.width);
470 int new_ypercent = (100 * new_window_height / video.height);
472 setup.window_scaling_percent = video.window_scaling_percent =
473 MIN(MAX(MIN_WINDOW_SCALING_PERCENT, MIN(new_xpercent, new_ypercent)),
474 MAX_WINDOW_SCALING_PERCENT);
476 video.window_width = new_window_width;
477 video.window_height = new_window_height;
479 if (game_status == GAME_MODE_SETUP)
480 RedrawSetupScreenAfterFullscreenToggle();
487 #define NUM_TOUCH_FINGERS 3
492 SDL_FingerID finger_id;
495 } touch_info[NUM_TOUCH_FINGERS];
497 void HandleFingerEvent(FingerEvent *event)
499 static Key motion_key_x = KSYM_UNDEFINED;
500 static Key motion_key_y = KSYM_UNDEFINED;
501 static Key button_key = KSYM_UNDEFINED;
502 static float motion_x1, motion_y1;
503 static float button_x1, button_y1;
504 static SDL_FingerID motion_id = -1;
505 static SDL_FingerID button_id = -1;
506 int move_trigger_distance_percent = 2; // percent of touchpad width/height
507 int drop_trigger_distance_percent = 5; // percent of touchpad width/height
508 float move_trigger_distance = (float)move_trigger_distance_percent / 100;
509 float drop_trigger_distance = (float)drop_trigger_distance_percent / 100;
510 float event_x = event->x;
511 float event_y = event->y;
513 #if DEBUG_EVENTS_FINGER
514 Error(ERR_DEBUG, "FINGER EVENT: finger was %s, touch ID %lld, finger ID %lld, x/y %f/%f, dx/dy %f/%f, pressure %f",
515 event->type == EVENT_FINGERPRESS ? "pressed" :
516 event->type == EVENT_FINGERRELEASE ? "released" : "moved",
520 event->dx, event->dy,
524 if (game_status != GAME_MODE_PLAYING)
527 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
529 int key_status = (event->type == EVENT_FINGERRELEASE ? KEY_RELEASED :
531 Key key = (event->x < 1.0 / 3.0 ?
532 (event->y < 1.0 / 2.0 ? setup.input[0].key.snap :
533 setup.input[0].key.drop) :
534 event->x > 2.0 / 3.0 ?
535 (event->y < 1.0 / 3.0 ? setup.input[0].key.up :
536 event->y > 2.0 / 3.0 ? setup.input[0].key.down :
537 event->x < 5.0 / 6.0 ? setup.input[0].key.left :
538 setup.input[0].key.right) :
540 char *key_status_name = (key_status == KEY_RELEASED ? "KEY_RELEASED" :
544 Error(ERR_DEBUG, "::: key '%s' was '%s' [fingerId: %lld]",
545 getKeyNameFromKey(key), key_status_name, event->fingerId);
547 // check if we already know this touch event's finger id
548 for (i = 0; i < NUM_TOUCH_FINGERS; i++)
550 if (touch_info[i].touched &&
551 touch_info[i].finger_id == event->fingerId)
553 // Error(ERR_DEBUG, "MARK 1: %d", i);
559 if (i >= NUM_TOUCH_FINGERS)
561 if (key_status == KEY_PRESSED)
563 int oldest_pos = 0, oldest_counter = touch_info[0].counter;
565 // unknown finger id -- get new, empty slot, if available
566 for (i = 0; i < NUM_TOUCH_FINGERS; i++)
568 if (touch_info[i].counter < oldest_counter)
571 oldest_counter = touch_info[i].counter;
573 // Error(ERR_DEBUG, "MARK 2: %d", i);
576 if (!touch_info[i].touched)
578 // Error(ERR_DEBUG, "MARK 3: %d", i);
584 if (i >= NUM_TOUCH_FINGERS)
586 // all slots allocated -- use oldest slot
589 // Error(ERR_DEBUG, "MARK 4: %d", i);
594 // release of previously unknown key (should not happen)
596 if (key != KSYM_UNDEFINED)
598 HandleKey(key, KEY_RELEASED);
600 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [1]",
601 getKeyNameFromKey(key), "KEY_RELEASED", i);
606 if (i < NUM_TOUCH_FINGERS)
608 if (key_status == KEY_PRESSED)
610 if (touch_info[i].key != key)
612 if (touch_info[i].key != KSYM_UNDEFINED)
614 HandleKey(touch_info[i].key, KEY_RELEASED);
616 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [2]",
617 getKeyNameFromKey(touch_info[i].key), "KEY_RELEASED", i);
620 if (key != KSYM_UNDEFINED)
622 HandleKey(key, KEY_PRESSED);
624 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [3]",
625 getKeyNameFromKey(key), "KEY_PRESSED", i);
629 touch_info[i].touched = TRUE;
630 touch_info[i].finger_id = event->fingerId;
631 touch_info[i].counter = Counter();
632 touch_info[i].key = key;
636 if (touch_info[i].key != KSYM_UNDEFINED)
638 HandleKey(touch_info[i].key, KEY_RELEASED);
640 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [4]",
641 getKeyNameFromKey(touch_info[i].key), "KEY_RELEASED", i);
644 touch_info[i].touched = FALSE;
645 touch_info[i].finger_id = 0;
646 touch_info[i].counter = 0;
647 touch_info[i].key = 0;
654 // use touch direction control
656 if (event->type == EVENT_FINGERPRESS)
658 if (event_x > 1.0 / 3.0)
662 motion_id = event->fingerId;
667 motion_key_x = KSYM_UNDEFINED;
668 motion_key_y = KSYM_UNDEFINED;
670 Error(ERR_DEBUG, "---------- MOVE STARTED (WAIT) ----------");
676 button_id = event->fingerId;
681 button_key = setup.input[0].key.snap;
683 HandleKey(button_key, KEY_PRESSED);
685 Error(ERR_DEBUG, "---------- SNAP STARTED ----------");
688 else if (event->type == EVENT_FINGERRELEASE)
690 if (event->fingerId == motion_id)
694 if (motion_key_x != KSYM_UNDEFINED)
695 HandleKey(motion_key_x, KEY_RELEASED);
696 if (motion_key_y != KSYM_UNDEFINED)
697 HandleKey(motion_key_y, KEY_RELEASED);
699 motion_key_x = KSYM_UNDEFINED;
700 motion_key_y = KSYM_UNDEFINED;
702 Error(ERR_DEBUG, "---------- MOVE STOPPED ----------");
704 else if (event->fingerId == button_id)
708 if (button_key != KSYM_UNDEFINED)
709 HandleKey(button_key, KEY_RELEASED);
711 button_key = KSYM_UNDEFINED;
713 Error(ERR_DEBUG, "---------- SNAP STOPPED ----------");
716 else if (event->type == EVENT_FINGERMOTION)
718 if (event->fingerId == motion_id)
720 float distance_x = ABS(event_x - motion_x1);
721 float distance_y = ABS(event_y - motion_y1);
722 Key new_motion_key_x = (event_x < motion_x1 ? setup.input[0].key.left :
723 event_x > motion_x1 ? setup.input[0].key.right :
725 Key new_motion_key_y = (event_y < motion_y1 ? setup.input[0].key.up :
726 event_y > motion_y1 ? setup.input[0].key.down :
729 if (distance_x < move_trigger_distance / 2 ||
730 distance_x < distance_y)
731 new_motion_key_x = KSYM_UNDEFINED;
733 if (distance_y < move_trigger_distance / 2 ||
734 distance_y < distance_x)
735 new_motion_key_y = KSYM_UNDEFINED;
737 if (distance_x > move_trigger_distance ||
738 distance_y > move_trigger_distance)
740 if (new_motion_key_x != motion_key_x)
742 if (motion_key_x != KSYM_UNDEFINED)
743 HandleKey(motion_key_x, KEY_RELEASED);
744 if (new_motion_key_x != KSYM_UNDEFINED)
745 HandleKey(new_motion_key_x, KEY_PRESSED);
748 if (new_motion_key_y != motion_key_y)
750 if (motion_key_y != KSYM_UNDEFINED)
751 HandleKey(motion_key_y, KEY_RELEASED);
752 if (new_motion_key_y != KSYM_UNDEFINED)
753 HandleKey(new_motion_key_y, KEY_PRESSED);
759 motion_key_x = new_motion_key_x;
760 motion_key_y = new_motion_key_y;
762 Error(ERR_DEBUG, "---------- MOVE STARTED (MOVE) ----------");
765 else if (event->fingerId == button_id)
767 float distance_x = ABS(event_x - button_x1);
768 float distance_y = ABS(event_y - button_y1);
770 if (distance_x < drop_trigger_distance / 2 &&
771 distance_y > drop_trigger_distance)
773 if (button_key == setup.input[0].key.snap)
774 HandleKey(button_key, KEY_RELEASED);
779 button_key = setup.input[0].key.drop;
781 HandleKey(button_key, KEY_PRESSED);
783 Error(ERR_DEBUG, "---------- DROP STARTED ----------");
789 static boolean checkTextInputKeyModState()
791 // when playing, only handle raw key events and ignore text input
792 if (game_status == GAME_MODE_PLAYING)
795 return ((GetKeyModState() & KMOD_TextInput) != KMOD_None);
798 void HandleTextEvent(TextEvent *event)
800 char *text = event->text;
801 Key key = getKeyFromKeyName(text);
803 #if DEBUG_EVENTS_TEXT
804 Error(ERR_DEBUG, "TEXT EVENT: text == '%s' [%d byte(s), '%c'/%d], resulting key == %d (%s) [%04x]",
807 text[0], (int)(text[0]),
809 getKeyNameFromKey(key),
813 #if defined(PLATFORM_ANDROID)
814 if (game_status == GAME_MODE_PSEUDO_TYPENAME)
816 HandleTypeName(0, key);
822 // only handle key input with text modifier keys pressed
823 if (checkTextInputKeyModState())
825 HandleKey(key, KEY_PRESSED);
826 HandleKey(key, KEY_RELEASED);
830 void HandlePauseResumeEvent(PauseResumeEvent *event)
832 if (event->type == SDL_APP_WILLENTERBACKGROUND)
836 else if (event->type == SDL_APP_DIDENTERFOREGROUND)
844 void HandleKeyEvent(KeyEvent *event)
846 int key_status = (event->type == EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
847 boolean with_modifiers = (game_status == GAME_MODE_PLAYING ? FALSE : TRUE);
848 Key key = GetEventKey(event, with_modifiers);
849 Key keymod = (with_modifiers ? GetEventKey(event, FALSE) : key);
852 Error(ERR_DEBUG, "KEY EVENT: key was %s, keysym.scancode == %d, keysym.sym == %d, keymod = %d, GetKeyModState() = 0x%04x, resulting key == %d (%s)",
853 event->type == EVENT_KEYPRESS ? "pressed" : "released",
854 event->keysym.scancode,
859 getKeyNameFromKey(key));
862 #if defined(PLATFORM_ANDROID)
863 // always map the "back" button to the "escape" key on Android devices
864 if (key == KSYM_Back)
868 HandleKeyModState(keymod, key_status);
870 #if defined(TARGET_SDL2)
871 // only handle raw key input without text modifier keys pressed
872 if (!checkTextInputKeyModState())
873 HandleKey(key, key_status);
875 HandleKey(key, key_status);
879 void HandleFocusEvent(FocusChangeEvent *event)
881 static int old_joystick_status = -1;
883 if (event->type == EVENT_FOCUSOUT)
885 KeyboardAutoRepeatOn();
886 old_joystick_status = joystick.status;
887 joystick.status = JOYSTICK_NOT_AVAILABLE;
891 else if (event->type == EVENT_FOCUSIN)
893 /* When there are two Rocks'n'Diamonds windows which overlap and
894 the player moves the pointer from one game window to the other,
895 a 'FocusOut' event is generated for the window the pointer is
896 leaving and a 'FocusIn' event is generated for the window the
897 pointer is entering. In some cases, it can happen that the
898 'FocusIn' event is handled by the one game process before the
899 'FocusOut' event by the other game process. In this case the
900 X11 environment would end up with activated keyboard auto repeat,
901 because unfortunately this is a global setting and not (which
902 would be far better) set for each X11 window individually.
903 The effect would be keyboard auto repeat while playing the game
904 (game_status == GAME_MODE_PLAYING), which is not desired.
905 To avoid this special case, we just wait 1/10 second before
906 processing the 'FocusIn' event.
909 if (game_status == GAME_MODE_PLAYING)
912 KeyboardAutoRepeatOffUnlessAutoplay();
915 if (old_joystick_status != -1)
916 joystick.status = old_joystick_status;
920 void HandleClientMessageEvent(ClientMessageEvent *event)
922 if (CheckCloseWindowEvent(event))
926 void HandleWindowManagerEvent(Event *event)
928 #if defined(TARGET_SDL)
929 SDLHandleWindowManagerEvent(event);
933 void HandleButton(int mx, int my, int button, int button_nr)
935 static int old_mx = 0, old_my = 0;
949 #if defined(PLATFORM_ANDROID)
950 if (game_status != GAME_MODE_PLAYING &&
951 HandleGadgets(mx, my, button))
953 /* do not handle this button event anymore */
954 mx = my = -32; /* force mouse event to be outside screen tiles */
957 if (HandleGadgets(mx, my, button))
959 /* do not handle this button event anymore */
960 mx = my = -32; /* force mouse event to be outside screen tiles */
964 /* do not use scroll wheel button events for anything other than gadgets */
965 if (IS_WHEEL_BUTTON(button_nr))
970 case GAME_MODE_TITLE:
971 HandleTitleScreen(mx, my, 0, 0, button);
975 HandleMainMenu(mx, my, 0, 0, button);
978 case GAME_MODE_PSEUDO_TYPENAME:
979 HandleTypeName(0, KSYM_Return);
982 case GAME_MODE_LEVELS:
983 HandleChooseLevelSet(mx, my, 0, 0, button);
986 case GAME_MODE_LEVELNR:
987 HandleChooseLevelNr(mx, my, 0, 0, button);
990 case GAME_MODE_SCORES:
991 HandleHallOfFame(0, 0, 0, 0, button);
994 case GAME_MODE_EDITOR:
995 HandleLevelEditorIdle();
999 HandleInfoScreen(mx, my, 0, 0, button);
1002 case GAME_MODE_SETUP:
1003 HandleSetupScreen(mx, my, 0, 0, button);
1006 case GAME_MODE_PLAYING:
1008 if (button == MB_PRESSED && !motion_status && IN_GFX_FIELD_PLAY(mx, my))
1009 DumpTile(LEVELX((mx - SX) / TILESIZE_VAR),
1010 LEVELY((my - SY) / TILESIZE_VAR));
1011 // DumpTile(LEVELX((mx - SX) / TILEX), LEVELY((my - SY) / TILEY));
1020 static boolean is_string_suffix(char *string, char *suffix)
1022 int string_len = strlen(string);
1023 int suffix_len = strlen(suffix);
1025 if (suffix_len > string_len)
1028 return (strEqual(&string[string_len - suffix_len], suffix));
1031 #define MAX_CHEAT_INPUT_LEN 32
1033 static void HandleKeysSpecial(Key key)
1035 static char cheat_input[2 * MAX_CHEAT_INPUT_LEN + 1] = "";
1036 char letter = getCharFromKey(key);
1037 int cheat_input_len = strlen(cheat_input);
1043 if (cheat_input_len >= 2 * MAX_CHEAT_INPUT_LEN)
1045 for (i = 0; i < MAX_CHEAT_INPUT_LEN + 1; i++)
1046 cheat_input[i] = cheat_input[MAX_CHEAT_INPUT_LEN + i];
1048 cheat_input_len = MAX_CHEAT_INPUT_LEN;
1051 cheat_input[cheat_input_len++] = letter;
1052 cheat_input[cheat_input_len] = '\0';
1054 #if DEBUG_EVENTS_KEY
1055 Error(ERR_DEBUG, "SPECIAL KEY '%s' [%d]\n", cheat_input, cheat_input_len);
1058 if (game_status == GAME_MODE_MAIN)
1060 if (is_string_suffix(cheat_input, ":insert-solution-tape") ||
1061 is_string_suffix(cheat_input, ":ist"))
1063 InsertSolutionTape();
1065 else if (is_string_suffix(cheat_input, ":reload-graphics") ||
1066 is_string_suffix(cheat_input, ":rg"))
1068 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS);
1071 else if (is_string_suffix(cheat_input, ":reload-sounds") ||
1072 is_string_suffix(cheat_input, ":rs"))
1074 ReloadCustomArtwork(1 << ARTWORK_TYPE_SOUNDS);
1077 else if (is_string_suffix(cheat_input, ":reload-music") ||
1078 is_string_suffix(cheat_input, ":rm"))
1080 ReloadCustomArtwork(1 << ARTWORK_TYPE_MUSIC);
1083 else if (is_string_suffix(cheat_input, ":reload-artwork") ||
1084 is_string_suffix(cheat_input, ":ra"))
1086 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS |
1087 1 << ARTWORK_TYPE_SOUNDS |
1088 1 << ARTWORK_TYPE_MUSIC);
1091 else if (is_string_suffix(cheat_input, ":dump-level") ||
1092 is_string_suffix(cheat_input, ":dl"))
1096 else if (is_string_suffix(cheat_input, ":dump-tape") ||
1097 is_string_suffix(cheat_input, ":dt"))
1101 else if (is_string_suffix(cheat_input, ":fix-tape") ||
1102 is_string_suffix(cheat_input, ":ft"))
1104 /* fix single-player tapes that contain player input for more than one
1105 player (due to a bug in 3.3.1.2 and earlier versions), which results
1106 in playing levels with more than one player in multi-player mode,
1107 even though the tape was originally recorded in single-player mode */
1109 /* remove player input actions for all players but the first one */
1110 for (i = 1; i < MAX_PLAYERS; i++)
1111 tape.player_participates[i] = FALSE;
1113 tape.changed = TRUE;
1115 else if (is_string_suffix(cheat_input, ":save-native-level") ||
1116 is_string_suffix(cheat_input, ":snl"))
1118 SaveNativeLevel(&level);
1121 else if (game_status == GAME_MODE_PLAYING)
1124 if (is_string_suffix(cheat_input, ".q"))
1125 DEBUG_SetMaximumDynamite();
1128 else if (game_status == GAME_MODE_EDITOR)
1130 if (is_string_suffix(cheat_input, ":dump-brush") ||
1131 is_string_suffix(cheat_input, ":DB"))
1135 else if (is_string_suffix(cheat_input, ":DDB"))
1142 void HandleKey(Key key, int key_status)
1144 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
1145 static struct SetupKeyboardInfo ski;
1146 static struct SetupShortcutInfo ssi;
1155 { &ski.left, &ssi.snap_left, DEFAULT_KEY_LEFT, JOY_LEFT },
1156 { &ski.right, &ssi.snap_right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
1157 { &ski.up, &ssi.snap_up, DEFAULT_KEY_UP, JOY_UP },
1158 { &ski.down, &ssi.snap_down, DEFAULT_KEY_DOWN, JOY_DOWN },
1159 { &ski.snap, NULL, DEFAULT_KEY_SNAP, JOY_BUTTON_SNAP },
1160 { &ski.drop, NULL, DEFAULT_KEY_DROP, JOY_BUTTON_DROP }
1165 if (game_status == GAME_MODE_PLAYING)
1167 /* only needed for single-step tape recording mode */
1168 static boolean clear_snap_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1169 static boolean clear_drop_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1170 static boolean element_snapped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1171 static boolean element_dropped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1174 for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
1176 byte key_action = 0;
1178 if (setup.input[pnr].use_joystick)
1181 ski = setup.input[pnr].key;
1183 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1184 if (key == *key_info[i].key_custom)
1185 key_action |= key_info[i].action;
1187 /* use combined snap+direction keys for the first player only */
1190 ssi = setup.shortcut;
1192 for (i = 0; i < NUM_DIRECTIONS; i++)
1193 if (key == *key_info[i].key_snap)
1194 key_action |= key_info[i].action | JOY_BUTTON_SNAP;
1197 /* clear delayed snap and drop actions in single step mode (see below) */
1198 if (tape.single_step)
1200 if (clear_snap_button[pnr])
1202 stored_player[pnr].action &= ~KEY_BUTTON_SNAP;
1203 clear_snap_button[pnr] = FALSE;
1206 if (clear_drop_button[pnr])
1208 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1209 clear_drop_button[pnr] = FALSE;
1213 if (key_status == KEY_PRESSED)
1214 stored_player[pnr].action |= key_action;
1216 stored_player[pnr].action &= ~key_action;
1218 if (tape.single_step && tape.recording && tape.pausing)
1220 if (key_status == KEY_PRESSED && key_action & KEY_MOTION)
1222 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1224 /* if snap key already pressed, don't snap when releasing (below) */
1225 if (stored_player[pnr].action & KEY_BUTTON_SNAP)
1226 element_snapped[pnr] = TRUE;
1228 /* if drop key already pressed, don't drop when releasing (below) */
1229 if (stored_player[pnr].action & KEY_BUTTON_DROP)
1230 element_dropped[pnr] = TRUE;
1232 else if (key_status == KEY_PRESSED && key_action & KEY_BUTTON_DROP)
1234 if (level.game_engine_type == GAME_ENGINE_TYPE_EM ||
1235 level.game_engine_type == GAME_ENGINE_TYPE_SP)
1238 if (level.game_engine_type == GAME_ENGINE_TYPE_SP &&
1239 getRedDiskReleaseFlag_SP() == 0)
1240 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1242 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1245 else if (key_status == KEY_RELEASED && key_action & KEY_BUTTON)
1247 if (key_action & KEY_BUTTON_SNAP)
1249 /* if snap key was released without moving (see above), snap now */
1250 if (!element_snapped[pnr])
1252 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1254 stored_player[pnr].action |= KEY_BUTTON_SNAP;
1256 /* clear delayed snap button on next event */
1257 clear_snap_button[pnr] = TRUE;
1260 element_snapped[pnr] = FALSE;
1263 if (key_action & KEY_BUTTON_DROP &&
1264 level.game_engine_type == GAME_ENGINE_TYPE_RND)
1266 /* if drop key was released without moving (see above), drop now */
1267 if (!element_dropped[pnr])
1269 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1271 if (level.game_engine_type != GAME_ENGINE_TYPE_SP ||
1272 getRedDiskReleaseFlag_SP() != 0)
1273 stored_player[pnr].action |= KEY_BUTTON_DROP;
1275 /* clear delayed drop button on next event */
1276 clear_drop_button[pnr] = TRUE;
1279 element_dropped[pnr] = FALSE;
1283 else if (tape.recording && tape.pausing)
1285 /* prevent key release events from un-pausing a paused game */
1286 if (key_status == KEY_PRESSED && key_action & KEY_ACTION)
1287 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1293 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1294 if (key == key_info[i].key_default)
1295 joy |= key_info[i].action;
1300 if (key_status == KEY_PRESSED)
1301 key_joystick_mapping |= joy;
1303 key_joystick_mapping &= ~joy;
1308 if (game_status != GAME_MODE_PLAYING)
1309 key_joystick_mapping = 0;
1311 if (key_status == KEY_RELEASED)
1314 if ((key == KSYM_F11 ||
1315 ((key == KSYM_Return ||
1316 key == KSYM_KP_Enter) && (GetKeyModState() & KMOD_Alt))) &&
1317 video.fullscreen_available)
1319 setup.fullscreen = !setup.fullscreen;
1321 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1323 if (game_status == GAME_MODE_SETUP)
1324 RedrawSetupScreenAfterFullscreenToggle();
1329 if ((key == KSYM_minus ||
1332 ((GetKeyModState() & KMOD_Control) ||
1333 (GetKeyModState() & KMOD_Alt)) &&
1334 video.window_scaling_available &&
1335 !video.fullscreen_enabled)
1338 setup.window_scaling_percent = STD_WINDOW_SCALING_PERCENT;
1340 setup.window_scaling_percent +=
1341 (key == KSYM_minus ? -1 : +1) * STEP_WINDOW_SCALING_PERCENT;
1343 if (setup.window_scaling_percent < MIN_WINDOW_SCALING_PERCENT)
1344 setup.window_scaling_percent = MIN_WINDOW_SCALING_PERCENT;
1345 else if (setup.window_scaling_percent > MAX_WINDOW_SCALING_PERCENT)
1346 setup.window_scaling_percent = MAX_WINDOW_SCALING_PERCENT;
1348 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1350 if (game_status == GAME_MODE_SETUP)
1351 RedrawSetupScreenAfterFullscreenToggle();
1356 if (game_status == GAME_MODE_PLAYING && AllPlayersGone &&
1357 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
1364 if (game_status == GAME_MODE_MAIN &&
1365 (key == setup.shortcut.toggle_pause || key == KSYM_space))
1367 StartGameActions(options.network, setup.autorecord, level.random_seed);
1372 if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING)
1374 if (key == setup.shortcut.save_game)
1376 else if (key == setup.shortcut.load_game)
1378 else if (key == setup.shortcut.toggle_pause)
1379 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1381 HandleTapeButtonKeys(key);
1382 HandleSoundButtonKeys(key);
1385 if (game_status == GAME_MODE_PLAYING && !network_playing)
1387 int centered_player_nr_next = -999;
1389 if (key == setup.shortcut.focus_player_all)
1390 centered_player_nr_next = -1;
1392 for (i = 0; i < MAX_PLAYERS; i++)
1393 if (key == setup.shortcut.focus_player[i])
1394 centered_player_nr_next = i;
1396 if (centered_player_nr_next != -999)
1398 game.centered_player_nr_next = centered_player_nr_next;
1399 game.set_centered_player = TRUE;
1403 tape.centered_player_nr_next = game.centered_player_nr_next;
1404 tape.set_centered_player = TRUE;
1409 HandleKeysSpecial(key);
1411 if (HandleGadgetsKeyInput(key))
1413 if (key != KSYM_Escape) /* always allow ESC key to be handled */
1414 key = KSYM_UNDEFINED;
1417 switch (game_status)
1419 case GAME_MODE_PSEUDO_TYPENAME:
1420 HandleTypeName(0, key);
1423 case GAME_MODE_TITLE:
1424 case GAME_MODE_MAIN:
1425 case GAME_MODE_LEVELS:
1426 case GAME_MODE_LEVELNR:
1427 case GAME_MODE_SETUP:
1428 case GAME_MODE_INFO:
1429 case GAME_MODE_SCORES:
1434 if (game_status == GAME_MODE_TITLE)
1435 HandleTitleScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1436 else if (game_status == GAME_MODE_MAIN)
1437 HandleMainMenu(0, 0, 0, 0, MB_MENU_CHOICE);
1438 else if (game_status == GAME_MODE_LEVELS)
1439 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_CHOICE);
1440 else if (game_status == GAME_MODE_LEVELNR)
1441 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_CHOICE);
1442 else if (game_status == GAME_MODE_SETUP)
1443 HandleSetupScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1444 else if (game_status == GAME_MODE_INFO)
1445 HandleInfoScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1446 else if (game_status == GAME_MODE_SCORES)
1447 HandleHallOfFame(0, 0, 0, 0, MB_MENU_CHOICE);
1451 if (game_status != GAME_MODE_MAIN)
1452 FadeSkipNextFadeIn();
1454 if (game_status == GAME_MODE_TITLE)
1455 HandleTitleScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1456 else if (game_status == GAME_MODE_LEVELS)
1457 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_LEAVE);
1458 else if (game_status == GAME_MODE_LEVELNR)
1459 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_LEAVE);
1460 else if (game_status == GAME_MODE_SETUP)
1461 HandleSetupScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1462 else if (game_status == GAME_MODE_INFO)
1463 HandleInfoScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1464 else if (game_status == GAME_MODE_SCORES)
1465 HandleHallOfFame(0, 0, 0, 0, MB_MENU_LEAVE);
1469 if (game_status == GAME_MODE_LEVELS)
1470 HandleChooseLevelSet(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1471 else if (game_status == GAME_MODE_LEVELNR)
1472 HandleChooseLevelNr(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1473 else if (game_status == GAME_MODE_SETUP)
1474 HandleSetupScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1475 else if (game_status == GAME_MODE_INFO)
1476 HandleInfoScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1477 else if (game_status == GAME_MODE_SCORES)
1478 HandleHallOfFame(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1481 case KSYM_Page_Down:
1482 if (game_status == GAME_MODE_LEVELS)
1483 HandleChooseLevelSet(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1484 else if (game_status == GAME_MODE_LEVELNR)
1485 HandleChooseLevelNr(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1486 else if (game_status == GAME_MODE_SETUP)
1487 HandleSetupScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1488 else if (game_status == GAME_MODE_INFO)
1489 HandleInfoScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1490 else if (game_status == GAME_MODE_SCORES)
1491 HandleHallOfFame(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1496 GameFrameDelay = (GameFrameDelay == 500 ? GAME_FRAME_DELAY : 500);
1500 setup.sp_show_border_elements = !setup.sp_show_border_elements;
1501 printf("Supaplex border elements %s\n",
1502 setup.sp_show_border_elements ? "enabled" : "disabled");
1511 case GAME_MODE_EDITOR:
1512 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
1513 HandleLevelEditorKeyInput(key);
1516 case GAME_MODE_PLAYING:
1521 RequestQuitGame(setup.ask_on_escape);
1528 if (GameFrameDelay == 500)
1529 GameFrameDelay = GAME_FRAME_DELAY;
1531 GameFrameDelay = 500;
1534 GameFrameDelay = (key - KSYM_0) * 10;
1535 printf("Game speed == %d%% (%d ms delay between two frames)\n",
1536 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
1542 options.debug = FALSE;
1543 printf("debug mode disabled\n");
1547 options.debug = TRUE;
1548 printf("debug mode enabled\n");
1554 if (!global.fps_slowdown)
1556 global.fps_slowdown = TRUE;
1557 global.fps_slowdown_factor = 2;
1558 printf("fps slowdown enabled -- display only every 2nd frame\n");
1560 else if (global.fps_slowdown_factor == 2)
1562 global.fps_slowdown_factor = 4;
1563 printf("fps slowdown enabled -- display only every 4th frame\n");
1567 global.fps_slowdown = FALSE;
1568 global.fps_slowdown_factor = 1;
1569 printf("fps slowdown disabled\n");
1575 printf("::: currently using game engine version %d\n",
1576 game.engine_version);
1587 if (key == KSYM_Escape)
1589 game_status = GAME_MODE_MAIN;
1597 void HandleNoEvent()
1599 if (button_status && game_status != GAME_MODE_PLAYING)
1601 HandleButton(0, 0, -button_status, button_status);
1608 #if defined(NETWORK_AVALIABLE)
1609 if (options.network)
1613 switch (game_status)
1615 case GAME_MODE_MAIN:
1616 DrawPreviewLevelAnimation();
1620 case GAME_MODE_LEVELS:
1621 case GAME_MODE_LEVELNR:
1622 case GAME_MODE_SETUP:
1623 case GAME_MODE_INFO:
1624 case GAME_MODE_SCORES:
1628 case GAME_MODE_EDITOR:
1629 HandleLevelEditorIdle();
1637 static int HandleJoystickForAllPlayers()
1642 for (i = 0; i < MAX_PLAYERS; i++)
1644 byte joy_action = 0;
1647 if (!setup.input[i].use_joystick)
1651 joy_action = Joystick(i);
1652 result |= joy_action;
1654 if (!setup.input[i].use_joystick)
1657 stored_player[i].action = joy_action;
1663 void HandleJoystick()
1665 int joystick = HandleJoystickForAllPlayers();
1666 int keyboard = key_joystick_mapping;
1667 int joy = (joystick | keyboard);
1668 int left = joy & JOY_LEFT;
1669 int right = joy & JOY_RIGHT;
1670 int up = joy & JOY_UP;
1671 int down = joy & JOY_DOWN;
1672 int button = joy & JOY_BUTTON;
1673 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
1674 int dx = (left ? -1 : right ? 1 : 0);
1675 int dy = (up ? -1 : down ? 1 : 0);
1677 switch (game_status)
1679 case GAME_MODE_TITLE:
1680 case GAME_MODE_MAIN:
1681 case GAME_MODE_LEVELS:
1682 case GAME_MODE_LEVELNR:
1683 case GAME_MODE_SETUP:
1684 case GAME_MODE_INFO:
1686 static unsigned int joystickmove_delay = 0;
1688 if (joystick && !button &&
1689 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
1690 newbutton = dx = dy = 0;
1692 if (game_status == GAME_MODE_TITLE)
1693 HandleTitleScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1694 else if (game_status == GAME_MODE_MAIN)
1695 HandleMainMenu(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1696 else if (game_status == GAME_MODE_LEVELS)
1697 HandleChooseLevelSet(0,0,dx,dy,newbutton?MB_MENU_CHOICE : MB_MENU_MARK);
1698 else if (game_status == GAME_MODE_LEVELNR)
1699 HandleChooseLevelNr(0,0,dx,dy,newbutton? MB_MENU_CHOICE : MB_MENU_MARK);
1700 else if (game_status == GAME_MODE_SETUP)
1701 HandleSetupScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1702 else if (game_status == GAME_MODE_INFO)
1703 HandleInfoScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1707 case GAME_MODE_SCORES:
1708 HandleHallOfFame(0, 0, dx, dy, !newbutton);
1711 case GAME_MODE_PLAYING:
1712 if (tape.playing || keyboard)
1713 newbutton = ((joy & JOY_BUTTON) != 0);
1715 if (newbutton && AllPlayersGone)