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;
292 unsigned int sync_frame_delay = 0;
293 unsigned int sync_frame_delay_value = GAME_FRAME_DELAY;
302 /* also execute after pending events have been processed before */
305 /* don't use all CPU time when idle; the main loop while playing
306 has its own synchronization and is CPU friendly, too */
308 if (game_status == GAME_MODE_PLAYING)
311 /* refresh window contents from drawing buffer, if needed */
314 if (game_status != GAME_MODE_PLAYING)
315 WaitUntilDelayReached(&sync_frame_delay, sync_frame_delay_value);
317 if (game_status == GAME_MODE_QUIT)
322 void ClearEventQueue()
324 while (PendingEvent())
332 case EVENT_BUTTONRELEASE:
333 button_status = MB_RELEASED;
336 case EVENT_KEYRELEASE:
341 HandleOtherEvents(&event);
347 void ClearPlayerAction()
351 /* simulate key release events for still pressed keys */
352 key_joystick_mapping = 0;
353 for (i = 0; i < MAX_PLAYERS; i++)
354 stored_player[i].action = 0;
357 void SleepWhileUnmapped()
359 boolean window_unmapped = TRUE;
361 KeyboardAutoRepeatOn();
363 while (window_unmapped)
371 case EVENT_BUTTONRELEASE:
372 button_status = MB_RELEASED;
375 case EVENT_KEYRELEASE:
376 key_joystick_mapping = 0;
379 case EVENT_MAPNOTIFY:
380 window_unmapped = FALSE;
383 case EVENT_UNMAPNOTIFY:
384 /* this is only to surely prevent the 'should not happen' case
385 * of recursively looping between 'SleepWhileUnmapped()' and
386 * 'HandleOtherEvents()' which usually calls this funtion.
391 HandleOtherEvents(&event);
396 if (game_status == GAME_MODE_PLAYING)
397 KeyboardAutoRepeatOffUnlessAutoplay();
400 void HandleExposeEvent(ExposeEvent *event)
404 void HandleButtonEvent(ButtonEvent *event)
406 #if DEBUG_EVENTS_BUTTON
407 Error(ERR_DEBUG, "BUTTON EVENT: button %d %s, x/y %d/%d\n",
409 event->type == EVENT_BUTTONPRESS ? "pressed" : "released",
413 motion_status = FALSE;
415 if (event->type == EVENT_BUTTONPRESS)
416 button_status = event->button;
418 button_status = MB_RELEASED;
420 HandleButton(event->x, event->y, button_status, event->button);
423 void HandleMotionEvent(MotionEvent *event)
425 if (button_status == MB_RELEASED && game_status != GAME_MODE_EDITOR)
428 motion_status = TRUE;
430 #if DEBUG_EVENTS_MOTION
431 Error(ERR_DEBUG, "MOTION EVENT: button %d moved, x/y %d/%d\n",
432 button_status, event->x, event->y);
435 HandleButton(event->x, event->y, button_status, button_status);
438 #if defined(TARGET_SDL2)
440 void HandleWindowEvent(WindowEvent *event)
442 #if DEBUG_EVENTS_WINDOW
443 int subtype = event->event;
446 (subtype == SDL_WINDOWEVENT_SHOWN ? "SDL_WINDOWEVENT_SHOWN" :
447 subtype == SDL_WINDOWEVENT_HIDDEN ? "SDL_WINDOWEVENT_HIDDEN" :
448 subtype == SDL_WINDOWEVENT_EXPOSED ? "SDL_WINDOWEVENT_EXPOSED" :
449 subtype == SDL_WINDOWEVENT_MOVED ? "SDL_WINDOWEVENT_MOVED" :
450 subtype == SDL_WINDOWEVENT_SIZE_CHANGED ? "SDL_WINDOWEVENT_SIZE_CHANGED" :
451 subtype == SDL_WINDOWEVENT_RESIZED ? "SDL_WINDOWEVENT_RESIZED" :
452 subtype == SDL_WINDOWEVENT_MINIMIZED ? "SDL_WINDOWEVENT_MINIMIZED" :
453 subtype == SDL_WINDOWEVENT_MAXIMIZED ? "SDL_WINDOWEVENT_MAXIMIZED" :
454 subtype == SDL_WINDOWEVENT_RESTORED ? "SDL_WINDOWEVENT_RESTORED" :
455 subtype == SDL_WINDOWEVENT_ENTER ? "SDL_WINDOWEVENT_ENTER" :
456 subtype == SDL_WINDOWEVENT_LEAVE ? "SDL_WINDOWEVENT_LEAVE" :
457 subtype == SDL_WINDOWEVENT_FOCUS_GAINED ? "SDL_WINDOWEVENT_FOCUS_GAINED" :
458 subtype == SDL_WINDOWEVENT_FOCUS_LOST ? "SDL_WINDOWEVENT_FOCUS_LOST" :
459 subtype == SDL_WINDOWEVENT_CLOSE ? "SDL_WINDOWEVENT_CLOSE" :
462 Error(ERR_DEBUG, "WINDOW EVENT: '%s', %ld, %ld",
463 event_name, event->data1, event->data2);
466 if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED ||
467 event->event == SDL_WINDOWEVENT_RESIZED ||
468 event->event == SDL_WINDOWEVENT_EXPOSED)
471 if (event->event == SDL_WINDOWEVENT_RESIZED && !video.fullscreen_enabled)
473 int new_window_width = event->data1;
474 int new_window_height = event->data2;
476 // if window size has changed after resizing, calculate new scaling factor
477 if (new_window_width != video.window_width ||
478 new_window_height != video.window_height)
480 int new_xpercent = (100 * new_window_width / video.width);
481 int new_ypercent = (100 * new_window_height / video.height);
483 setup.window_scaling_percent = video.window_scaling_percent =
484 MIN(MAX(MIN_WINDOW_SCALING_PERCENT, MIN(new_xpercent, new_ypercent)),
485 MAX_WINDOW_SCALING_PERCENT);
487 video.window_width = new_window_width;
488 video.window_height = new_window_height;
490 if (game_status == GAME_MODE_SETUP)
491 RedrawSetupScreenAfterFullscreenToggle();
498 #define NUM_TOUCH_FINGERS 3
503 SDL_FingerID finger_id;
506 } touch_info[NUM_TOUCH_FINGERS];
508 void HandleFingerEvent(FingerEvent *event)
510 static Key motion_key_x = KSYM_UNDEFINED;
511 static Key motion_key_y = KSYM_UNDEFINED;
512 static Key button_key = KSYM_UNDEFINED;
513 static float motion_x1, motion_y1;
514 static float button_x1, button_y1;
515 static SDL_FingerID motion_id = -1;
516 static SDL_FingerID button_id = -1;
517 int move_trigger_distance_percent = 2; // percent of touchpad width/height
518 int drop_trigger_distance_percent = 5; // percent of touchpad width/height
519 float move_trigger_distance = (float)move_trigger_distance_percent / 100;
520 float drop_trigger_distance = (float)drop_trigger_distance_percent / 100;
521 float event_x = event->x;
522 float event_y = event->y;
524 #if DEBUG_EVENTS_FINGER
525 Error(ERR_DEBUG, "FINGER EVENT: finger was %s, touch ID %lld, finger ID %lld, x/y %f/%f, dx/dy %f/%f, pressure %f",
526 event->type == EVENT_FINGERPRESS ? "pressed" :
527 event->type == EVENT_FINGERRELEASE ? "released" : "moved",
531 event->dx, event->dy,
535 if (game_status != GAME_MODE_PLAYING)
538 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
540 int key_status = (event->type == EVENT_FINGERRELEASE ? KEY_RELEASED :
542 Key key = (event->x < 1.0 / 3.0 ?
543 (event->y < 1.0 / 2.0 ? setup.input[0].key.snap :
544 setup.input[0].key.drop) :
545 event->x > 2.0 / 3.0 ?
546 (event->y < 1.0 / 3.0 ? setup.input[0].key.up :
547 event->y > 2.0 / 3.0 ? setup.input[0].key.down :
548 event->x < 5.0 / 6.0 ? setup.input[0].key.left :
549 setup.input[0].key.right) :
551 char *key_status_name = (key_status == KEY_RELEASED ? "KEY_RELEASED" :
555 Error(ERR_DEBUG, "::: key '%s' was '%s' [fingerId: %lld]",
556 getKeyNameFromKey(key), key_status_name, event->fingerId);
558 // check if we already know this touch event's finger id
559 for (i = 0; i < NUM_TOUCH_FINGERS; i++)
561 if (touch_info[i].touched &&
562 touch_info[i].finger_id == event->fingerId)
564 // Error(ERR_DEBUG, "MARK 1: %d", i);
570 if (i >= NUM_TOUCH_FINGERS)
572 if (key_status == KEY_PRESSED)
574 int oldest_pos = 0, oldest_counter = touch_info[0].counter;
576 // unknown finger id -- get new, empty slot, if available
577 for (i = 0; i < NUM_TOUCH_FINGERS; i++)
579 if (touch_info[i].counter < oldest_counter)
582 oldest_counter = touch_info[i].counter;
584 // Error(ERR_DEBUG, "MARK 2: %d", i);
587 if (!touch_info[i].touched)
589 // Error(ERR_DEBUG, "MARK 3: %d", i);
595 if (i >= NUM_TOUCH_FINGERS)
597 // all slots allocated -- use oldest slot
600 // Error(ERR_DEBUG, "MARK 4: %d", i);
605 // release of previously unknown key (should not happen)
607 if (key != KSYM_UNDEFINED)
609 HandleKey(key, KEY_RELEASED);
611 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [1]",
612 getKeyNameFromKey(key), "KEY_RELEASED", i);
617 if (i < NUM_TOUCH_FINGERS)
619 if (key_status == KEY_PRESSED)
621 if (touch_info[i].key != key)
623 if (touch_info[i].key != KSYM_UNDEFINED)
625 HandleKey(touch_info[i].key, KEY_RELEASED);
627 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [2]",
628 getKeyNameFromKey(touch_info[i].key), "KEY_RELEASED", i);
631 if (key != KSYM_UNDEFINED)
633 HandleKey(key, KEY_PRESSED);
635 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [3]",
636 getKeyNameFromKey(key), "KEY_PRESSED", i);
640 touch_info[i].touched = TRUE;
641 touch_info[i].finger_id = event->fingerId;
642 touch_info[i].counter = Counter();
643 touch_info[i].key = key;
647 if (touch_info[i].key != KSYM_UNDEFINED)
649 HandleKey(touch_info[i].key, KEY_RELEASED);
651 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [4]",
652 getKeyNameFromKey(touch_info[i].key), "KEY_RELEASED", i);
655 touch_info[i].touched = FALSE;
656 touch_info[i].finger_id = 0;
657 touch_info[i].counter = 0;
658 touch_info[i].key = 0;
665 // use touch direction control
667 if (event->type == EVENT_FINGERPRESS)
669 if (event_x > 1.0 / 3.0)
673 motion_id = event->fingerId;
678 motion_key_x = KSYM_UNDEFINED;
679 motion_key_y = KSYM_UNDEFINED;
681 Error(ERR_DEBUG, "---------- MOVE STARTED (WAIT) ----------");
687 button_id = event->fingerId;
692 button_key = setup.input[0].key.snap;
694 HandleKey(button_key, KEY_PRESSED);
696 Error(ERR_DEBUG, "---------- SNAP STARTED ----------");
699 else if (event->type == EVENT_FINGERRELEASE)
701 if (event->fingerId == motion_id)
705 if (motion_key_x != KSYM_UNDEFINED)
706 HandleKey(motion_key_x, KEY_RELEASED);
707 if (motion_key_y != KSYM_UNDEFINED)
708 HandleKey(motion_key_y, KEY_RELEASED);
710 motion_key_x = KSYM_UNDEFINED;
711 motion_key_y = KSYM_UNDEFINED;
713 Error(ERR_DEBUG, "---------- MOVE STOPPED ----------");
715 else if (event->fingerId == button_id)
719 if (button_key != KSYM_UNDEFINED)
720 HandleKey(button_key, KEY_RELEASED);
722 button_key = KSYM_UNDEFINED;
724 Error(ERR_DEBUG, "---------- SNAP STOPPED ----------");
727 else if (event->type == EVENT_FINGERMOTION)
729 if (event->fingerId == motion_id)
731 float distance_x = ABS(event_x - motion_x1);
732 float distance_y = ABS(event_y - motion_y1);
733 Key new_motion_key_x = (event_x < motion_x1 ? setup.input[0].key.left :
734 event_x > motion_x1 ? setup.input[0].key.right :
736 Key new_motion_key_y = (event_y < motion_y1 ? setup.input[0].key.up :
737 event_y > motion_y1 ? setup.input[0].key.down :
740 if (distance_x < move_trigger_distance / 2 ||
741 distance_x < distance_y)
742 new_motion_key_x = KSYM_UNDEFINED;
744 if (distance_y < move_trigger_distance / 2 ||
745 distance_y < distance_x)
746 new_motion_key_y = KSYM_UNDEFINED;
748 if (distance_x > move_trigger_distance ||
749 distance_y > move_trigger_distance)
751 if (new_motion_key_x != motion_key_x)
753 if (motion_key_x != KSYM_UNDEFINED)
754 HandleKey(motion_key_x, KEY_RELEASED);
755 if (new_motion_key_x != KSYM_UNDEFINED)
756 HandleKey(new_motion_key_x, KEY_PRESSED);
759 if (new_motion_key_y != motion_key_y)
761 if (motion_key_y != KSYM_UNDEFINED)
762 HandleKey(motion_key_y, KEY_RELEASED);
763 if (new_motion_key_y != KSYM_UNDEFINED)
764 HandleKey(new_motion_key_y, KEY_PRESSED);
770 motion_key_x = new_motion_key_x;
771 motion_key_y = new_motion_key_y;
773 Error(ERR_DEBUG, "---------- MOVE STARTED (MOVE) ----------");
776 else if (event->fingerId == button_id)
778 float distance_x = ABS(event_x - button_x1);
779 float distance_y = ABS(event_y - button_y1);
781 if (distance_x < drop_trigger_distance / 2 &&
782 distance_y > drop_trigger_distance)
784 if (button_key == setup.input[0].key.snap)
785 HandleKey(button_key, KEY_RELEASED);
790 button_key = setup.input[0].key.drop;
792 HandleKey(button_key, KEY_PRESSED);
794 Error(ERR_DEBUG, "---------- DROP STARTED ----------");
800 static boolean checkTextInputKeyModState()
802 // when playing, only handle raw key events and ignore text input
803 if (game_status == GAME_MODE_PLAYING)
806 return ((GetKeyModState() & KMOD_TextInput) != KMOD_None);
809 void HandleTextEvent(TextEvent *event)
811 char *text = event->text;
812 Key key = getKeyFromKeyName(text);
814 #if DEBUG_EVENTS_TEXT
815 Error(ERR_DEBUG, "TEXT EVENT: text == '%s' [%d byte(s), '%c'/%d], resulting key == %d (%s) [%04x]",
818 text[0], (int)(text[0]),
820 getKeyNameFromKey(key),
824 #if defined(PLATFORM_ANDROID)
825 if (game_status == GAME_MODE_PSEUDO_TYPENAME)
827 HandleTypeName(0, key);
833 // only handle key input with text modifier keys pressed
834 if (checkTextInputKeyModState())
836 HandleKey(key, KEY_PRESSED);
837 HandleKey(key, KEY_RELEASED);
841 void HandlePauseResumeEvent(PauseResumeEvent *event)
843 if (event->type == SDL_APP_WILLENTERBACKGROUND)
847 else if (event->type == SDL_APP_DIDENTERFOREGROUND)
855 void HandleKeyEvent(KeyEvent *event)
857 int key_status = (event->type == EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
858 boolean with_modifiers = (game_status == GAME_MODE_PLAYING ? FALSE : TRUE);
859 Key key = GetEventKey(event, with_modifiers);
860 Key keymod = (with_modifiers ? GetEventKey(event, FALSE) : key);
863 Error(ERR_DEBUG, "KEY EVENT: key was %s, keysym.scancode == %d, keysym.sym == %d, keymod = %d, GetKeyModState() = 0x%04x, resulting key == %d (%s)",
864 event->type == EVENT_KEYPRESS ? "pressed" : "released",
865 event->keysym.scancode,
870 getKeyNameFromKey(key));
873 #if defined(PLATFORM_ANDROID)
874 // always map the "back" button to the "escape" key on Android devices
875 if (key == KSYM_Back)
879 HandleKeyModState(keymod, key_status);
881 #if defined(TARGET_SDL2)
882 // only handle raw key input without text modifier keys pressed
883 if (!checkTextInputKeyModState())
884 HandleKey(key, key_status);
886 HandleKey(key, key_status);
890 void HandleFocusEvent(FocusChangeEvent *event)
892 static int old_joystick_status = -1;
894 if (event->type == EVENT_FOCUSOUT)
896 KeyboardAutoRepeatOn();
897 old_joystick_status = joystick.status;
898 joystick.status = JOYSTICK_NOT_AVAILABLE;
902 else if (event->type == EVENT_FOCUSIN)
904 /* When there are two Rocks'n'Diamonds windows which overlap and
905 the player moves the pointer from one game window to the other,
906 a 'FocusOut' event is generated for the window the pointer is
907 leaving and a 'FocusIn' event is generated for the window the
908 pointer is entering. In some cases, it can happen that the
909 'FocusIn' event is handled by the one game process before the
910 'FocusOut' event by the other game process. In this case the
911 X11 environment would end up with activated keyboard auto repeat,
912 because unfortunately this is a global setting and not (which
913 would be far better) set for each X11 window individually.
914 The effect would be keyboard auto repeat while playing the game
915 (game_status == GAME_MODE_PLAYING), which is not desired.
916 To avoid this special case, we just wait 1/10 second before
917 processing the 'FocusIn' event.
920 if (game_status == GAME_MODE_PLAYING)
923 KeyboardAutoRepeatOffUnlessAutoplay();
926 if (old_joystick_status != -1)
927 joystick.status = old_joystick_status;
931 void HandleClientMessageEvent(ClientMessageEvent *event)
933 if (CheckCloseWindowEvent(event))
937 void HandleWindowManagerEvent(Event *event)
939 #if defined(TARGET_SDL)
940 SDLHandleWindowManagerEvent(event);
944 void HandleButton(int mx, int my, int button, int button_nr)
946 static int old_mx = 0, old_my = 0;
947 boolean button_hold = FALSE;
962 #if defined(PLATFORM_ANDROID)
963 // !!! for now, do not handle gadgets when playing -- maybe fix this !!!
964 if (game_status != GAME_MODE_PLAYING &&
965 HandleGadgets(mx, my, button))
967 /* do not handle this button event anymore */
968 mx = my = -32; /* force mouse event to be outside screen tiles */
971 if (HandleGadgets(mx, my, button))
973 /* do not handle this button event anymore */
974 mx = my = -32; /* force mouse event to be outside screen tiles */
978 if (button_hold && game_status == GAME_MODE_PLAYING && tape.pausing)
981 /* do not use scroll wheel button events for anything other than gadgets */
982 if (IS_WHEEL_BUTTON(button_nr))
987 case GAME_MODE_TITLE:
988 HandleTitleScreen(mx, my, 0, 0, button);
992 HandleMainMenu(mx, my, 0, 0, button);
995 case GAME_MODE_PSEUDO_TYPENAME:
996 HandleTypeName(0, KSYM_Return);
999 case GAME_MODE_LEVELS:
1000 HandleChooseLevelSet(mx, my, 0, 0, button);
1003 case GAME_MODE_LEVELNR:
1004 HandleChooseLevelNr(mx, my, 0, 0, button);
1007 case GAME_MODE_SCORES:
1008 HandleHallOfFame(0, 0, 0, 0, button);
1011 case GAME_MODE_EDITOR:
1012 HandleLevelEditorIdle();
1015 case GAME_MODE_INFO:
1016 HandleInfoScreen(mx, my, 0, 0, button);
1019 case GAME_MODE_SETUP:
1020 HandleSetupScreen(mx, my, 0, 0, button);
1023 case GAME_MODE_PLAYING:
1025 if (button == MB_PRESSED && !motion_status && IN_GFX_FIELD_PLAY(mx, my))
1026 DumpTile(LEVELX((mx - SX) / TILESIZE_VAR),
1027 LEVELY((my - SY) / TILESIZE_VAR));
1028 // DumpTile(LEVELX((mx - SX) / TILEX), LEVELY((my - SY) / TILEY));
1037 static boolean is_string_suffix(char *string, char *suffix)
1039 int string_len = strlen(string);
1040 int suffix_len = strlen(suffix);
1042 if (suffix_len > string_len)
1045 return (strEqual(&string[string_len - suffix_len], suffix));
1048 #define MAX_CHEAT_INPUT_LEN 32
1050 static void HandleKeysSpecial(Key key)
1052 static char cheat_input[2 * MAX_CHEAT_INPUT_LEN + 1] = "";
1053 char letter = getCharFromKey(key);
1054 int cheat_input_len = strlen(cheat_input);
1060 if (cheat_input_len >= 2 * MAX_CHEAT_INPUT_LEN)
1062 for (i = 0; i < MAX_CHEAT_INPUT_LEN + 1; i++)
1063 cheat_input[i] = cheat_input[MAX_CHEAT_INPUT_LEN + i];
1065 cheat_input_len = MAX_CHEAT_INPUT_LEN;
1068 cheat_input[cheat_input_len++] = letter;
1069 cheat_input[cheat_input_len] = '\0';
1071 #if DEBUG_EVENTS_KEY
1072 Error(ERR_DEBUG, "SPECIAL KEY '%s' [%d]\n", cheat_input, cheat_input_len);
1075 if (game_status == GAME_MODE_MAIN)
1077 if (is_string_suffix(cheat_input, ":insert-solution-tape") ||
1078 is_string_suffix(cheat_input, ":ist"))
1080 InsertSolutionTape();
1082 else if (is_string_suffix(cheat_input, ":reload-graphics") ||
1083 is_string_suffix(cheat_input, ":rg"))
1085 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS);
1088 else if (is_string_suffix(cheat_input, ":reload-sounds") ||
1089 is_string_suffix(cheat_input, ":rs"))
1091 ReloadCustomArtwork(1 << ARTWORK_TYPE_SOUNDS);
1094 else if (is_string_suffix(cheat_input, ":reload-music") ||
1095 is_string_suffix(cheat_input, ":rm"))
1097 ReloadCustomArtwork(1 << ARTWORK_TYPE_MUSIC);
1100 else if (is_string_suffix(cheat_input, ":reload-artwork") ||
1101 is_string_suffix(cheat_input, ":ra"))
1103 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS |
1104 1 << ARTWORK_TYPE_SOUNDS |
1105 1 << ARTWORK_TYPE_MUSIC);
1108 else if (is_string_suffix(cheat_input, ":dump-level") ||
1109 is_string_suffix(cheat_input, ":dl"))
1113 else if (is_string_suffix(cheat_input, ":dump-tape") ||
1114 is_string_suffix(cheat_input, ":dt"))
1118 else if (is_string_suffix(cheat_input, ":fix-tape") ||
1119 is_string_suffix(cheat_input, ":ft"))
1121 /* fix single-player tapes that contain player input for more than one
1122 player (due to a bug in 3.3.1.2 and earlier versions), which results
1123 in playing levels with more than one player in multi-player mode,
1124 even though the tape was originally recorded in single-player mode */
1126 /* remove player input actions for all players but the first one */
1127 for (i = 1; i < MAX_PLAYERS; i++)
1128 tape.player_participates[i] = FALSE;
1130 tape.changed = TRUE;
1132 else if (is_string_suffix(cheat_input, ":save-native-level") ||
1133 is_string_suffix(cheat_input, ":snl"))
1135 SaveNativeLevel(&level);
1138 else if (game_status == GAME_MODE_PLAYING)
1141 if (is_string_suffix(cheat_input, ".q"))
1142 DEBUG_SetMaximumDynamite();
1145 else if (game_status == GAME_MODE_EDITOR)
1147 if (is_string_suffix(cheat_input, ":dump-brush") ||
1148 is_string_suffix(cheat_input, ":DB"))
1152 else if (is_string_suffix(cheat_input, ":DDB"))
1159 void HandleKey(Key key, int key_status)
1161 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
1162 static boolean ignore_repeated_key = FALSE;
1163 static struct SetupKeyboardInfo ski;
1164 static struct SetupShortcutInfo ssi;
1173 { &ski.left, &ssi.snap_left, DEFAULT_KEY_LEFT, JOY_LEFT },
1174 { &ski.right, &ssi.snap_right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
1175 { &ski.up, &ssi.snap_up, DEFAULT_KEY_UP, JOY_UP },
1176 { &ski.down, &ssi.snap_down, DEFAULT_KEY_DOWN, JOY_DOWN },
1177 { &ski.snap, NULL, DEFAULT_KEY_SNAP, JOY_BUTTON_SNAP },
1178 { &ski.drop, NULL, DEFAULT_KEY_DROP, JOY_BUTTON_DROP }
1183 if (game_status == GAME_MODE_PLAYING)
1185 /* only needed for single-step tape recording mode */
1186 static boolean clear_snap_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1187 static boolean clear_drop_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1188 static boolean element_snapped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1189 static boolean element_dropped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1192 for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
1194 byte key_action = 0;
1196 if (setup.input[pnr].use_joystick)
1199 ski = setup.input[pnr].key;
1201 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1202 if (key == *key_info[i].key_custom)
1203 key_action |= key_info[i].action;
1205 /* use combined snap+direction keys for the first player only */
1208 ssi = setup.shortcut;
1210 for (i = 0; i < NUM_DIRECTIONS; i++)
1211 if (key == *key_info[i].key_snap)
1212 key_action |= key_info[i].action | JOY_BUTTON_SNAP;
1215 /* clear delayed snap and drop actions in single step mode (see below) */
1216 if (tape.single_step)
1218 if (clear_snap_button[pnr])
1220 stored_player[pnr].action &= ~KEY_BUTTON_SNAP;
1221 clear_snap_button[pnr] = FALSE;
1224 if (clear_drop_button[pnr])
1226 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1227 clear_drop_button[pnr] = FALSE;
1231 if (key_status == KEY_PRESSED)
1232 stored_player[pnr].action |= key_action;
1234 stored_player[pnr].action &= ~key_action;
1236 if (tape.single_step && tape.recording && tape.pausing)
1238 if (key_status == KEY_PRESSED && key_action & KEY_MOTION)
1240 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1242 /* if snap key already pressed, don't snap when releasing (below) */
1243 if (stored_player[pnr].action & KEY_BUTTON_SNAP)
1244 element_snapped[pnr] = TRUE;
1246 /* if drop key already pressed, don't drop when releasing (below) */
1247 if (stored_player[pnr].action & KEY_BUTTON_DROP)
1248 element_dropped[pnr] = TRUE;
1250 else if (key_status == KEY_PRESSED && key_action & KEY_BUTTON_DROP)
1252 if (level.game_engine_type == GAME_ENGINE_TYPE_EM ||
1253 level.game_engine_type == GAME_ENGINE_TYPE_SP)
1256 if (level.game_engine_type == GAME_ENGINE_TYPE_SP &&
1257 getRedDiskReleaseFlag_SP() == 0)
1258 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1260 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1263 else if (key_status == KEY_RELEASED && key_action & KEY_BUTTON)
1265 if (key_action & KEY_BUTTON_SNAP)
1267 /* if snap key was released without moving (see above), snap now */
1268 if (!element_snapped[pnr])
1270 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1272 stored_player[pnr].action |= KEY_BUTTON_SNAP;
1274 /* clear delayed snap button on next event */
1275 clear_snap_button[pnr] = TRUE;
1278 element_snapped[pnr] = FALSE;
1281 if (key_action & KEY_BUTTON_DROP &&
1282 level.game_engine_type == GAME_ENGINE_TYPE_RND)
1284 /* if drop key was released without moving (see above), drop now */
1285 if (!element_dropped[pnr])
1287 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1289 if (level.game_engine_type != GAME_ENGINE_TYPE_SP ||
1290 getRedDiskReleaseFlag_SP() != 0)
1291 stored_player[pnr].action |= KEY_BUTTON_DROP;
1293 /* clear delayed drop button on next event */
1294 clear_drop_button[pnr] = TRUE;
1297 element_dropped[pnr] = FALSE;
1301 else if (tape.recording && tape.pausing)
1303 /* prevent key release events from un-pausing a paused game */
1304 if (key_status == KEY_PRESSED && key_action & KEY_ACTION)
1305 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1311 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1312 if (key == key_info[i].key_default)
1313 joy |= key_info[i].action;
1318 if (key_status == KEY_PRESSED)
1319 key_joystick_mapping |= joy;
1321 key_joystick_mapping &= ~joy;
1326 if (game_status != GAME_MODE_PLAYING)
1327 key_joystick_mapping = 0;
1329 if (key_status == KEY_RELEASED)
1331 // reset flag to ignore repeated "key pressed" events after key release
1332 ignore_repeated_key = FALSE;
1337 if ((key == KSYM_F11 ||
1338 ((key == KSYM_Return ||
1339 key == KSYM_KP_Enter) && (GetKeyModState() & KMOD_Alt))) &&
1340 video.fullscreen_available &&
1341 !ignore_repeated_key)
1343 setup.fullscreen = !setup.fullscreen;
1345 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1347 if (game_status == GAME_MODE_SETUP)
1348 RedrawSetupScreenAfterFullscreenToggle();
1350 // set flag to ignore repeated "key pressed" events
1351 ignore_repeated_key = TRUE;
1356 if ((key == KSYM_minus ||
1359 ((GetKeyModState() & KMOD_Control) ||
1360 (GetKeyModState() & KMOD_Alt)) &&
1361 video.window_scaling_available &&
1362 !video.fullscreen_enabled)
1365 setup.window_scaling_percent = STD_WINDOW_SCALING_PERCENT;
1367 setup.window_scaling_percent +=
1368 (key == KSYM_minus ? -1 : +1) * STEP_WINDOW_SCALING_PERCENT;
1370 if (setup.window_scaling_percent < MIN_WINDOW_SCALING_PERCENT)
1371 setup.window_scaling_percent = MIN_WINDOW_SCALING_PERCENT;
1372 else if (setup.window_scaling_percent > MAX_WINDOW_SCALING_PERCENT)
1373 setup.window_scaling_percent = MAX_WINDOW_SCALING_PERCENT;
1375 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1377 if (game_status == GAME_MODE_SETUP)
1378 RedrawSetupScreenAfterFullscreenToggle();
1383 if (game_status == GAME_MODE_PLAYING && AllPlayersGone &&
1384 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
1391 if (game_status == GAME_MODE_MAIN &&
1392 (key == setup.shortcut.toggle_pause || key == KSYM_space))
1394 StartGameActions(options.network, setup.autorecord, level.random_seed);
1399 if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING)
1401 if (key == setup.shortcut.save_game)
1403 else if (key == setup.shortcut.load_game)
1405 else if (key == setup.shortcut.toggle_pause)
1406 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1408 HandleTapeButtonKeys(key);
1409 HandleSoundButtonKeys(key);
1412 if (game_status == GAME_MODE_PLAYING && !network_playing)
1414 int centered_player_nr_next = -999;
1416 if (key == setup.shortcut.focus_player_all)
1417 centered_player_nr_next = -1;
1419 for (i = 0; i < MAX_PLAYERS; i++)
1420 if (key == setup.shortcut.focus_player[i])
1421 centered_player_nr_next = i;
1423 if (centered_player_nr_next != -999)
1425 game.centered_player_nr_next = centered_player_nr_next;
1426 game.set_centered_player = TRUE;
1430 tape.centered_player_nr_next = game.centered_player_nr_next;
1431 tape.set_centered_player = TRUE;
1436 HandleKeysSpecial(key);
1438 if (HandleGadgetsKeyInput(key))
1440 if (key != KSYM_Escape) /* always allow ESC key to be handled */
1441 key = KSYM_UNDEFINED;
1444 switch (game_status)
1446 case GAME_MODE_PSEUDO_TYPENAME:
1447 HandleTypeName(0, key);
1450 case GAME_MODE_TITLE:
1451 case GAME_MODE_MAIN:
1452 case GAME_MODE_LEVELS:
1453 case GAME_MODE_LEVELNR:
1454 case GAME_MODE_SETUP:
1455 case GAME_MODE_INFO:
1456 case GAME_MODE_SCORES:
1461 if (game_status == GAME_MODE_TITLE)
1462 HandleTitleScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1463 else if (game_status == GAME_MODE_MAIN)
1464 HandleMainMenu(0, 0, 0, 0, MB_MENU_CHOICE);
1465 else if (game_status == GAME_MODE_LEVELS)
1466 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_CHOICE);
1467 else if (game_status == GAME_MODE_LEVELNR)
1468 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_CHOICE);
1469 else if (game_status == GAME_MODE_SETUP)
1470 HandleSetupScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1471 else if (game_status == GAME_MODE_INFO)
1472 HandleInfoScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1473 else if (game_status == GAME_MODE_SCORES)
1474 HandleHallOfFame(0, 0, 0, 0, MB_MENU_CHOICE);
1478 if (game_status != GAME_MODE_MAIN)
1479 FadeSkipNextFadeIn();
1481 if (game_status == GAME_MODE_TITLE)
1482 HandleTitleScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1483 else if (game_status == GAME_MODE_LEVELS)
1484 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_LEAVE);
1485 else if (game_status == GAME_MODE_LEVELNR)
1486 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_LEAVE);
1487 else if (game_status == GAME_MODE_SETUP)
1488 HandleSetupScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1489 else if (game_status == GAME_MODE_INFO)
1490 HandleInfoScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1491 else if (game_status == GAME_MODE_SCORES)
1492 HandleHallOfFame(0, 0, 0, 0, MB_MENU_LEAVE);
1496 if (game_status == GAME_MODE_LEVELS)
1497 HandleChooseLevelSet(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1498 else if (game_status == GAME_MODE_LEVELNR)
1499 HandleChooseLevelNr(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1500 else if (game_status == GAME_MODE_SETUP)
1501 HandleSetupScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1502 else if (game_status == GAME_MODE_INFO)
1503 HandleInfoScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1504 else if (game_status == GAME_MODE_SCORES)
1505 HandleHallOfFame(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1508 case KSYM_Page_Down:
1509 if (game_status == GAME_MODE_LEVELS)
1510 HandleChooseLevelSet(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1511 else if (game_status == GAME_MODE_LEVELNR)
1512 HandleChooseLevelNr(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1513 else if (game_status == GAME_MODE_SETUP)
1514 HandleSetupScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1515 else if (game_status == GAME_MODE_INFO)
1516 HandleInfoScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1517 else if (game_status == GAME_MODE_SCORES)
1518 HandleHallOfFame(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1523 GameFrameDelay = (GameFrameDelay == 500 ? GAME_FRAME_DELAY : 500);
1527 setup.sp_show_border_elements = !setup.sp_show_border_elements;
1528 printf("Supaplex border elements %s\n",
1529 setup.sp_show_border_elements ? "enabled" : "disabled");
1538 case GAME_MODE_EDITOR:
1539 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
1540 HandleLevelEditorKeyInput(key);
1543 case GAME_MODE_PLAYING:
1548 RequestQuitGame(setup.ask_on_escape);
1555 if (GameFrameDelay == 500)
1556 GameFrameDelay = GAME_FRAME_DELAY;
1558 GameFrameDelay = 500;
1561 GameFrameDelay = (key - KSYM_0) * 10;
1562 printf("Game speed == %d%% (%d ms delay between two frames)\n",
1563 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
1569 options.debug = FALSE;
1570 printf("debug mode disabled\n");
1574 options.debug = TRUE;
1575 printf("debug mode enabled\n");
1580 printf("::: currently using game engine version %d\n",
1581 game.engine_version);
1592 if (key == KSYM_Escape)
1594 SetGameStatus(GAME_MODE_MAIN);
1603 void HandleNoEvent()
1605 // if (button_status && game_status != GAME_MODE_PLAYING)
1606 if (button_status && (game_status != GAME_MODE_PLAYING || tape.pausing))
1608 HandleButton(0, 0, -button_status, button_status);
1615 #if defined(NETWORK_AVALIABLE)
1616 if (options.network)
1620 switch (game_status)
1622 case GAME_MODE_MAIN:
1623 DrawPreviewLevelAnimation();
1627 case GAME_MODE_LEVELS:
1628 case GAME_MODE_LEVELNR:
1629 case GAME_MODE_SETUP:
1630 case GAME_MODE_INFO:
1631 case GAME_MODE_SCORES:
1635 case GAME_MODE_EDITOR:
1636 HandleLevelEditorIdle();
1644 static int HandleJoystickForAllPlayers()
1649 for (i = 0; i < MAX_PLAYERS; i++)
1651 byte joy_action = 0;
1654 if (!setup.input[i].use_joystick)
1658 joy_action = Joystick(i);
1659 result |= joy_action;
1661 if (!setup.input[i].use_joystick)
1664 stored_player[i].action = joy_action;
1670 void HandleJoystick()
1672 int joystick = HandleJoystickForAllPlayers();
1673 int keyboard = key_joystick_mapping;
1674 int joy = (joystick | keyboard);
1675 int left = joy & JOY_LEFT;
1676 int right = joy & JOY_RIGHT;
1677 int up = joy & JOY_UP;
1678 int down = joy & JOY_DOWN;
1679 int button = joy & JOY_BUTTON;
1680 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
1681 int dx = (left ? -1 : right ? 1 : 0);
1682 int dy = (up ? -1 : down ? 1 : 0);
1684 switch (game_status)
1686 case GAME_MODE_TITLE:
1687 case GAME_MODE_MAIN:
1688 case GAME_MODE_LEVELS:
1689 case GAME_MODE_LEVELNR:
1690 case GAME_MODE_SETUP:
1691 case GAME_MODE_INFO:
1693 static unsigned int joystickmove_delay = 0;
1695 if (joystick && !button &&
1696 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
1697 newbutton = dx = dy = 0;
1699 if (game_status == GAME_MODE_TITLE)
1700 HandleTitleScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1701 else if (game_status == GAME_MODE_MAIN)
1702 HandleMainMenu(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1703 else if (game_status == GAME_MODE_LEVELS)
1704 HandleChooseLevelSet(0,0,dx,dy,newbutton?MB_MENU_CHOICE : MB_MENU_MARK);
1705 else if (game_status == GAME_MODE_LEVELNR)
1706 HandleChooseLevelNr(0,0,dx,dy,newbutton? MB_MENU_CHOICE : MB_MENU_MARK);
1707 else if (game_status == GAME_MODE_SETUP)
1708 HandleSetupScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1709 else if (game_status == GAME_MODE_INFO)
1710 HandleInfoScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1714 case GAME_MODE_SCORES:
1715 HandleHallOfFame(0, 0, dx, dy, !newbutton);
1718 case GAME_MODE_PLAYING:
1719 if (tape.playing || keyboard)
1720 newbutton = ((joy & JOY_BUTTON) != 0);
1722 if (newbutton && AllPlayersGone)