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)
158 unsigned int event_frame_delay = 0;
159 unsigned int event_frame_delay_value = GAME_FRAME_DELAY;
161 ResetDelayCounter(&event_frame_delay);
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);
209 // do not handle events for longer than standard frame delay period
210 if (DelayReached(&event_frame_delay, event_frame_delay_value))
215 void HandleOtherEvents(Event *event)
220 HandleExposeEvent((ExposeEvent *) event);
223 case EVENT_UNMAPNOTIFY:
225 /* This causes the game to stop not only when iconified, but also
226 when on another virtual desktop, which might be not desired. */
227 SleepWhileUnmapped();
233 HandleFocusEvent((FocusChangeEvent *) event);
236 case EVENT_CLIENTMESSAGE:
237 HandleClientMessageEvent((ClientMessageEvent *) event);
240 #if defined(TARGET_SDL)
241 case SDL_JOYAXISMOTION:
242 case SDL_JOYBUTTONDOWN:
243 case SDL_JOYBUTTONUP:
244 HandleJoystickEvent(event);
248 HandleWindowManagerEvent(event);
257 void HandleMouseCursor()
259 if (game_status == GAME_MODE_TITLE)
261 /* when showing title screens, hide mouse pointer (if not moved) */
263 if (gfx.cursor_mode != CURSOR_NONE &&
264 DelayReached(&special_cursor_delay, special_cursor_delay_value))
266 SetMouseCursor(CURSOR_NONE);
269 else if (game_status == GAME_MODE_PLAYING && (!tape.pausing ||
272 /* when playing, display a special mouse pointer inside the playfield */
274 if (gfx.cursor_mode != CURSOR_PLAYFIELD &&
275 cursor_inside_playfield &&
276 DelayReached(&special_cursor_delay, special_cursor_delay_value))
278 SetMouseCursor(CURSOR_PLAYFIELD);
281 else if (gfx.cursor_mode != CURSOR_DEFAULT)
283 SetMouseCursor(CURSOR_DEFAULT);
286 /* this is set after all pending events have been processed */
287 cursor_mode_last = gfx.cursor_mode;
299 /* also execute after pending events have been processed before */
302 /* don't use all CPU time when idle; the main loop while playing
303 has its own synchronization and is CPU friendly, too */
305 if (game_status == GAME_MODE_PLAYING)
308 /* always copy backbuffer to visible screen for every video frame */
311 /* reset video frame delay to default (may change again while playing) */
312 SetVideoFrameDelay(GAME_FRAME_DELAY);
314 if (game_status == GAME_MODE_QUIT)
319 void ClearEventQueue()
321 while (PendingEvent())
329 case EVENT_BUTTONRELEASE:
330 button_status = MB_RELEASED;
333 case EVENT_KEYRELEASE:
338 HandleOtherEvents(&event);
344 void ClearPlayerAction()
348 /* simulate key release events for still pressed keys */
349 key_joystick_mapping = 0;
350 for (i = 0; i < MAX_PLAYERS; i++)
351 stored_player[i].action = 0;
354 void SleepWhileUnmapped()
356 boolean window_unmapped = TRUE;
358 KeyboardAutoRepeatOn();
360 while (window_unmapped)
368 case EVENT_BUTTONRELEASE:
369 button_status = MB_RELEASED;
372 case EVENT_KEYRELEASE:
373 key_joystick_mapping = 0;
376 case EVENT_MAPNOTIFY:
377 window_unmapped = FALSE;
380 case EVENT_UNMAPNOTIFY:
381 /* this is only to surely prevent the 'should not happen' case
382 * of recursively looping between 'SleepWhileUnmapped()' and
383 * 'HandleOtherEvents()' which usually calls this funtion.
388 HandleOtherEvents(&event);
393 if (game_status == GAME_MODE_PLAYING)
394 KeyboardAutoRepeatOffUnlessAutoplay();
397 void HandleExposeEvent(ExposeEvent *event)
401 void HandleButtonEvent(ButtonEvent *event)
403 #if DEBUG_EVENTS_BUTTON
404 Error(ERR_DEBUG, "BUTTON EVENT: button %d %s, x/y %d/%d\n",
406 event->type == EVENT_BUTTONPRESS ? "pressed" : "released",
410 motion_status = FALSE;
412 if (event->type == EVENT_BUTTONPRESS)
413 button_status = event->button;
415 button_status = MB_RELEASED;
417 HandleButton(event->x, event->y, button_status, event->button);
420 void HandleMotionEvent(MotionEvent *event)
422 if (button_status == MB_RELEASED && game_status != GAME_MODE_EDITOR)
425 motion_status = TRUE;
427 #if DEBUG_EVENTS_MOTION
428 Error(ERR_DEBUG, "MOTION EVENT: button %d moved, x/y %d/%d\n",
429 button_status, event->x, event->y);
432 HandleButton(event->x, event->y, button_status, button_status);
435 #if defined(TARGET_SDL2)
437 void HandleWindowEvent(WindowEvent *event)
439 #if DEBUG_EVENTS_WINDOW
440 int subtype = event->event;
443 (subtype == SDL_WINDOWEVENT_SHOWN ? "SDL_WINDOWEVENT_SHOWN" :
444 subtype == SDL_WINDOWEVENT_HIDDEN ? "SDL_WINDOWEVENT_HIDDEN" :
445 subtype == SDL_WINDOWEVENT_EXPOSED ? "SDL_WINDOWEVENT_EXPOSED" :
446 subtype == SDL_WINDOWEVENT_MOVED ? "SDL_WINDOWEVENT_MOVED" :
447 subtype == SDL_WINDOWEVENT_SIZE_CHANGED ? "SDL_WINDOWEVENT_SIZE_CHANGED" :
448 subtype == SDL_WINDOWEVENT_RESIZED ? "SDL_WINDOWEVENT_RESIZED" :
449 subtype == SDL_WINDOWEVENT_MINIMIZED ? "SDL_WINDOWEVENT_MINIMIZED" :
450 subtype == SDL_WINDOWEVENT_MAXIMIZED ? "SDL_WINDOWEVENT_MAXIMIZED" :
451 subtype == SDL_WINDOWEVENT_RESTORED ? "SDL_WINDOWEVENT_RESTORED" :
452 subtype == SDL_WINDOWEVENT_ENTER ? "SDL_WINDOWEVENT_ENTER" :
453 subtype == SDL_WINDOWEVENT_LEAVE ? "SDL_WINDOWEVENT_LEAVE" :
454 subtype == SDL_WINDOWEVENT_FOCUS_GAINED ? "SDL_WINDOWEVENT_FOCUS_GAINED" :
455 subtype == SDL_WINDOWEVENT_FOCUS_LOST ? "SDL_WINDOWEVENT_FOCUS_LOST" :
456 subtype == SDL_WINDOWEVENT_CLOSE ? "SDL_WINDOWEVENT_CLOSE" :
459 Error(ERR_DEBUG, "WINDOW EVENT: '%s', %ld, %ld",
460 event_name, event->data1, event->data2);
463 if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED ||
464 event->event == SDL_WINDOWEVENT_RESIZED ||
465 event->event == SDL_WINDOWEVENT_EXPOSED)
468 if (event->event == SDL_WINDOWEVENT_RESIZED && !video.fullscreen_enabled)
470 int new_window_width = event->data1;
471 int new_window_height = event->data2;
473 // if window size has changed after resizing, calculate new scaling factor
474 if (new_window_width != video.window_width ||
475 new_window_height != video.window_height)
477 int new_xpercent = (100 * new_window_width / video.width);
478 int new_ypercent = (100 * new_window_height / video.height);
480 setup.window_scaling_percent = video.window_scaling_percent =
481 MIN(MAX(MIN_WINDOW_SCALING_PERCENT, MIN(new_xpercent, new_ypercent)),
482 MAX_WINDOW_SCALING_PERCENT);
484 video.window_width = new_window_width;
485 video.window_height = new_window_height;
487 if (game_status == GAME_MODE_SETUP)
488 RedrawSetupScreenAfterFullscreenToggle();
495 #define NUM_TOUCH_FINGERS 3
500 SDL_FingerID finger_id;
503 } touch_info[NUM_TOUCH_FINGERS];
505 void HandleFingerEvent(FingerEvent *event)
507 static Key motion_key_x = KSYM_UNDEFINED;
508 static Key motion_key_y = KSYM_UNDEFINED;
509 static Key button_key = KSYM_UNDEFINED;
510 static float motion_x1, motion_y1;
511 static float button_x1, button_y1;
512 static SDL_FingerID motion_id = -1;
513 static SDL_FingerID button_id = -1;
514 int move_trigger_distance_percent = 2; // percent of touchpad width/height
515 int drop_trigger_distance_percent = 5; // percent of touchpad width/height
516 float move_trigger_distance = (float)move_trigger_distance_percent / 100;
517 float drop_trigger_distance = (float)drop_trigger_distance_percent / 100;
518 float event_x = event->x;
519 float event_y = event->y;
521 #if DEBUG_EVENTS_FINGER
522 Error(ERR_DEBUG, "FINGER EVENT: finger was %s, touch ID %lld, finger ID %lld, x/y %f/%f, dx/dy %f/%f, pressure %f",
523 event->type == EVENT_FINGERPRESS ? "pressed" :
524 event->type == EVENT_FINGERRELEASE ? "released" : "moved",
528 event->dx, event->dy,
532 if (game_status != GAME_MODE_PLAYING)
535 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
537 int key_status = (event->type == EVENT_FINGERRELEASE ? KEY_RELEASED :
539 Key key = (event->x < 1.0 / 3.0 ?
540 (event->y < 1.0 / 2.0 ? setup.input[0].key.snap :
541 setup.input[0].key.drop) :
542 event->x > 2.0 / 3.0 ?
543 (event->y < 1.0 / 3.0 ? setup.input[0].key.up :
544 event->y > 2.0 / 3.0 ? setup.input[0].key.down :
545 event->x < 5.0 / 6.0 ? setup.input[0].key.left :
546 setup.input[0].key.right) :
548 char *key_status_name = (key_status == KEY_RELEASED ? "KEY_RELEASED" :
552 Error(ERR_DEBUG, "::: key '%s' was '%s' [fingerId: %lld]",
553 getKeyNameFromKey(key), key_status_name, event->fingerId);
555 // check if we already know this touch event's finger id
556 for (i = 0; i < NUM_TOUCH_FINGERS; i++)
558 if (touch_info[i].touched &&
559 touch_info[i].finger_id == event->fingerId)
561 // Error(ERR_DEBUG, "MARK 1: %d", i);
567 if (i >= NUM_TOUCH_FINGERS)
569 if (key_status == KEY_PRESSED)
571 int oldest_pos = 0, oldest_counter = touch_info[0].counter;
573 // unknown finger id -- get new, empty slot, if available
574 for (i = 0; i < NUM_TOUCH_FINGERS; i++)
576 if (touch_info[i].counter < oldest_counter)
579 oldest_counter = touch_info[i].counter;
581 // Error(ERR_DEBUG, "MARK 2: %d", i);
584 if (!touch_info[i].touched)
586 // Error(ERR_DEBUG, "MARK 3: %d", i);
592 if (i >= NUM_TOUCH_FINGERS)
594 // all slots allocated -- use oldest slot
597 // Error(ERR_DEBUG, "MARK 4: %d", i);
602 // release of previously unknown key (should not happen)
604 if (key != KSYM_UNDEFINED)
606 HandleKey(key, KEY_RELEASED);
608 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [1]",
609 getKeyNameFromKey(key), "KEY_RELEASED", i);
614 if (i < NUM_TOUCH_FINGERS)
616 if (key_status == KEY_PRESSED)
618 if (touch_info[i].key != key)
620 if (touch_info[i].key != KSYM_UNDEFINED)
622 HandleKey(touch_info[i].key, KEY_RELEASED);
624 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [2]",
625 getKeyNameFromKey(touch_info[i].key), "KEY_RELEASED", i);
628 if (key != KSYM_UNDEFINED)
630 HandleKey(key, KEY_PRESSED);
632 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [3]",
633 getKeyNameFromKey(key), "KEY_PRESSED", i);
637 touch_info[i].touched = TRUE;
638 touch_info[i].finger_id = event->fingerId;
639 touch_info[i].counter = Counter();
640 touch_info[i].key = key;
644 if (touch_info[i].key != KSYM_UNDEFINED)
646 HandleKey(touch_info[i].key, KEY_RELEASED);
648 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [4]",
649 getKeyNameFromKey(touch_info[i].key), "KEY_RELEASED", i);
652 touch_info[i].touched = FALSE;
653 touch_info[i].finger_id = 0;
654 touch_info[i].counter = 0;
655 touch_info[i].key = 0;
662 // use touch direction control
664 if (event->type == EVENT_FINGERPRESS)
666 if (event_x > 1.0 / 3.0)
670 motion_id = event->fingerId;
675 motion_key_x = KSYM_UNDEFINED;
676 motion_key_y = KSYM_UNDEFINED;
678 Error(ERR_DEBUG, "---------- MOVE STARTED (WAIT) ----------");
684 button_id = event->fingerId;
689 button_key = setup.input[0].key.snap;
691 HandleKey(button_key, KEY_PRESSED);
693 Error(ERR_DEBUG, "---------- SNAP STARTED ----------");
696 else if (event->type == EVENT_FINGERRELEASE)
698 if (event->fingerId == motion_id)
702 if (motion_key_x != KSYM_UNDEFINED)
703 HandleKey(motion_key_x, KEY_RELEASED);
704 if (motion_key_y != KSYM_UNDEFINED)
705 HandleKey(motion_key_y, KEY_RELEASED);
707 motion_key_x = KSYM_UNDEFINED;
708 motion_key_y = KSYM_UNDEFINED;
710 Error(ERR_DEBUG, "---------- MOVE STOPPED ----------");
712 else if (event->fingerId == button_id)
716 if (button_key != KSYM_UNDEFINED)
717 HandleKey(button_key, KEY_RELEASED);
719 button_key = KSYM_UNDEFINED;
721 Error(ERR_DEBUG, "---------- SNAP STOPPED ----------");
724 else if (event->type == EVENT_FINGERMOTION)
726 if (event->fingerId == motion_id)
728 float distance_x = ABS(event_x - motion_x1);
729 float distance_y = ABS(event_y - motion_y1);
730 Key new_motion_key_x = (event_x < motion_x1 ? setup.input[0].key.left :
731 event_x > motion_x1 ? setup.input[0].key.right :
733 Key new_motion_key_y = (event_y < motion_y1 ? setup.input[0].key.up :
734 event_y > motion_y1 ? setup.input[0].key.down :
737 if (distance_x < move_trigger_distance / 2 ||
738 distance_x < distance_y)
739 new_motion_key_x = KSYM_UNDEFINED;
741 if (distance_y < move_trigger_distance / 2 ||
742 distance_y < distance_x)
743 new_motion_key_y = KSYM_UNDEFINED;
745 if (distance_x > move_trigger_distance ||
746 distance_y > move_trigger_distance)
748 if (new_motion_key_x != motion_key_x)
750 if (motion_key_x != KSYM_UNDEFINED)
751 HandleKey(motion_key_x, KEY_RELEASED);
752 if (new_motion_key_x != KSYM_UNDEFINED)
753 HandleKey(new_motion_key_x, KEY_PRESSED);
756 if (new_motion_key_y != motion_key_y)
758 if (motion_key_y != KSYM_UNDEFINED)
759 HandleKey(motion_key_y, KEY_RELEASED);
760 if (new_motion_key_y != KSYM_UNDEFINED)
761 HandleKey(new_motion_key_y, KEY_PRESSED);
767 motion_key_x = new_motion_key_x;
768 motion_key_y = new_motion_key_y;
770 Error(ERR_DEBUG, "---------- MOVE STARTED (MOVE) ----------");
773 else if (event->fingerId == button_id)
775 float distance_x = ABS(event_x - button_x1);
776 float distance_y = ABS(event_y - button_y1);
778 if (distance_x < drop_trigger_distance / 2 &&
779 distance_y > drop_trigger_distance)
781 if (button_key == setup.input[0].key.snap)
782 HandleKey(button_key, KEY_RELEASED);
787 button_key = setup.input[0].key.drop;
789 HandleKey(button_key, KEY_PRESSED);
791 Error(ERR_DEBUG, "---------- DROP STARTED ----------");
797 static boolean checkTextInputKeyModState()
799 // when playing, only handle raw key events and ignore text input
800 if (game_status == GAME_MODE_PLAYING)
803 return ((GetKeyModState() & KMOD_TextInput) != KMOD_None);
806 void HandleTextEvent(TextEvent *event)
808 char *text = event->text;
809 Key key = getKeyFromKeyName(text);
811 #if DEBUG_EVENTS_TEXT
812 Error(ERR_DEBUG, "TEXT EVENT: text == '%s' [%d byte(s), '%c'/%d], resulting key == %d (%s) [%04x]",
815 text[0], (int)(text[0]),
817 getKeyNameFromKey(key),
821 #if defined(PLATFORM_ANDROID)
822 if (game_status == GAME_MODE_PSEUDO_TYPENAME)
824 HandleTypeName(0, key);
830 // only handle key input with text modifier keys pressed
831 if (checkTextInputKeyModState())
833 HandleKey(key, KEY_PRESSED);
834 HandleKey(key, KEY_RELEASED);
838 void HandlePauseResumeEvent(PauseResumeEvent *event)
840 if (event->type == SDL_APP_WILLENTERBACKGROUND)
844 else if (event->type == SDL_APP_DIDENTERFOREGROUND)
852 void HandleKeyEvent(KeyEvent *event)
854 int key_status = (event->type == EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
855 boolean with_modifiers = (game_status == GAME_MODE_PLAYING ? FALSE : TRUE);
856 Key key = GetEventKey(event, with_modifiers);
857 Key keymod = (with_modifiers ? GetEventKey(event, FALSE) : key);
860 Error(ERR_DEBUG, "KEY EVENT: key was %s, keysym.scancode == %d, keysym.sym == %d, keymod = %d, GetKeyModState() = 0x%04x, resulting key == %d (%s)",
861 event->type == EVENT_KEYPRESS ? "pressed" : "released",
862 event->keysym.scancode,
867 getKeyNameFromKey(key));
870 #if defined(PLATFORM_ANDROID)
871 // always map the "back" button to the "escape" key on Android devices
872 if (key == KSYM_Back)
876 HandleKeyModState(keymod, key_status);
878 #if defined(TARGET_SDL2)
879 // only handle raw key input without text modifier keys pressed
880 if (!checkTextInputKeyModState())
881 HandleKey(key, key_status);
883 HandleKey(key, key_status);
887 void HandleFocusEvent(FocusChangeEvent *event)
889 static int old_joystick_status = -1;
891 if (event->type == EVENT_FOCUSOUT)
893 KeyboardAutoRepeatOn();
894 old_joystick_status = joystick.status;
895 joystick.status = JOYSTICK_NOT_AVAILABLE;
899 else if (event->type == EVENT_FOCUSIN)
901 /* When there are two Rocks'n'Diamonds windows which overlap and
902 the player moves the pointer from one game window to the other,
903 a 'FocusOut' event is generated for the window the pointer is
904 leaving and a 'FocusIn' event is generated for the window the
905 pointer is entering. In some cases, it can happen that the
906 'FocusIn' event is handled by the one game process before the
907 'FocusOut' event by the other game process. In this case the
908 X11 environment would end up with activated keyboard auto repeat,
909 because unfortunately this is a global setting and not (which
910 would be far better) set for each X11 window individually.
911 The effect would be keyboard auto repeat while playing the game
912 (game_status == GAME_MODE_PLAYING), which is not desired.
913 To avoid this special case, we just wait 1/10 second before
914 processing the 'FocusIn' event.
917 if (game_status == GAME_MODE_PLAYING)
920 KeyboardAutoRepeatOffUnlessAutoplay();
923 if (old_joystick_status != -1)
924 joystick.status = old_joystick_status;
928 void HandleClientMessageEvent(ClientMessageEvent *event)
930 if (CheckCloseWindowEvent(event))
934 void HandleWindowManagerEvent(Event *event)
936 #if defined(TARGET_SDL)
937 SDLHandleWindowManagerEvent(event);
941 void HandleButton(int mx, int my, int button, int button_nr)
943 static int old_mx = 0, old_my = 0;
944 boolean button_hold = FALSE;
959 #if defined(PLATFORM_ANDROID)
960 // !!! for now, do not handle gadgets when playing -- maybe fix this !!!
961 if (game_status != GAME_MODE_PLAYING &&
962 HandleGadgets(mx, my, button))
964 /* do not handle this button event anymore */
965 mx = my = -32; /* force mouse event to be outside screen tiles */
968 if (HandleGadgets(mx, my, button))
970 /* do not handle this button event anymore */
971 mx = my = -32; /* force mouse event to be outside screen tiles */
975 if (button_hold && game_status == GAME_MODE_PLAYING && tape.pausing)
978 /* do not use scroll wheel button events for anything other than gadgets */
979 if (IS_WHEEL_BUTTON(button_nr))
984 case GAME_MODE_TITLE:
985 HandleTitleScreen(mx, my, 0, 0, button);
989 HandleMainMenu(mx, my, 0, 0, button);
992 case GAME_MODE_PSEUDO_TYPENAME:
993 HandleTypeName(0, KSYM_Return);
996 case GAME_MODE_LEVELS:
997 HandleChooseLevelSet(mx, my, 0, 0, button);
1000 case GAME_MODE_LEVELNR:
1001 HandleChooseLevelNr(mx, my, 0, 0, button);
1004 case GAME_MODE_SCORES:
1005 HandleHallOfFame(0, 0, 0, 0, button);
1008 case GAME_MODE_EDITOR:
1009 HandleLevelEditorIdle();
1012 case GAME_MODE_INFO:
1013 HandleInfoScreen(mx, my, 0, 0, button);
1016 case GAME_MODE_SETUP:
1017 HandleSetupScreen(mx, my, 0, 0, button);
1020 case GAME_MODE_PLAYING:
1022 if (button == MB_PRESSED && !motion_status && IN_GFX_FIELD_PLAY(mx, my))
1023 DumpTile(LEVELX((mx - SX) / TILESIZE_VAR),
1024 LEVELY((my - SY) / TILESIZE_VAR));
1025 // DumpTile(LEVELX((mx - SX) / TILEX), LEVELY((my - SY) / TILEY));
1034 static boolean is_string_suffix(char *string, char *suffix)
1036 int string_len = strlen(string);
1037 int suffix_len = strlen(suffix);
1039 if (suffix_len > string_len)
1042 return (strEqual(&string[string_len - suffix_len], suffix));
1045 #define MAX_CHEAT_INPUT_LEN 32
1047 static void HandleKeysSpecial(Key key)
1049 static char cheat_input[2 * MAX_CHEAT_INPUT_LEN + 1] = "";
1050 char letter = getCharFromKey(key);
1051 int cheat_input_len = strlen(cheat_input);
1057 if (cheat_input_len >= 2 * MAX_CHEAT_INPUT_LEN)
1059 for (i = 0; i < MAX_CHEAT_INPUT_LEN + 1; i++)
1060 cheat_input[i] = cheat_input[MAX_CHEAT_INPUT_LEN + i];
1062 cheat_input_len = MAX_CHEAT_INPUT_LEN;
1065 cheat_input[cheat_input_len++] = letter;
1066 cheat_input[cheat_input_len] = '\0';
1068 #if DEBUG_EVENTS_KEY
1069 Error(ERR_DEBUG, "SPECIAL KEY '%s' [%d]\n", cheat_input, cheat_input_len);
1072 if (game_status == GAME_MODE_MAIN)
1074 if (is_string_suffix(cheat_input, ":insert-solution-tape") ||
1075 is_string_suffix(cheat_input, ":ist"))
1077 InsertSolutionTape();
1079 else if (is_string_suffix(cheat_input, ":reload-graphics") ||
1080 is_string_suffix(cheat_input, ":rg"))
1082 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS);
1085 else if (is_string_suffix(cheat_input, ":reload-sounds") ||
1086 is_string_suffix(cheat_input, ":rs"))
1088 ReloadCustomArtwork(1 << ARTWORK_TYPE_SOUNDS);
1091 else if (is_string_suffix(cheat_input, ":reload-music") ||
1092 is_string_suffix(cheat_input, ":rm"))
1094 ReloadCustomArtwork(1 << ARTWORK_TYPE_MUSIC);
1097 else if (is_string_suffix(cheat_input, ":reload-artwork") ||
1098 is_string_suffix(cheat_input, ":ra"))
1100 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS |
1101 1 << ARTWORK_TYPE_SOUNDS |
1102 1 << ARTWORK_TYPE_MUSIC);
1105 else if (is_string_suffix(cheat_input, ":dump-level") ||
1106 is_string_suffix(cheat_input, ":dl"))
1110 else if (is_string_suffix(cheat_input, ":dump-tape") ||
1111 is_string_suffix(cheat_input, ":dt"))
1115 else if (is_string_suffix(cheat_input, ":fix-tape") ||
1116 is_string_suffix(cheat_input, ":ft"))
1118 /* fix single-player tapes that contain player input for more than one
1119 player (due to a bug in 3.3.1.2 and earlier versions), which results
1120 in playing levels with more than one player in multi-player mode,
1121 even though the tape was originally recorded in single-player mode */
1123 /* remove player input actions for all players but the first one */
1124 for (i = 1; i < MAX_PLAYERS; i++)
1125 tape.player_participates[i] = FALSE;
1127 tape.changed = TRUE;
1129 else if (is_string_suffix(cheat_input, ":save-native-level") ||
1130 is_string_suffix(cheat_input, ":snl"))
1132 SaveNativeLevel(&level);
1135 else if (game_status == GAME_MODE_PLAYING)
1138 if (is_string_suffix(cheat_input, ".q"))
1139 DEBUG_SetMaximumDynamite();
1142 else if (game_status == GAME_MODE_EDITOR)
1144 if (is_string_suffix(cheat_input, ":dump-brush") ||
1145 is_string_suffix(cheat_input, ":DB"))
1149 else if (is_string_suffix(cheat_input, ":DDB"))
1156 void HandleKey(Key key, int key_status)
1158 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
1159 static boolean ignore_repeated_key = FALSE;
1160 static struct SetupKeyboardInfo ski;
1161 static struct SetupShortcutInfo ssi;
1170 { &ski.left, &ssi.snap_left, DEFAULT_KEY_LEFT, JOY_LEFT },
1171 { &ski.right, &ssi.snap_right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
1172 { &ski.up, &ssi.snap_up, DEFAULT_KEY_UP, JOY_UP },
1173 { &ski.down, &ssi.snap_down, DEFAULT_KEY_DOWN, JOY_DOWN },
1174 { &ski.snap, NULL, DEFAULT_KEY_SNAP, JOY_BUTTON_SNAP },
1175 { &ski.drop, NULL, DEFAULT_KEY_DROP, JOY_BUTTON_DROP }
1180 if (game_status == GAME_MODE_PLAYING)
1182 /* only needed for single-step tape recording mode */
1183 static boolean clear_snap_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1184 static boolean clear_drop_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1185 static boolean element_snapped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1186 static boolean element_dropped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1189 for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
1191 byte key_action = 0;
1193 if (setup.input[pnr].use_joystick)
1196 ski = setup.input[pnr].key;
1198 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1199 if (key == *key_info[i].key_custom)
1200 key_action |= key_info[i].action;
1202 /* use combined snap+direction keys for the first player only */
1205 ssi = setup.shortcut;
1207 for (i = 0; i < NUM_DIRECTIONS; i++)
1208 if (key == *key_info[i].key_snap)
1209 key_action |= key_info[i].action | JOY_BUTTON_SNAP;
1212 /* clear delayed snap and drop actions in single step mode (see below) */
1213 if (tape.single_step)
1215 if (clear_snap_button[pnr])
1217 stored_player[pnr].action &= ~KEY_BUTTON_SNAP;
1218 clear_snap_button[pnr] = FALSE;
1221 if (clear_drop_button[pnr])
1223 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1224 clear_drop_button[pnr] = FALSE;
1228 if (key_status == KEY_PRESSED)
1229 stored_player[pnr].action |= key_action;
1231 stored_player[pnr].action &= ~key_action;
1233 if (tape.single_step && tape.recording && tape.pausing)
1235 if (key_status == KEY_PRESSED && key_action & KEY_MOTION)
1237 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1239 /* if snap key already pressed, don't snap when releasing (below) */
1240 if (stored_player[pnr].action & KEY_BUTTON_SNAP)
1241 element_snapped[pnr] = TRUE;
1243 /* if drop key already pressed, don't drop when releasing (below) */
1244 if (stored_player[pnr].action & KEY_BUTTON_DROP)
1245 element_dropped[pnr] = TRUE;
1247 else if (key_status == KEY_PRESSED && key_action & KEY_BUTTON_DROP)
1249 if (level.game_engine_type == GAME_ENGINE_TYPE_EM ||
1250 level.game_engine_type == GAME_ENGINE_TYPE_SP)
1253 if (level.game_engine_type == GAME_ENGINE_TYPE_SP &&
1254 getRedDiskReleaseFlag_SP() == 0)
1255 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1257 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1260 else if (key_status == KEY_RELEASED && key_action & KEY_BUTTON)
1262 if (key_action & KEY_BUTTON_SNAP)
1264 /* if snap key was released without moving (see above), snap now */
1265 if (!element_snapped[pnr])
1267 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1269 stored_player[pnr].action |= KEY_BUTTON_SNAP;
1271 /* clear delayed snap button on next event */
1272 clear_snap_button[pnr] = TRUE;
1275 element_snapped[pnr] = FALSE;
1278 if (key_action & KEY_BUTTON_DROP &&
1279 level.game_engine_type == GAME_ENGINE_TYPE_RND)
1281 /* if drop key was released without moving (see above), drop now */
1282 if (!element_dropped[pnr])
1284 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1286 if (level.game_engine_type != GAME_ENGINE_TYPE_SP ||
1287 getRedDiskReleaseFlag_SP() != 0)
1288 stored_player[pnr].action |= KEY_BUTTON_DROP;
1290 /* clear delayed drop button on next event */
1291 clear_drop_button[pnr] = TRUE;
1294 element_dropped[pnr] = FALSE;
1298 else if (tape.recording && tape.pausing)
1300 /* prevent key release events from un-pausing a paused game */
1301 if (key_status == KEY_PRESSED && key_action & KEY_ACTION)
1302 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1308 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1309 if (key == key_info[i].key_default)
1310 joy |= key_info[i].action;
1315 if (key_status == KEY_PRESSED)
1316 key_joystick_mapping |= joy;
1318 key_joystick_mapping &= ~joy;
1323 if (game_status != GAME_MODE_PLAYING)
1324 key_joystick_mapping = 0;
1326 if (key_status == KEY_RELEASED)
1328 // reset flag to ignore repeated "key pressed" events after key release
1329 ignore_repeated_key = FALSE;
1334 if ((key == KSYM_F11 ||
1335 ((key == KSYM_Return ||
1336 key == KSYM_KP_Enter) && (GetKeyModState() & KMOD_Alt))) &&
1337 video.fullscreen_available &&
1338 !ignore_repeated_key)
1340 setup.fullscreen = !setup.fullscreen;
1342 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1344 if (game_status == GAME_MODE_SETUP)
1345 RedrawSetupScreenAfterFullscreenToggle();
1347 // set flag to ignore repeated "key pressed" events
1348 ignore_repeated_key = TRUE;
1353 if ((key == KSYM_minus ||
1356 ((GetKeyModState() & KMOD_Control) ||
1357 (GetKeyModState() & KMOD_Alt)) &&
1358 video.window_scaling_available &&
1359 !video.fullscreen_enabled)
1362 setup.window_scaling_percent = STD_WINDOW_SCALING_PERCENT;
1364 setup.window_scaling_percent +=
1365 (key == KSYM_minus ? -1 : +1) * STEP_WINDOW_SCALING_PERCENT;
1367 if (setup.window_scaling_percent < MIN_WINDOW_SCALING_PERCENT)
1368 setup.window_scaling_percent = MIN_WINDOW_SCALING_PERCENT;
1369 else if (setup.window_scaling_percent > MAX_WINDOW_SCALING_PERCENT)
1370 setup.window_scaling_percent = MAX_WINDOW_SCALING_PERCENT;
1372 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1374 if (game_status == GAME_MODE_SETUP)
1375 RedrawSetupScreenAfterFullscreenToggle();
1380 if (game_status == GAME_MODE_PLAYING && AllPlayersGone &&
1381 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
1388 if (game_status == GAME_MODE_MAIN &&
1389 (key == setup.shortcut.toggle_pause || key == KSYM_space))
1391 StartGameActions(options.network, setup.autorecord, level.random_seed);
1396 if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING)
1398 if (key == setup.shortcut.save_game)
1400 else if (key == setup.shortcut.load_game)
1402 else if (key == setup.shortcut.toggle_pause)
1403 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1405 HandleTapeButtonKeys(key);
1406 HandleSoundButtonKeys(key);
1409 if (game_status == GAME_MODE_PLAYING && !network_playing)
1411 int centered_player_nr_next = -999;
1413 if (key == setup.shortcut.focus_player_all)
1414 centered_player_nr_next = -1;
1416 for (i = 0; i < MAX_PLAYERS; i++)
1417 if (key == setup.shortcut.focus_player[i])
1418 centered_player_nr_next = i;
1420 if (centered_player_nr_next != -999)
1422 game.centered_player_nr_next = centered_player_nr_next;
1423 game.set_centered_player = TRUE;
1427 tape.centered_player_nr_next = game.centered_player_nr_next;
1428 tape.set_centered_player = TRUE;
1433 HandleKeysSpecial(key);
1435 if (HandleGadgetsKeyInput(key))
1437 if (key != KSYM_Escape) /* always allow ESC key to be handled */
1438 key = KSYM_UNDEFINED;
1441 switch (game_status)
1443 case GAME_MODE_PSEUDO_TYPENAME:
1444 HandleTypeName(0, key);
1447 case GAME_MODE_TITLE:
1448 case GAME_MODE_MAIN:
1449 case GAME_MODE_LEVELS:
1450 case GAME_MODE_LEVELNR:
1451 case GAME_MODE_SETUP:
1452 case GAME_MODE_INFO:
1453 case GAME_MODE_SCORES:
1458 if (game_status == GAME_MODE_TITLE)
1459 HandleTitleScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1460 else if (game_status == GAME_MODE_MAIN)
1461 HandleMainMenu(0, 0, 0, 0, MB_MENU_CHOICE);
1462 else if (game_status == GAME_MODE_LEVELS)
1463 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_CHOICE);
1464 else if (game_status == GAME_MODE_LEVELNR)
1465 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_CHOICE);
1466 else if (game_status == GAME_MODE_SETUP)
1467 HandleSetupScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1468 else if (game_status == GAME_MODE_INFO)
1469 HandleInfoScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1470 else if (game_status == GAME_MODE_SCORES)
1471 HandleHallOfFame(0, 0, 0, 0, MB_MENU_CHOICE);
1475 if (game_status != GAME_MODE_MAIN)
1476 FadeSkipNextFadeIn();
1478 if (game_status == GAME_MODE_TITLE)
1479 HandleTitleScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1480 else if (game_status == GAME_MODE_LEVELS)
1481 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_LEAVE);
1482 else if (game_status == GAME_MODE_LEVELNR)
1483 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_LEAVE);
1484 else if (game_status == GAME_MODE_SETUP)
1485 HandleSetupScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1486 else if (game_status == GAME_MODE_INFO)
1487 HandleInfoScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1488 else if (game_status == GAME_MODE_SCORES)
1489 HandleHallOfFame(0, 0, 0, 0, MB_MENU_LEAVE);
1493 if (game_status == GAME_MODE_LEVELS)
1494 HandleChooseLevelSet(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1495 else if (game_status == GAME_MODE_LEVELNR)
1496 HandleChooseLevelNr(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1497 else if (game_status == GAME_MODE_SETUP)
1498 HandleSetupScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1499 else if (game_status == GAME_MODE_INFO)
1500 HandleInfoScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1501 else if (game_status == GAME_MODE_SCORES)
1502 HandleHallOfFame(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1505 case KSYM_Page_Down:
1506 if (game_status == GAME_MODE_LEVELS)
1507 HandleChooseLevelSet(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1508 else if (game_status == GAME_MODE_LEVELNR)
1509 HandleChooseLevelNr(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1510 else if (game_status == GAME_MODE_SETUP)
1511 HandleSetupScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1512 else if (game_status == GAME_MODE_INFO)
1513 HandleInfoScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1514 else if (game_status == GAME_MODE_SCORES)
1515 HandleHallOfFame(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1520 GameFrameDelay = (GameFrameDelay == 500 ? GAME_FRAME_DELAY : 500);
1524 setup.sp_show_border_elements = !setup.sp_show_border_elements;
1525 printf("Supaplex border elements %s\n",
1526 setup.sp_show_border_elements ? "enabled" : "disabled");
1535 case GAME_MODE_EDITOR:
1536 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
1537 HandleLevelEditorKeyInput(key);
1540 case GAME_MODE_PLAYING:
1545 RequestQuitGame(setup.ask_on_escape);
1552 if (GameFrameDelay == 500)
1553 GameFrameDelay = GAME_FRAME_DELAY;
1555 GameFrameDelay = 500;
1558 GameFrameDelay = (key - KSYM_0) * 10;
1559 printf("Game speed == %d%% (%d ms delay between two frames)\n",
1560 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
1566 options.debug = FALSE;
1567 printf("debug mode disabled\n");
1571 options.debug = TRUE;
1572 printf("debug mode enabled\n");
1577 printf("::: currently using game engine version %d\n",
1578 game.engine_version);
1589 if (key == KSYM_Escape)
1591 SetGameStatus(GAME_MODE_MAIN);
1600 void HandleNoEvent()
1602 // if (button_status && game_status != GAME_MODE_PLAYING)
1603 if (button_status && (game_status != GAME_MODE_PLAYING || tape.pausing))
1605 HandleButton(0, 0, -button_status, button_status);
1612 #if defined(NETWORK_AVALIABLE)
1613 if (options.network)
1617 switch (game_status)
1619 case GAME_MODE_MAIN:
1620 DrawPreviewLevelAnimation();
1624 case GAME_MODE_LEVELS:
1625 case GAME_MODE_LEVELNR:
1626 case GAME_MODE_SETUP:
1627 case GAME_MODE_INFO:
1628 case GAME_MODE_SCORES:
1632 case GAME_MODE_EDITOR:
1633 HandleLevelEditorIdle();
1641 static int HandleJoystickForAllPlayers()
1646 for (i = 0; i < MAX_PLAYERS; i++)
1648 byte joy_action = 0;
1651 if (!setup.input[i].use_joystick)
1655 joy_action = Joystick(i);
1656 result |= joy_action;
1658 if (!setup.input[i].use_joystick)
1661 stored_player[i].action = joy_action;
1667 void HandleJoystick()
1669 int joystick = HandleJoystickForAllPlayers();
1670 int keyboard = key_joystick_mapping;
1671 int joy = (joystick | keyboard);
1672 int left = joy & JOY_LEFT;
1673 int right = joy & JOY_RIGHT;
1674 int up = joy & JOY_UP;
1675 int down = joy & JOY_DOWN;
1676 int button = joy & JOY_BUTTON;
1677 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
1678 int dx = (left ? -1 : right ? 1 : 0);
1679 int dy = (up ? -1 : down ? 1 : 0);
1681 switch (game_status)
1683 case GAME_MODE_TITLE:
1684 case GAME_MODE_MAIN:
1685 case GAME_MODE_LEVELS:
1686 case GAME_MODE_LEVELNR:
1687 case GAME_MODE_SETUP:
1688 case GAME_MODE_INFO:
1690 static unsigned int joystickmove_delay = 0;
1692 if (joystick && !button &&
1693 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
1694 newbutton = dx = dy = 0;
1696 if (game_status == GAME_MODE_TITLE)
1697 HandleTitleScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1698 else if (game_status == GAME_MODE_MAIN)
1699 HandleMainMenu(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1700 else if (game_status == GAME_MODE_LEVELS)
1701 HandleChooseLevelSet(0,0,dx,dy,newbutton?MB_MENU_CHOICE : MB_MENU_MARK);
1702 else if (game_status == GAME_MODE_LEVELNR)
1703 HandleChooseLevelNr(0,0,dx,dy,newbutton? MB_MENU_CHOICE : MB_MENU_MARK);
1704 else if (game_status == GAME_MODE_SETUP)
1705 HandleSetupScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1706 else if (game_status == GAME_MODE_INFO)
1707 HandleInfoScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1711 case GAME_MODE_SCORES:
1712 HandleHallOfFame(0, 0, dx, dy, !newbutton);
1715 case GAME_MODE_PLAYING:
1716 if (tape.playing || keyboard)
1717 newbutton = ((joy & JOY_BUTTON) != 0);
1719 if (newbutton && AllPlayersGone)