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 // (extreme window scaling allowed, but cannot be saved permanently)
481 video.window_scaling_percent = MIN(new_xpercent, new_ypercent);
482 setup.window_scaling_percent =
483 MIN(MAX(MIN_WINDOW_SCALING_PERCENT, video.window_scaling_percent),
484 MAX_WINDOW_SCALING_PERCENT);
486 video.window_width = new_window_width;
487 video.window_height = new_window_height;
489 if (game_status == GAME_MODE_SETUP)
490 RedrawSetupScreenAfterFullscreenToggle();
497 #define NUM_TOUCH_FINGERS 3
502 SDL_FingerID finger_id;
505 } touch_info[NUM_TOUCH_FINGERS];
507 void HandleFingerEvent(FingerEvent *event)
509 static Key motion_key_x = KSYM_UNDEFINED;
510 static Key motion_key_y = KSYM_UNDEFINED;
511 static Key button_key = KSYM_UNDEFINED;
512 static float motion_x1, motion_y1;
513 static float button_x1, button_y1;
514 static SDL_FingerID motion_id = -1;
515 static SDL_FingerID button_id = -1;
516 int move_trigger_distance_percent = 2; // percent of touchpad width/height
517 int drop_trigger_distance_percent = 5; // percent of touchpad width/height
518 float move_trigger_distance = (float)move_trigger_distance_percent / 100;
519 float drop_trigger_distance = (float)drop_trigger_distance_percent / 100;
520 float event_x = event->x;
521 float event_y = event->y;
523 #if DEBUG_EVENTS_FINGER
524 Error(ERR_DEBUG, "FINGER EVENT: finger was %s, touch ID %lld, finger ID %lld, x/y %f/%f, dx/dy %f/%f, pressure %f",
525 event->type == EVENT_FINGERPRESS ? "pressed" :
526 event->type == EVENT_FINGERRELEASE ? "released" : "moved",
530 event->dx, event->dy,
534 if (game_status != GAME_MODE_PLAYING)
537 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
539 int key_status = (event->type == EVENT_FINGERRELEASE ? KEY_RELEASED :
541 Key key = (event->x < 1.0 / 3.0 ?
542 (event->y < 1.0 / 2.0 ? setup.input[0].key.snap :
543 setup.input[0].key.drop) :
544 event->x > 2.0 / 3.0 ?
545 (event->y < 1.0 / 3.0 ? setup.input[0].key.up :
546 event->y > 2.0 / 3.0 ? setup.input[0].key.down :
547 event->x < 5.0 / 6.0 ? setup.input[0].key.left :
548 setup.input[0].key.right) :
550 char *key_status_name = (key_status == KEY_RELEASED ? "KEY_RELEASED" :
554 Error(ERR_DEBUG, "::: key '%s' was '%s' [fingerId: %lld]",
555 getKeyNameFromKey(key), key_status_name, event->fingerId);
557 // check if we already know this touch event's finger id
558 for (i = 0; i < NUM_TOUCH_FINGERS; i++)
560 if (touch_info[i].touched &&
561 touch_info[i].finger_id == event->fingerId)
563 // Error(ERR_DEBUG, "MARK 1: %d", i);
569 if (i >= NUM_TOUCH_FINGERS)
571 if (key_status == KEY_PRESSED)
573 int oldest_pos = 0, oldest_counter = touch_info[0].counter;
575 // unknown finger id -- get new, empty slot, if available
576 for (i = 0; i < NUM_TOUCH_FINGERS; i++)
578 if (touch_info[i].counter < oldest_counter)
581 oldest_counter = touch_info[i].counter;
583 // Error(ERR_DEBUG, "MARK 2: %d", i);
586 if (!touch_info[i].touched)
588 // Error(ERR_DEBUG, "MARK 3: %d", i);
594 if (i >= NUM_TOUCH_FINGERS)
596 // all slots allocated -- use oldest slot
599 // Error(ERR_DEBUG, "MARK 4: %d", i);
604 // release of previously unknown key (should not happen)
606 if (key != KSYM_UNDEFINED)
608 HandleKey(key, KEY_RELEASED);
610 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [1]",
611 getKeyNameFromKey(key), "KEY_RELEASED", i);
616 if (i < NUM_TOUCH_FINGERS)
618 if (key_status == KEY_PRESSED)
620 if (touch_info[i].key != key)
622 if (touch_info[i].key != KSYM_UNDEFINED)
624 HandleKey(touch_info[i].key, KEY_RELEASED);
626 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [2]",
627 getKeyNameFromKey(touch_info[i].key), "KEY_RELEASED", i);
630 if (key != KSYM_UNDEFINED)
632 HandleKey(key, KEY_PRESSED);
634 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [3]",
635 getKeyNameFromKey(key), "KEY_PRESSED", i);
639 touch_info[i].touched = TRUE;
640 touch_info[i].finger_id = event->fingerId;
641 touch_info[i].counter = Counter();
642 touch_info[i].key = key;
646 if (touch_info[i].key != KSYM_UNDEFINED)
648 HandleKey(touch_info[i].key, KEY_RELEASED);
650 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [4]",
651 getKeyNameFromKey(touch_info[i].key), "KEY_RELEASED", i);
654 touch_info[i].touched = FALSE;
655 touch_info[i].finger_id = 0;
656 touch_info[i].counter = 0;
657 touch_info[i].key = 0;
664 // use touch direction control
666 if (event->type == EVENT_FINGERPRESS)
668 if (event_x > 1.0 / 3.0)
672 motion_id = event->fingerId;
677 motion_key_x = KSYM_UNDEFINED;
678 motion_key_y = KSYM_UNDEFINED;
680 Error(ERR_DEBUG, "---------- MOVE STARTED (WAIT) ----------");
686 button_id = event->fingerId;
691 button_key = setup.input[0].key.snap;
693 HandleKey(button_key, KEY_PRESSED);
695 Error(ERR_DEBUG, "---------- SNAP STARTED ----------");
698 else if (event->type == EVENT_FINGERRELEASE)
700 if (event->fingerId == motion_id)
704 if (motion_key_x != KSYM_UNDEFINED)
705 HandleKey(motion_key_x, KEY_RELEASED);
706 if (motion_key_y != KSYM_UNDEFINED)
707 HandleKey(motion_key_y, KEY_RELEASED);
709 motion_key_x = KSYM_UNDEFINED;
710 motion_key_y = KSYM_UNDEFINED;
712 Error(ERR_DEBUG, "---------- MOVE STOPPED ----------");
714 else if (event->fingerId == button_id)
718 if (button_key != KSYM_UNDEFINED)
719 HandleKey(button_key, KEY_RELEASED);
721 button_key = KSYM_UNDEFINED;
723 Error(ERR_DEBUG, "---------- SNAP STOPPED ----------");
726 else if (event->type == EVENT_FINGERMOTION)
728 if (event->fingerId == motion_id)
730 float distance_x = ABS(event_x - motion_x1);
731 float distance_y = ABS(event_y - motion_y1);
732 Key new_motion_key_x = (event_x < motion_x1 ? setup.input[0].key.left :
733 event_x > motion_x1 ? setup.input[0].key.right :
735 Key new_motion_key_y = (event_y < motion_y1 ? setup.input[0].key.up :
736 event_y > motion_y1 ? setup.input[0].key.down :
739 if (distance_x < move_trigger_distance / 2 ||
740 distance_x < distance_y)
741 new_motion_key_x = KSYM_UNDEFINED;
743 if (distance_y < move_trigger_distance / 2 ||
744 distance_y < distance_x)
745 new_motion_key_y = KSYM_UNDEFINED;
747 if (distance_x > move_trigger_distance ||
748 distance_y > move_trigger_distance)
750 if (new_motion_key_x != motion_key_x)
752 if (motion_key_x != KSYM_UNDEFINED)
753 HandleKey(motion_key_x, KEY_RELEASED);
754 if (new_motion_key_x != KSYM_UNDEFINED)
755 HandleKey(new_motion_key_x, KEY_PRESSED);
758 if (new_motion_key_y != motion_key_y)
760 if (motion_key_y != KSYM_UNDEFINED)
761 HandleKey(motion_key_y, KEY_RELEASED);
762 if (new_motion_key_y != KSYM_UNDEFINED)
763 HandleKey(new_motion_key_y, KEY_PRESSED);
769 motion_key_x = new_motion_key_x;
770 motion_key_y = new_motion_key_y;
772 Error(ERR_DEBUG, "---------- MOVE STARTED (MOVE) ----------");
775 else if (event->fingerId == button_id)
777 float distance_x = ABS(event_x - button_x1);
778 float distance_y = ABS(event_y - button_y1);
780 if (distance_x < drop_trigger_distance / 2 &&
781 distance_y > drop_trigger_distance)
783 if (button_key == setup.input[0].key.snap)
784 HandleKey(button_key, KEY_RELEASED);
789 button_key = setup.input[0].key.drop;
791 HandleKey(button_key, KEY_PRESSED);
793 Error(ERR_DEBUG, "---------- DROP STARTED ----------");
799 static boolean checkTextInputKeyModState()
801 // when playing, only handle raw key events and ignore text input
802 if (game_status == GAME_MODE_PLAYING)
805 return ((GetKeyModState() & KMOD_TextInput) != KMOD_None);
808 void HandleTextEvent(TextEvent *event)
810 char *text = event->text;
811 Key key = getKeyFromKeyName(text);
813 #if DEBUG_EVENTS_TEXT
814 Error(ERR_DEBUG, "TEXT EVENT: text == '%s' [%d byte(s), '%c'/%d], resulting key == %d (%s) [%04x]",
817 text[0], (int)(text[0]),
819 getKeyNameFromKey(key),
823 #if defined(PLATFORM_ANDROID)
824 if (game_status == GAME_MODE_PSEUDO_TYPENAME)
826 HandleTypeName(0, key);
832 // only handle key input with text modifier keys pressed
833 if (checkTextInputKeyModState())
835 HandleKey(key, KEY_PRESSED);
836 HandleKey(key, KEY_RELEASED);
840 void HandlePauseResumeEvent(PauseResumeEvent *event)
842 if (event->type == SDL_APP_WILLENTERBACKGROUND)
846 else if (event->type == SDL_APP_DIDENTERFOREGROUND)
854 void HandleKeyEvent(KeyEvent *event)
856 int key_status = (event->type == EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
857 boolean with_modifiers = (game_status == GAME_MODE_PLAYING ? FALSE : TRUE);
858 Key key = GetEventKey(event, with_modifiers);
859 Key keymod = (with_modifiers ? GetEventKey(event, FALSE) : key);
862 Error(ERR_DEBUG, "KEY EVENT: key was %s, keysym.scancode == %d, keysym.sym == %d, keymod = %d, GetKeyModState() = 0x%04x, resulting key == %d (%s)",
863 event->type == EVENT_KEYPRESS ? "pressed" : "released",
864 event->keysym.scancode,
869 getKeyNameFromKey(key));
872 #if defined(PLATFORM_ANDROID)
873 // always map the "back" button to the "escape" key on Android devices
874 if (key == KSYM_Back)
878 HandleKeyModState(keymod, key_status);
880 #if defined(TARGET_SDL2)
881 // only handle raw key input without text modifier keys pressed
882 if (!checkTextInputKeyModState())
883 HandleKey(key, key_status);
885 HandleKey(key, key_status);
889 void HandleFocusEvent(FocusChangeEvent *event)
891 static int old_joystick_status = -1;
893 if (event->type == EVENT_FOCUSOUT)
895 KeyboardAutoRepeatOn();
896 old_joystick_status = joystick.status;
897 joystick.status = JOYSTICK_NOT_AVAILABLE;
901 else if (event->type == EVENT_FOCUSIN)
903 /* When there are two Rocks'n'Diamonds windows which overlap and
904 the player moves the pointer from one game window to the other,
905 a 'FocusOut' event is generated for the window the pointer is
906 leaving and a 'FocusIn' event is generated for the window the
907 pointer is entering. In some cases, it can happen that the
908 'FocusIn' event is handled by the one game process before the
909 'FocusOut' event by the other game process. In this case the
910 X11 environment would end up with activated keyboard auto repeat,
911 because unfortunately this is a global setting and not (which
912 would be far better) set for each X11 window individually.
913 The effect would be keyboard auto repeat while playing the game
914 (game_status == GAME_MODE_PLAYING), which is not desired.
915 To avoid this special case, we just wait 1/10 second before
916 processing the 'FocusIn' event.
919 if (game_status == GAME_MODE_PLAYING)
922 KeyboardAutoRepeatOffUnlessAutoplay();
925 if (old_joystick_status != -1)
926 joystick.status = old_joystick_status;
930 void HandleClientMessageEvent(ClientMessageEvent *event)
932 if (CheckCloseWindowEvent(event))
936 void HandleWindowManagerEvent(Event *event)
938 #if defined(TARGET_SDL)
939 SDLHandleWindowManagerEvent(event);
943 void HandleButton(int mx, int my, int button, int button_nr)
945 static int old_mx = 0, old_my = 0;
946 boolean button_hold = FALSE;
961 #if defined(PLATFORM_ANDROID)
962 // !!! for now, do not handle gadgets when playing -- maybe fix this !!!
963 if (game_status != GAME_MODE_PLAYING &&
964 HandleGadgets(mx, my, button))
966 /* do not handle this button event anymore */
967 mx = my = -32; /* force mouse event to be outside screen tiles */
970 if (HandleGadgets(mx, my, button))
972 /* do not handle this button event anymore */
973 mx = my = -32; /* force mouse event to be outside screen tiles */
977 if (button_hold && game_status == GAME_MODE_PLAYING && tape.pausing)
980 /* do not use scroll wheel button events for anything other than gadgets */
981 if (IS_WHEEL_BUTTON(button_nr))
986 case GAME_MODE_TITLE:
987 HandleTitleScreen(mx, my, 0, 0, button);
991 HandleMainMenu(mx, my, 0, 0, button);
994 case GAME_MODE_PSEUDO_TYPENAME:
995 HandleTypeName(0, KSYM_Return);
998 case GAME_MODE_LEVELS:
999 HandleChooseLevelSet(mx, my, 0, 0, button);
1002 case GAME_MODE_LEVELNR:
1003 HandleChooseLevelNr(mx, my, 0, 0, button);
1006 case GAME_MODE_SCORES:
1007 HandleHallOfFame(0, 0, 0, 0, button);
1010 case GAME_MODE_EDITOR:
1011 HandleLevelEditorIdle();
1014 case GAME_MODE_INFO:
1015 HandleInfoScreen(mx, my, 0, 0, button);
1018 case GAME_MODE_SETUP:
1019 HandleSetupScreen(mx, my, 0, 0, button);
1022 case GAME_MODE_PLAYING:
1024 if (button == MB_PRESSED && !motion_status && IN_GFX_FIELD_PLAY(mx, my))
1025 DumpTile(LEVELX((mx - SX) / TILESIZE_VAR),
1026 LEVELY((my - SY) / TILESIZE_VAR));
1027 // DumpTile(LEVELX((mx - SX) / TILEX), LEVELY((my - SY) / TILEY));
1036 static boolean is_string_suffix(char *string, char *suffix)
1038 int string_len = strlen(string);
1039 int suffix_len = strlen(suffix);
1041 if (suffix_len > string_len)
1044 return (strEqual(&string[string_len - suffix_len], suffix));
1047 #define MAX_CHEAT_INPUT_LEN 32
1049 static void HandleKeysSpecial(Key key)
1051 static char cheat_input[2 * MAX_CHEAT_INPUT_LEN + 1] = "";
1052 char letter = getCharFromKey(key);
1053 int cheat_input_len = strlen(cheat_input);
1059 if (cheat_input_len >= 2 * MAX_CHEAT_INPUT_LEN)
1061 for (i = 0; i < MAX_CHEAT_INPUT_LEN + 1; i++)
1062 cheat_input[i] = cheat_input[MAX_CHEAT_INPUT_LEN + i];
1064 cheat_input_len = MAX_CHEAT_INPUT_LEN;
1067 cheat_input[cheat_input_len++] = letter;
1068 cheat_input[cheat_input_len] = '\0';
1070 #if DEBUG_EVENTS_KEY
1071 Error(ERR_DEBUG, "SPECIAL KEY '%s' [%d]\n", cheat_input, cheat_input_len);
1074 if (game_status == GAME_MODE_MAIN)
1076 if (is_string_suffix(cheat_input, ":insert-solution-tape") ||
1077 is_string_suffix(cheat_input, ":ist"))
1079 InsertSolutionTape();
1081 else if (is_string_suffix(cheat_input, ":reload-graphics") ||
1082 is_string_suffix(cheat_input, ":rg"))
1084 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS);
1087 else if (is_string_suffix(cheat_input, ":reload-sounds") ||
1088 is_string_suffix(cheat_input, ":rs"))
1090 ReloadCustomArtwork(1 << ARTWORK_TYPE_SOUNDS);
1093 else if (is_string_suffix(cheat_input, ":reload-music") ||
1094 is_string_suffix(cheat_input, ":rm"))
1096 ReloadCustomArtwork(1 << ARTWORK_TYPE_MUSIC);
1099 else if (is_string_suffix(cheat_input, ":reload-artwork") ||
1100 is_string_suffix(cheat_input, ":ra"))
1102 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS |
1103 1 << ARTWORK_TYPE_SOUNDS |
1104 1 << ARTWORK_TYPE_MUSIC);
1107 else if (is_string_suffix(cheat_input, ":dump-level") ||
1108 is_string_suffix(cheat_input, ":dl"))
1112 else if (is_string_suffix(cheat_input, ":dump-tape") ||
1113 is_string_suffix(cheat_input, ":dt"))
1117 else if (is_string_suffix(cheat_input, ":fix-tape") ||
1118 is_string_suffix(cheat_input, ":ft"))
1120 /* fix single-player tapes that contain player input for more than one
1121 player (due to a bug in 3.3.1.2 and earlier versions), which results
1122 in playing levels with more than one player in multi-player mode,
1123 even though the tape was originally recorded in single-player mode */
1125 /* remove player input actions for all players but the first one */
1126 for (i = 1; i < MAX_PLAYERS; i++)
1127 tape.player_participates[i] = FALSE;
1129 tape.changed = TRUE;
1131 else if (is_string_suffix(cheat_input, ":save-native-level") ||
1132 is_string_suffix(cheat_input, ":snl"))
1134 SaveNativeLevel(&level);
1137 else if (game_status == GAME_MODE_PLAYING)
1140 if (is_string_suffix(cheat_input, ".q"))
1141 DEBUG_SetMaximumDynamite();
1144 else if (game_status == GAME_MODE_EDITOR)
1146 if (is_string_suffix(cheat_input, ":dump-brush") ||
1147 is_string_suffix(cheat_input, ":DB"))
1151 else if (is_string_suffix(cheat_input, ":DDB"))
1158 void HandleKey(Key key, int key_status)
1160 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
1161 static boolean ignore_repeated_key = FALSE;
1162 static struct SetupKeyboardInfo ski;
1163 static struct SetupShortcutInfo ssi;
1172 { &ski.left, &ssi.snap_left, DEFAULT_KEY_LEFT, JOY_LEFT },
1173 { &ski.right, &ssi.snap_right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
1174 { &ski.up, &ssi.snap_up, DEFAULT_KEY_UP, JOY_UP },
1175 { &ski.down, &ssi.snap_down, DEFAULT_KEY_DOWN, JOY_DOWN },
1176 { &ski.snap, NULL, DEFAULT_KEY_SNAP, JOY_BUTTON_SNAP },
1177 { &ski.drop, NULL, DEFAULT_KEY_DROP, JOY_BUTTON_DROP }
1182 if (game_status == GAME_MODE_PLAYING)
1184 /* only needed for single-step tape recording mode */
1185 static boolean clear_snap_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1186 static boolean clear_drop_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1187 static boolean element_snapped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1188 static boolean element_dropped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1191 for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
1193 byte key_action = 0;
1195 if (setup.input[pnr].use_joystick)
1198 ski = setup.input[pnr].key;
1200 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1201 if (key == *key_info[i].key_custom)
1202 key_action |= key_info[i].action;
1204 /* use combined snap+direction keys for the first player only */
1207 ssi = setup.shortcut;
1209 for (i = 0; i < NUM_DIRECTIONS; i++)
1210 if (key == *key_info[i].key_snap)
1211 key_action |= key_info[i].action | JOY_BUTTON_SNAP;
1214 /* clear delayed snap and drop actions in single step mode (see below) */
1215 if (tape.single_step)
1217 if (clear_snap_button[pnr])
1219 stored_player[pnr].action &= ~KEY_BUTTON_SNAP;
1220 clear_snap_button[pnr] = FALSE;
1223 if (clear_drop_button[pnr])
1225 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1226 clear_drop_button[pnr] = FALSE;
1230 if (key_status == KEY_PRESSED)
1231 stored_player[pnr].action |= key_action;
1233 stored_player[pnr].action &= ~key_action;
1235 if (tape.single_step && tape.recording && tape.pausing)
1237 if (key_status == KEY_PRESSED && key_action & KEY_MOTION)
1239 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1241 /* if snap key already pressed, don't snap when releasing (below) */
1242 if (stored_player[pnr].action & KEY_BUTTON_SNAP)
1243 element_snapped[pnr] = TRUE;
1245 /* if drop key already pressed, don't drop when releasing (below) */
1246 if (stored_player[pnr].action & KEY_BUTTON_DROP)
1247 element_dropped[pnr] = TRUE;
1249 else if (key_status == KEY_PRESSED && key_action & KEY_BUTTON_DROP)
1251 if (level.game_engine_type == GAME_ENGINE_TYPE_EM ||
1252 level.game_engine_type == GAME_ENGINE_TYPE_SP)
1255 if (level.game_engine_type == GAME_ENGINE_TYPE_SP &&
1256 getRedDiskReleaseFlag_SP() == 0)
1257 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1259 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1262 else if (key_status == KEY_RELEASED && key_action & KEY_BUTTON)
1264 if (key_action & KEY_BUTTON_SNAP)
1266 /* if snap key was released without moving (see above), snap now */
1267 if (!element_snapped[pnr])
1269 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1271 stored_player[pnr].action |= KEY_BUTTON_SNAP;
1273 /* clear delayed snap button on next event */
1274 clear_snap_button[pnr] = TRUE;
1277 element_snapped[pnr] = FALSE;
1280 if (key_action & KEY_BUTTON_DROP &&
1281 level.game_engine_type == GAME_ENGINE_TYPE_RND)
1283 /* if drop key was released without moving (see above), drop now */
1284 if (!element_dropped[pnr])
1286 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1288 if (level.game_engine_type != GAME_ENGINE_TYPE_SP ||
1289 getRedDiskReleaseFlag_SP() != 0)
1290 stored_player[pnr].action |= KEY_BUTTON_DROP;
1292 /* clear delayed drop button on next event */
1293 clear_drop_button[pnr] = TRUE;
1296 element_dropped[pnr] = FALSE;
1300 else if (tape.recording && tape.pausing)
1302 /* prevent key release events from un-pausing a paused game */
1303 if (key_status == KEY_PRESSED && key_action & KEY_ACTION)
1304 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1310 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1311 if (key == key_info[i].key_default)
1312 joy |= key_info[i].action;
1317 if (key_status == KEY_PRESSED)
1318 key_joystick_mapping |= joy;
1320 key_joystick_mapping &= ~joy;
1325 if (game_status != GAME_MODE_PLAYING)
1326 key_joystick_mapping = 0;
1328 if (key_status == KEY_RELEASED)
1330 // reset flag to ignore repeated "key pressed" events after key release
1331 ignore_repeated_key = FALSE;
1336 if ((key == KSYM_F11 ||
1337 ((key == KSYM_Return ||
1338 key == KSYM_KP_Enter) && (GetKeyModState() & KMOD_Alt))) &&
1339 video.fullscreen_available &&
1340 !ignore_repeated_key)
1342 setup.fullscreen = !setup.fullscreen;
1344 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1346 if (game_status == GAME_MODE_SETUP)
1347 RedrawSetupScreenAfterFullscreenToggle();
1349 // set flag to ignore repeated "key pressed" events
1350 ignore_repeated_key = TRUE;
1355 if ((key == KSYM_minus ||
1358 ((GetKeyModState() & KMOD_Control) ||
1359 (GetKeyModState() & KMOD_Alt)) &&
1360 video.window_scaling_available &&
1361 !video.fullscreen_enabled)
1364 setup.window_scaling_percent = STD_WINDOW_SCALING_PERCENT;
1366 setup.window_scaling_percent +=
1367 (key == KSYM_minus ? -1 : +1) * STEP_WINDOW_SCALING_PERCENT;
1369 if (setup.window_scaling_percent < MIN_WINDOW_SCALING_PERCENT)
1370 setup.window_scaling_percent = MIN_WINDOW_SCALING_PERCENT;
1371 else if (setup.window_scaling_percent > MAX_WINDOW_SCALING_PERCENT)
1372 setup.window_scaling_percent = MAX_WINDOW_SCALING_PERCENT;
1374 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1376 if (game_status == GAME_MODE_SETUP)
1377 RedrawSetupScreenAfterFullscreenToggle();
1382 if (game_status == GAME_MODE_PLAYING && AllPlayersGone &&
1383 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
1390 if (game_status == GAME_MODE_MAIN &&
1391 (key == setup.shortcut.toggle_pause || key == KSYM_space))
1393 StartGameActions(options.network, setup.autorecord, level.random_seed);
1398 if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING)
1400 if (key == setup.shortcut.save_game)
1402 else if (key == setup.shortcut.load_game)
1404 else if (key == setup.shortcut.toggle_pause)
1405 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1407 HandleTapeButtonKeys(key);
1408 HandleSoundButtonKeys(key);
1411 if (game_status == GAME_MODE_PLAYING && !network_playing)
1413 int centered_player_nr_next = -999;
1415 if (key == setup.shortcut.focus_player_all)
1416 centered_player_nr_next = -1;
1418 for (i = 0; i < MAX_PLAYERS; i++)
1419 if (key == setup.shortcut.focus_player[i])
1420 centered_player_nr_next = i;
1422 if (centered_player_nr_next != -999)
1424 game.centered_player_nr_next = centered_player_nr_next;
1425 game.set_centered_player = TRUE;
1429 tape.centered_player_nr_next = game.centered_player_nr_next;
1430 tape.set_centered_player = TRUE;
1435 HandleKeysSpecial(key);
1437 if (HandleGadgetsKeyInput(key))
1439 if (key != KSYM_Escape) /* always allow ESC key to be handled */
1440 key = KSYM_UNDEFINED;
1443 switch (game_status)
1445 case GAME_MODE_PSEUDO_TYPENAME:
1446 HandleTypeName(0, key);
1449 case GAME_MODE_TITLE:
1450 case GAME_MODE_MAIN:
1451 case GAME_MODE_LEVELS:
1452 case GAME_MODE_LEVELNR:
1453 case GAME_MODE_SETUP:
1454 case GAME_MODE_INFO:
1455 case GAME_MODE_SCORES:
1460 if (game_status == GAME_MODE_TITLE)
1461 HandleTitleScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1462 else if (game_status == GAME_MODE_MAIN)
1463 HandleMainMenu(0, 0, 0, 0, MB_MENU_CHOICE);
1464 else if (game_status == GAME_MODE_LEVELS)
1465 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_CHOICE);
1466 else if (game_status == GAME_MODE_LEVELNR)
1467 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_CHOICE);
1468 else if (game_status == GAME_MODE_SETUP)
1469 HandleSetupScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1470 else if (game_status == GAME_MODE_INFO)
1471 HandleInfoScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1472 else if (game_status == GAME_MODE_SCORES)
1473 HandleHallOfFame(0, 0, 0, 0, MB_MENU_CHOICE);
1477 if (game_status != GAME_MODE_MAIN)
1478 FadeSkipNextFadeIn();
1480 if (game_status == GAME_MODE_TITLE)
1481 HandleTitleScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1482 else if (game_status == GAME_MODE_LEVELS)
1483 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_LEAVE);
1484 else if (game_status == GAME_MODE_LEVELNR)
1485 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_LEAVE);
1486 else if (game_status == GAME_MODE_SETUP)
1487 HandleSetupScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1488 else if (game_status == GAME_MODE_INFO)
1489 HandleInfoScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1490 else if (game_status == GAME_MODE_SCORES)
1491 HandleHallOfFame(0, 0, 0, 0, MB_MENU_LEAVE);
1495 if (game_status == GAME_MODE_LEVELS)
1496 HandleChooseLevelSet(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1497 else if (game_status == GAME_MODE_LEVELNR)
1498 HandleChooseLevelNr(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1499 else if (game_status == GAME_MODE_SETUP)
1500 HandleSetupScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1501 else if (game_status == GAME_MODE_INFO)
1502 HandleInfoScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1503 else if (game_status == GAME_MODE_SCORES)
1504 HandleHallOfFame(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1507 case KSYM_Page_Down:
1508 if (game_status == GAME_MODE_LEVELS)
1509 HandleChooseLevelSet(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1510 else if (game_status == GAME_MODE_LEVELNR)
1511 HandleChooseLevelNr(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1512 else if (game_status == GAME_MODE_SETUP)
1513 HandleSetupScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1514 else if (game_status == GAME_MODE_INFO)
1515 HandleInfoScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1516 else if (game_status == GAME_MODE_SCORES)
1517 HandleHallOfFame(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1522 GameFrameDelay = (GameFrameDelay == 500 ? GAME_FRAME_DELAY : 500);
1526 setup.sp_show_border_elements = !setup.sp_show_border_elements;
1527 printf("Supaplex border elements %s\n",
1528 setup.sp_show_border_elements ? "enabled" : "disabled");
1537 case GAME_MODE_EDITOR:
1538 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
1539 HandleLevelEditorKeyInput(key);
1542 case GAME_MODE_PLAYING:
1547 RequestQuitGame(setup.ask_on_escape);
1554 if (GameFrameDelay == 500)
1555 GameFrameDelay = GAME_FRAME_DELAY;
1557 GameFrameDelay = 500;
1560 GameFrameDelay = (key - KSYM_0) * 10;
1561 printf("Game speed == %d%% (%d ms delay between two frames)\n",
1562 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
1568 options.debug = FALSE;
1569 printf("debug mode disabled\n");
1573 options.debug = TRUE;
1574 printf("debug mode enabled\n");
1579 printf("::: currently using game engine version %d\n",
1580 game.engine_version);
1591 if (key == KSYM_Escape)
1593 SetGameStatus(GAME_MODE_MAIN);
1602 void HandleNoEvent()
1604 // if (button_status && game_status != GAME_MODE_PLAYING)
1605 if (button_status && (game_status != GAME_MODE_PLAYING || tape.pausing))
1607 HandleButton(0, 0, -button_status, button_status);
1614 #if defined(NETWORK_AVALIABLE)
1615 if (options.network)
1619 switch (game_status)
1621 case GAME_MODE_MAIN:
1622 DrawPreviewLevelAnimation();
1626 case GAME_MODE_LEVELS:
1627 case GAME_MODE_LEVELNR:
1628 case GAME_MODE_SETUP:
1629 case GAME_MODE_INFO:
1630 case GAME_MODE_SCORES:
1634 case GAME_MODE_EDITOR:
1635 HandleLevelEditorIdle();
1643 static int HandleJoystickForAllPlayers()
1648 for (i = 0; i < MAX_PLAYERS; i++)
1650 byte joy_action = 0;
1653 if (!setup.input[i].use_joystick)
1657 joy_action = Joystick(i);
1658 result |= joy_action;
1660 if (!setup.input[i].use_joystick)
1663 stored_player[i].action = joy_action;
1669 void HandleJoystick()
1671 int joystick = HandleJoystickForAllPlayers();
1672 int keyboard = key_joystick_mapping;
1673 int joy = (joystick | keyboard);
1674 int left = joy & JOY_LEFT;
1675 int right = joy & JOY_RIGHT;
1676 int up = joy & JOY_UP;
1677 int down = joy & JOY_DOWN;
1678 int button = joy & JOY_BUTTON;
1679 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
1680 int dx = (left ? -1 : right ? 1 : 0);
1681 int dy = (up ? -1 : down ? 1 : 0);
1683 switch (game_status)
1685 case GAME_MODE_TITLE:
1686 case GAME_MODE_MAIN:
1687 case GAME_MODE_LEVELS:
1688 case GAME_MODE_LEVELNR:
1689 case GAME_MODE_SETUP:
1690 case GAME_MODE_INFO:
1692 static unsigned int joystickmove_delay = 0;
1694 if (joystick && !button &&
1695 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
1696 newbutton = dx = dy = 0;
1698 if (game_status == GAME_MODE_TITLE)
1699 HandleTitleScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1700 else if (game_status == GAME_MODE_MAIN)
1701 HandleMainMenu(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1702 else if (game_status == GAME_MODE_LEVELS)
1703 HandleChooseLevelSet(0,0,dx,dy,newbutton?MB_MENU_CHOICE : MB_MENU_MARK);
1704 else if (game_status == GAME_MODE_LEVELNR)
1705 HandleChooseLevelNr(0,0,dx,dy,newbutton? MB_MENU_CHOICE : MB_MENU_MARK);
1706 else if (game_status == GAME_MODE_SETUP)
1707 HandleSetupScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1708 else if (game_status == GAME_MODE_INFO)
1709 HandleInfoScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1713 case GAME_MODE_SCORES:
1714 HandleHallOfFame(0, 0, dx, dy, !newbutton);
1717 case GAME_MODE_PLAYING:
1718 if (tape.playing || keyboard)
1719 newbutton = ((joy & JOY_BUTTON) != 0);
1721 if (newbutton && AllPlayersGone)