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"
26 #define DEBUG_EVENTS 0
28 #define DEBUG_EVENTS_BUTTON (DEBUG_EVENTS * 0)
29 #define DEBUG_EVENTS_MOTION (DEBUG_EVENTS * 0)
30 #define DEBUG_EVENTS_WINDOW (DEBUG_EVENTS * 0)
31 #define DEBUG_EVENTS_FINGER (DEBUG_EVENTS * 0)
32 #define DEBUG_EVENTS_TEXT (DEBUG_EVENTS * 1)
33 #define DEBUG_EVENTS_KEY (DEBUG_EVENTS * 1)
36 static boolean cursor_inside_playfield = FALSE;
37 static int cursor_mode_last = CURSOR_DEFAULT;
38 static unsigned int special_cursor_delay = 0;
39 static unsigned int special_cursor_delay_value = 1000;
41 /* event filter especially needed for SDL event filtering due to
42 delay problems with lots of mouse motion events when mouse button
43 not pressed (X11 can handle this with 'PointerMotionHintMask') */
45 /* event filter addition for SDL2: as SDL2 does not have a function to enable
46 or disable keyboard auto-repeat, filter repeated keyboard events instead */
48 static int FilterEventsExt(const Event *event)
52 #if defined(TARGET_SDL2)
53 /* skip repeated key press events if keyboard auto-repeat is disabled */
54 if (event->type == EVENT_KEYPRESS &&
60 /* non-motion events are directly passed to event handler functions */
61 if (event->type != EVENT_MOTIONNOTIFY)
64 motion = (MotionEvent *)event;
65 cursor_inside_playfield = (motion->x >= SX && motion->x < SX + SXSIZE &&
66 motion->y >= SY && motion->y < SY + SYSIZE);
68 /* do no reset mouse cursor before all pending events have been processed */
69 if (gfx.cursor_mode == cursor_mode_last &&
70 ((game_status == GAME_MODE_TITLE &&
71 gfx.cursor_mode == CURSOR_NONE) ||
72 (game_status == GAME_MODE_PLAYING &&
73 gfx.cursor_mode == CURSOR_PLAYFIELD)))
75 SetMouseCursor(CURSOR_DEFAULT);
77 DelayReached(&special_cursor_delay, 0);
79 cursor_mode_last = CURSOR_DEFAULT;
82 /* skip mouse motion events without pressed button outside level editor */
83 if (button_status == MB_RELEASED &&
84 game_status != GAME_MODE_EDITOR && game_status != GAME_MODE_PLAYING)
90 #if defined(TARGET_SDL2)
91 int FilterEvents(void *userdata, Event *event)
93 return FilterEventsExt(event);
96 int FilterEvents(const Event *event)
98 return FilterEventsExt(event);
102 /* to prevent delay problems, skip mouse motion events if the very next
103 event is also a mouse motion event (and therefore effectively only
104 handling the last of a row of mouse motion events in the event queue) */
106 boolean SkipPressedMouseMotionEvent(const Event *event)
108 /* nothing to do if the current event is not a mouse motion event */
109 if (event->type != EVENT_MOTIONNOTIFY)
112 /* only skip motion events with pressed button outside the game */
113 if (button_status == MB_RELEASED || 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)
157 static unsigned int sync_frame_delay = 0;
158 unsigned int sync_frame_delay_value = GAME_FRAME_DELAY;
162 if (PendingEvent()) /* got event */
166 while (NextValidEvent(&event))
170 case EVENT_BUTTONPRESS:
171 case EVENT_BUTTONRELEASE:
172 HandleButtonEvent((ButtonEvent *) &event);
175 case EVENT_MOTIONNOTIFY:
176 HandleMotionEvent((MotionEvent *) &event);
179 #if defined(TARGET_SDL2)
180 case SDL_WINDOWEVENT:
181 HandleWindowEvent((WindowEvent *) &event);
184 case EVENT_FINGERPRESS:
185 case EVENT_FINGERRELEASE:
186 case EVENT_FINGERMOTION:
187 HandleFingerEvent((FingerEvent *) &event);
190 case EVENT_TEXTINPUT:
191 HandleTextEvent((TextEvent *) &event);
194 case SDL_APP_WILLENTERBACKGROUND:
195 case SDL_APP_DIDENTERBACKGROUND:
196 case SDL_APP_WILLENTERFOREGROUND:
197 case SDL_APP_DIDENTERFOREGROUND:
198 HandlePauseResumeEvent((PauseResumeEvent *) &event);
203 case EVENT_KEYRELEASE:
204 HandleKeyEvent((KeyEvent *) &event);
208 HandleOtherEvents(&event);
212 if (DelayReached(&sync_frame_delay, sync_frame_delay_value))
218 if (game_status == GAME_MODE_TITLE)
220 /* when showing title screens, hide mouse pointer (if not moved) */
222 if (gfx.cursor_mode != CURSOR_NONE &&
223 DelayReached(&special_cursor_delay, special_cursor_delay_value))
225 SetMouseCursor(CURSOR_NONE);
228 else if (game_status == GAME_MODE_PLAYING && (!tape.pausing ||
231 /* when playing, display a special mouse pointer inside the playfield */
233 if (gfx.cursor_mode != CURSOR_PLAYFIELD &&
234 cursor_inside_playfield &&
235 DelayReached(&special_cursor_delay, special_cursor_delay_value))
237 SetMouseCursor(CURSOR_PLAYFIELD);
240 else if (gfx.cursor_mode != CURSOR_DEFAULT)
242 SetMouseCursor(CURSOR_DEFAULT);
245 /* this is set after all pending events have been processed */
246 cursor_mode_last = gfx.cursor_mode;
249 /* also execute after pending events have been processed before */
252 /* don't use all CPU time when idle; the main loop while playing
253 has its own synchronization and is CPU friendly, too */
255 if (game_status == GAME_MODE_PLAYING)
258 /* refresh window contents from drawing buffer, if needed */
261 if (game_status != GAME_MODE_PLAYING)
262 WaitUntilDelayReached(&sync_frame_delay, sync_frame_delay_value);
264 if (game_status == GAME_MODE_QUIT)
269 void HandleOtherEvents(Event *event)
274 HandleExposeEvent((ExposeEvent *) event);
277 case EVENT_UNMAPNOTIFY:
279 /* This causes the game to stop not only when iconified, but also
280 when on another virtual desktop, which might be not desired. */
281 SleepWhileUnmapped();
287 HandleFocusEvent((FocusChangeEvent *) event);
290 case EVENT_CLIENTMESSAGE:
291 HandleClientMessageEvent((ClientMessageEvent *) event);
294 #if defined(TARGET_SDL)
295 case SDL_JOYAXISMOTION:
296 case SDL_JOYBUTTONDOWN:
297 case SDL_JOYBUTTONUP:
298 HandleJoystickEvent(event);
302 HandleWindowManagerEvent(event);
311 void ClearEventQueue()
313 while (PendingEvent())
321 case EVENT_BUTTONRELEASE:
322 button_status = MB_RELEASED;
325 case EVENT_KEYRELEASE:
330 HandleOtherEvents(&event);
336 void ClearPlayerAction()
340 /* simulate key release events for still pressed keys */
341 key_joystick_mapping = 0;
342 for (i = 0; i < MAX_PLAYERS; i++)
343 stored_player[i].action = 0;
346 void SleepWhileUnmapped()
348 boolean window_unmapped = TRUE;
350 KeyboardAutoRepeatOn();
352 while (window_unmapped)
360 case EVENT_BUTTONRELEASE:
361 button_status = MB_RELEASED;
364 case EVENT_KEYRELEASE:
365 key_joystick_mapping = 0;
368 case EVENT_MAPNOTIFY:
369 window_unmapped = FALSE;
372 case EVENT_UNMAPNOTIFY:
373 /* this is only to surely prevent the 'should not happen' case
374 * of recursively looping between 'SleepWhileUnmapped()' and
375 * 'HandleOtherEvents()' which usually calls this funtion.
380 HandleOtherEvents(&event);
385 if (game_status == GAME_MODE_PLAYING)
386 KeyboardAutoRepeatOffUnlessAutoplay();
389 void HandleExposeEvent(ExposeEvent *event)
393 void HandleButtonEvent(ButtonEvent *event)
395 #if DEBUG_EVENTS_BUTTON
396 Error(ERR_DEBUG, "BUTTON EVENT: button %d %s, x/y %d/%d\n",
398 event->type == EVENT_BUTTONPRESS ? "pressed" : "released",
402 motion_status = FALSE;
404 if (event->type == EVENT_BUTTONPRESS)
405 button_status = event->button;
407 button_status = MB_RELEASED;
409 HandleButton(event->x, event->y, button_status, event->button);
412 void HandleMotionEvent(MotionEvent *event)
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;
936 boolean button_hold = FALSE;
951 #if defined(PLATFORM_ANDROID)
952 // !!! for now, do not handle gadgets when playing -- maybe fix this !!!
953 if (game_status != GAME_MODE_PLAYING &&
954 HandleGadgets(mx, my, button))
956 /* do not handle this button event anymore */
957 mx = my = -32; /* force mouse event to be outside screen tiles */
960 if (HandleGadgets(mx, my, button))
962 /* do not handle this button event anymore */
963 mx = my = -32; /* force mouse event to be outside screen tiles */
967 if (button_hold && game_status == GAME_MODE_PLAYING && tape.pausing)
970 /* do not use scroll wheel button events for anything other than gadgets */
971 if (IS_WHEEL_BUTTON(button_nr))
976 case GAME_MODE_TITLE:
977 HandleTitleScreen(mx, my, 0, 0, button);
981 HandleMainMenu(mx, my, 0, 0, button);
984 case GAME_MODE_PSEUDO_TYPENAME:
985 HandleTypeName(0, KSYM_Return);
988 case GAME_MODE_LEVELS:
989 HandleChooseLevelSet(mx, my, 0, 0, button);
992 case GAME_MODE_LEVELNR:
993 HandleChooseLevelNr(mx, my, 0, 0, button);
996 case GAME_MODE_SCORES:
997 HandleHallOfFame(0, 0, 0, 0, button);
1000 case GAME_MODE_EDITOR:
1001 HandleLevelEditorIdle();
1004 case GAME_MODE_INFO:
1005 HandleInfoScreen(mx, my, 0, 0, button);
1008 case GAME_MODE_SETUP:
1009 HandleSetupScreen(mx, my, 0, 0, button);
1012 case GAME_MODE_PLAYING:
1014 if (button == MB_PRESSED && !motion_status && IN_GFX_FIELD_PLAY(mx, my))
1015 DumpTile(LEVELX((mx - SX) / TILESIZE_VAR),
1016 LEVELY((my - SY) / TILESIZE_VAR));
1017 // DumpTile(LEVELX((mx - SX) / TILEX), LEVELY((my - SY) / TILEY));
1026 static boolean is_string_suffix(char *string, char *suffix)
1028 int string_len = strlen(string);
1029 int suffix_len = strlen(suffix);
1031 if (suffix_len > string_len)
1034 return (strEqual(&string[string_len - suffix_len], suffix));
1037 #define MAX_CHEAT_INPUT_LEN 32
1039 static void HandleKeysSpecial(Key key)
1041 static char cheat_input[2 * MAX_CHEAT_INPUT_LEN + 1] = "";
1042 char letter = getCharFromKey(key);
1043 int cheat_input_len = strlen(cheat_input);
1049 if (cheat_input_len >= 2 * MAX_CHEAT_INPUT_LEN)
1051 for (i = 0; i < MAX_CHEAT_INPUT_LEN + 1; i++)
1052 cheat_input[i] = cheat_input[MAX_CHEAT_INPUT_LEN + i];
1054 cheat_input_len = MAX_CHEAT_INPUT_LEN;
1057 cheat_input[cheat_input_len++] = letter;
1058 cheat_input[cheat_input_len] = '\0';
1060 #if DEBUG_EVENTS_KEY
1061 Error(ERR_DEBUG, "SPECIAL KEY '%s' [%d]\n", cheat_input, cheat_input_len);
1064 if (game_status == GAME_MODE_MAIN)
1066 if (is_string_suffix(cheat_input, ":insert-solution-tape") ||
1067 is_string_suffix(cheat_input, ":ist"))
1069 InsertSolutionTape();
1071 else if (is_string_suffix(cheat_input, ":reload-graphics") ||
1072 is_string_suffix(cheat_input, ":rg"))
1074 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS);
1077 else if (is_string_suffix(cheat_input, ":reload-sounds") ||
1078 is_string_suffix(cheat_input, ":rs"))
1080 ReloadCustomArtwork(1 << ARTWORK_TYPE_SOUNDS);
1083 else if (is_string_suffix(cheat_input, ":reload-music") ||
1084 is_string_suffix(cheat_input, ":rm"))
1086 ReloadCustomArtwork(1 << ARTWORK_TYPE_MUSIC);
1089 else if (is_string_suffix(cheat_input, ":reload-artwork") ||
1090 is_string_suffix(cheat_input, ":ra"))
1092 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS |
1093 1 << ARTWORK_TYPE_SOUNDS |
1094 1 << ARTWORK_TYPE_MUSIC);
1097 else if (is_string_suffix(cheat_input, ":dump-level") ||
1098 is_string_suffix(cheat_input, ":dl"))
1102 else if (is_string_suffix(cheat_input, ":dump-tape") ||
1103 is_string_suffix(cheat_input, ":dt"))
1107 else if (is_string_suffix(cheat_input, ":fix-tape") ||
1108 is_string_suffix(cheat_input, ":ft"))
1110 /* fix single-player tapes that contain player input for more than one
1111 player (due to a bug in 3.3.1.2 and earlier versions), which results
1112 in playing levels with more than one player in multi-player mode,
1113 even though the tape was originally recorded in single-player mode */
1115 /* remove player input actions for all players but the first one */
1116 for (i = 1; i < MAX_PLAYERS; i++)
1117 tape.player_participates[i] = FALSE;
1119 tape.changed = TRUE;
1121 else if (is_string_suffix(cheat_input, ":save-native-level") ||
1122 is_string_suffix(cheat_input, ":snl"))
1124 SaveNativeLevel(&level);
1127 else if (game_status == GAME_MODE_PLAYING)
1130 if (is_string_suffix(cheat_input, ".q"))
1131 DEBUG_SetMaximumDynamite();
1134 else if (game_status == GAME_MODE_EDITOR)
1136 if (is_string_suffix(cheat_input, ":dump-brush") ||
1137 is_string_suffix(cheat_input, ":DB"))
1141 else if (is_string_suffix(cheat_input, ":DDB"))
1148 void HandleKey(Key key, int key_status)
1150 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
1151 static struct SetupKeyboardInfo ski;
1152 static struct SetupShortcutInfo ssi;
1161 { &ski.left, &ssi.snap_left, DEFAULT_KEY_LEFT, JOY_LEFT },
1162 { &ski.right, &ssi.snap_right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
1163 { &ski.up, &ssi.snap_up, DEFAULT_KEY_UP, JOY_UP },
1164 { &ski.down, &ssi.snap_down, DEFAULT_KEY_DOWN, JOY_DOWN },
1165 { &ski.snap, NULL, DEFAULT_KEY_SNAP, JOY_BUTTON_SNAP },
1166 { &ski.drop, NULL, DEFAULT_KEY_DROP, JOY_BUTTON_DROP }
1171 if (game_status == GAME_MODE_PLAYING)
1173 /* only needed for single-step tape recording mode */
1174 static boolean clear_snap_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1175 static boolean clear_drop_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1176 static boolean element_snapped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1177 static boolean element_dropped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1180 for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
1182 byte key_action = 0;
1184 if (setup.input[pnr].use_joystick)
1187 ski = setup.input[pnr].key;
1189 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1190 if (key == *key_info[i].key_custom)
1191 key_action |= key_info[i].action;
1193 /* use combined snap+direction keys for the first player only */
1196 ssi = setup.shortcut;
1198 for (i = 0; i < NUM_DIRECTIONS; i++)
1199 if (key == *key_info[i].key_snap)
1200 key_action |= key_info[i].action | JOY_BUTTON_SNAP;
1203 /* clear delayed snap and drop actions in single step mode (see below) */
1204 if (tape.single_step)
1206 if (clear_snap_button[pnr])
1208 stored_player[pnr].action &= ~KEY_BUTTON_SNAP;
1209 clear_snap_button[pnr] = FALSE;
1212 if (clear_drop_button[pnr])
1214 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1215 clear_drop_button[pnr] = FALSE;
1219 if (key_status == KEY_PRESSED)
1220 stored_player[pnr].action |= key_action;
1222 stored_player[pnr].action &= ~key_action;
1224 if (tape.single_step && tape.recording && tape.pausing)
1226 if (key_status == KEY_PRESSED && key_action & KEY_MOTION)
1228 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1230 /* if snap key already pressed, don't snap when releasing (below) */
1231 if (stored_player[pnr].action & KEY_BUTTON_SNAP)
1232 element_snapped[pnr] = TRUE;
1234 /* if drop key already pressed, don't drop when releasing (below) */
1235 if (stored_player[pnr].action & KEY_BUTTON_DROP)
1236 element_dropped[pnr] = TRUE;
1238 else if (key_status == KEY_PRESSED && key_action & KEY_BUTTON_DROP)
1240 if (level.game_engine_type == GAME_ENGINE_TYPE_EM ||
1241 level.game_engine_type == GAME_ENGINE_TYPE_SP)
1244 if (level.game_engine_type == GAME_ENGINE_TYPE_SP &&
1245 getRedDiskReleaseFlag_SP() == 0)
1246 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1248 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1251 else if (key_status == KEY_RELEASED && key_action & KEY_BUTTON)
1253 if (key_action & KEY_BUTTON_SNAP)
1255 /* if snap key was released without moving (see above), snap now */
1256 if (!element_snapped[pnr])
1258 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1260 stored_player[pnr].action |= KEY_BUTTON_SNAP;
1262 /* clear delayed snap button on next event */
1263 clear_snap_button[pnr] = TRUE;
1266 element_snapped[pnr] = FALSE;
1269 if (key_action & KEY_BUTTON_DROP &&
1270 level.game_engine_type == GAME_ENGINE_TYPE_RND)
1272 /* if drop key was released without moving (see above), drop now */
1273 if (!element_dropped[pnr])
1275 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1277 if (level.game_engine_type != GAME_ENGINE_TYPE_SP ||
1278 getRedDiskReleaseFlag_SP() != 0)
1279 stored_player[pnr].action |= KEY_BUTTON_DROP;
1281 /* clear delayed drop button on next event */
1282 clear_drop_button[pnr] = TRUE;
1285 element_dropped[pnr] = FALSE;
1289 else if (tape.recording && tape.pausing)
1291 /* prevent key release events from un-pausing a paused game */
1292 if (key_status == KEY_PRESSED && key_action & KEY_ACTION)
1293 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1299 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1300 if (key == key_info[i].key_default)
1301 joy |= key_info[i].action;
1306 if (key_status == KEY_PRESSED)
1307 key_joystick_mapping |= joy;
1309 key_joystick_mapping &= ~joy;
1314 if (game_status != GAME_MODE_PLAYING)
1315 key_joystick_mapping = 0;
1317 if (key_status == KEY_RELEASED)
1320 if ((key == KSYM_F11 ||
1321 ((key == KSYM_Return ||
1322 key == KSYM_KP_Enter) && (GetKeyModState() & KMOD_Alt))) &&
1323 video.fullscreen_available)
1325 setup.fullscreen = !setup.fullscreen;
1327 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1329 if (game_status == GAME_MODE_SETUP)
1330 RedrawSetupScreenAfterFullscreenToggle();
1335 if ((key == KSYM_minus ||
1338 ((GetKeyModState() & KMOD_Control) ||
1339 (GetKeyModState() & KMOD_Alt)) &&
1340 video.window_scaling_available &&
1341 !video.fullscreen_enabled)
1344 setup.window_scaling_percent = STD_WINDOW_SCALING_PERCENT;
1346 setup.window_scaling_percent +=
1347 (key == KSYM_minus ? -1 : +1) * STEP_WINDOW_SCALING_PERCENT;
1349 if (setup.window_scaling_percent < MIN_WINDOW_SCALING_PERCENT)
1350 setup.window_scaling_percent = MIN_WINDOW_SCALING_PERCENT;
1351 else if (setup.window_scaling_percent > MAX_WINDOW_SCALING_PERCENT)
1352 setup.window_scaling_percent = MAX_WINDOW_SCALING_PERCENT;
1354 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1356 if (game_status == GAME_MODE_SETUP)
1357 RedrawSetupScreenAfterFullscreenToggle();
1362 if (game_status == GAME_MODE_PLAYING && AllPlayersGone &&
1363 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
1370 if (game_status == GAME_MODE_MAIN &&
1371 (key == setup.shortcut.toggle_pause || key == KSYM_space))
1373 StartGameActions(options.network, setup.autorecord, level.random_seed);
1378 if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING)
1380 if (key == setup.shortcut.save_game)
1382 else if (key == setup.shortcut.load_game)
1384 else if (key == setup.shortcut.toggle_pause)
1385 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1387 HandleTapeButtonKeys(key);
1388 HandleSoundButtonKeys(key);
1391 if (game_status == GAME_MODE_PLAYING && !network_playing)
1393 int centered_player_nr_next = -999;
1395 if (key == setup.shortcut.focus_player_all)
1396 centered_player_nr_next = -1;
1398 for (i = 0; i < MAX_PLAYERS; i++)
1399 if (key == setup.shortcut.focus_player[i])
1400 centered_player_nr_next = i;
1402 if (centered_player_nr_next != -999)
1404 game.centered_player_nr_next = centered_player_nr_next;
1405 game.set_centered_player = TRUE;
1409 tape.centered_player_nr_next = game.centered_player_nr_next;
1410 tape.set_centered_player = TRUE;
1415 HandleKeysSpecial(key);
1417 if (HandleGadgetsKeyInput(key))
1419 if (key != KSYM_Escape) /* always allow ESC key to be handled */
1420 key = KSYM_UNDEFINED;
1423 switch (game_status)
1425 case GAME_MODE_PSEUDO_TYPENAME:
1426 HandleTypeName(0, key);
1429 case GAME_MODE_TITLE:
1430 case GAME_MODE_MAIN:
1431 case GAME_MODE_LEVELS:
1432 case GAME_MODE_LEVELNR:
1433 case GAME_MODE_SETUP:
1434 case GAME_MODE_INFO:
1435 case GAME_MODE_SCORES:
1440 if (game_status == GAME_MODE_TITLE)
1441 HandleTitleScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1442 else if (game_status == GAME_MODE_MAIN)
1443 HandleMainMenu(0, 0, 0, 0, MB_MENU_CHOICE);
1444 else if (game_status == GAME_MODE_LEVELS)
1445 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_CHOICE);
1446 else if (game_status == GAME_MODE_LEVELNR)
1447 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_CHOICE);
1448 else if (game_status == GAME_MODE_SETUP)
1449 HandleSetupScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1450 else if (game_status == GAME_MODE_INFO)
1451 HandleInfoScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1452 else if (game_status == GAME_MODE_SCORES)
1453 HandleHallOfFame(0, 0, 0, 0, MB_MENU_CHOICE);
1457 if (game_status != GAME_MODE_MAIN)
1458 FadeSkipNextFadeIn();
1460 if (game_status == GAME_MODE_TITLE)
1461 HandleTitleScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1462 else if (game_status == GAME_MODE_LEVELS)
1463 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_LEAVE);
1464 else if (game_status == GAME_MODE_LEVELNR)
1465 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_LEAVE);
1466 else if (game_status == GAME_MODE_SETUP)
1467 HandleSetupScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1468 else if (game_status == GAME_MODE_INFO)
1469 HandleInfoScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1470 else if (game_status == GAME_MODE_SCORES)
1471 HandleHallOfFame(0, 0, 0, 0, MB_MENU_LEAVE);
1475 if (game_status == GAME_MODE_LEVELS)
1476 HandleChooseLevelSet(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1477 else if (game_status == GAME_MODE_LEVELNR)
1478 HandleChooseLevelNr(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1479 else if (game_status == GAME_MODE_SETUP)
1480 HandleSetupScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1481 else if (game_status == GAME_MODE_INFO)
1482 HandleInfoScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1483 else if (game_status == GAME_MODE_SCORES)
1484 HandleHallOfFame(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1487 case KSYM_Page_Down:
1488 if (game_status == GAME_MODE_LEVELS)
1489 HandleChooseLevelSet(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1490 else if (game_status == GAME_MODE_LEVELNR)
1491 HandleChooseLevelNr(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1492 else if (game_status == GAME_MODE_SETUP)
1493 HandleSetupScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1494 else if (game_status == GAME_MODE_INFO)
1495 HandleInfoScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1496 else if (game_status == GAME_MODE_SCORES)
1497 HandleHallOfFame(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1502 GameFrameDelay = (GameFrameDelay == 500 ? GAME_FRAME_DELAY : 500);
1506 setup.sp_show_border_elements = !setup.sp_show_border_elements;
1507 printf("Supaplex border elements %s\n",
1508 setup.sp_show_border_elements ? "enabled" : "disabled");
1517 case GAME_MODE_EDITOR:
1518 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
1519 HandleLevelEditorKeyInput(key);
1522 case GAME_MODE_PLAYING:
1527 RequestQuitGame(setup.ask_on_escape);
1534 if (GameFrameDelay == 500)
1535 GameFrameDelay = GAME_FRAME_DELAY;
1537 GameFrameDelay = 500;
1540 GameFrameDelay = (key - KSYM_0) * 10;
1541 printf("Game speed == %d%% (%d ms delay between two frames)\n",
1542 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
1548 options.debug = FALSE;
1549 printf("debug mode disabled\n");
1553 options.debug = TRUE;
1554 printf("debug mode enabled\n");
1559 printf("::: currently using game engine version %d\n",
1560 game.engine_version);
1571 if (key == KSYM_Escape)
1573 SetGameStatus(GAME_MODE_MAIN);
1582 void HandleNoEvent()
1584 // if (button_status && game_status != GAME_MODE_PLAYING)
1585 if (button_status && (game_status != GAME_MODE_PLAYING || tape.pausing))
1587 HandleButton(0, 0, -button_status, button_status);
1594 #if defined(NETWORK_AVALIABLE)
1595 if (options.network)
1599 switch (game_status)
1601 case GAME_MODE_MAIN:
1602 DrawPreviewLevelAnimation();
1606 case GAME_MODE_LEVELS:
1607 case GAME_MODE_LEVELNR:
1608 case GAME_MODE_SETUP:
1609 case GAME_MODE_INFO:
1610 case GAME_MODE_SCORES:
1614 case GAME_MODE_EDITOR:
1615 HandleLevelEditorIdle();
1623 static int HandleJoystickForAllPlayers()
1628 for (i = 0; i < MAX_PLAYERS; i++)
1630 byte joy_action = 0;
1633 if (!setup.input[i].use_joystick)
1637 joy_action = Joystick(i);
1638 result |= joy_action;
1640 if (!setup.input[i].use_joystick)
1643 stored_player[i].action = joy_action;
1649 void HandleJoystick()
1651 int joystick = HandleJoystickForAllPlayers();
1652 int keyboard = key_joystick_mapping;
1653 int joy = (joystick | keyboard);
1654 int left = joy & JOY_LEFT;
1655 int right = joy & JOY_RIGHT;
1656 int up = joy & JOY_UP;
1657 int down = joy & JOY_DOWN;
1658 int button = joy & JOY_BUTTON;
1659 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
1660 int dx = (left ? -1 : right ? 1 : 0);
1661 int dy = (up ? -1 : down ? 1 : 0);
1663 switch (game_status)
1665 case GAME_MODE_TITLE:
1666 case GAME_MODE_MAIN:
1667 case GAME_MODE_LEVELS:
1668 case GAME_MODE_LEVELNR:
1669 case GAME_MODE_SETUP:
1670 case GAME_MODE_INFO:
1672 static unsigned int joystickmove_delay = 0;
1674 if (joystick && !button &&
1675 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
1676 newbutton = dx = dy = 0;
1678 if (game_status == GAME_MODE_TITLE)
1679 HandleTitleScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1680 else if (game_status == GAME_MODE_MAIN)
1681 HandleMainMenu(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1682 else if (game_status == GAME_MODE_LEVELS)
1683 HandleChooseLevelSet(0,0,dx,dy,newbutton?MB_MENU_CHOICE : MB_MENU_MARK);
1684 else if (game_status == GAME_MODE_LEVELNR)
1685 HandleChooseLevelNr(0,0,dx,dy,newbutton? MB_MENU_CHOICE : MB_MENU_MARK);
1686 else if (game_status == GAME_MODE_SETUP)
1687 HandleSetupScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1688 else if (game_status == GAME_MODE_INFO)
1689 HandleInfoScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1693 case GAME_MODE_SCORES:
1694 HandleHallOfFame(0, 0, dx, dy, !newbutton);
1697 case GAME_MODE_PLAYING:
1698 if (tape.playing || keyboard)
1699 newbutton = ((joy & JOY_BUTTON) != 0);
1701 if (newbutton && AllPlayersGone)