1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
12 #include "libgame/libgame.h"
26 #define DEBUG_EVENTS 0
28 #define DEBUG_EVENTS_BUTTON (DEBUG_EVENTS * 0)
29 #define DEBUG_EVENTS_MOTION (DEBUG_EVENTS * 0)
30 #define DEBUG_EVENTS_WINDOW (DEBUG_EVENTS * 0)
31 #define DEBUG_EVENTS_FINGER (DEBUG_EVENTS * 0)
32 #define DEBUG_EVENTS_TEXT (DEBUG_EVENTS * 1)
33 #define DEBUG_EVENTS_KEY (DEBUG_EVENTS * 1)
36 static boolean cursor_inside_playfield = FALSE;
37 static int cursor_mode_last = CURSOR_DEFAULT;
38 static unsigned int special_cursor_delay = 0;
39 static unsigned int special_cursor_delay_value = 1000;
41 /* event filter especially needed for SDL event filtering due to
42 delay problems with lots of mouse motion events when mouse button
43 not pressed (X11 can handle this with 'PointerMotionHintMask') */
45 /* event filter addition for SDL2: as SDL2 does not have a function to enable
46 or disable keyboard auto-repeat, filter repeated keyboard events instead */
48 static int FilterEventsExt(const Event *event)
52 #if defined(TARGET_SDL2)
53 /* skip repeated key press events if keyboard auto-repeat is disabled */
54 if (event->type == EVENT_KEYPRESS &&
60 /* non-motion events are directly passed to event handler functions */
61 if (event->type != EVENT_MOTIONNOTIFY)
64 motion = (MotionEvent *)event;
65 cursor_inside_playfield = (motion->x >= SX && motion->x < SX + SXSIZE &&
66 motion->y >= SY && motion->y < SY + SYSIZE);
68 /* do no reset mouse cursor before all pending events have been processed */
69 if (gfx.cursor_mode == cursor_mode_last &&
70 ((game_status == GAME_MODE_TITLE &&
71 gfx.cursor_mode == CURSOR_NONE) ||
72 (game_status == GAME_MODE_PLAYING &&
73 gfx.cursor_mode == CURSOR_PLAYFIELD)))
75 SetMouseCursor(CURSOR_DEFAULT);
77 DelayReached(&special_cursor_delay, 0);
79 cursor_mode_last = CURSOR_DEFAULT;
82 /* skip mouse motion events without pressed button outside level editor */
83 if (button_status == MB_RELEASED &&
84 game_status != GAME_MODE_EDITOR && game_status != GAME_MODE_PLAYING)
90 #if defined(TARGET_SDL2)
91 int FilterEvents(void *userdata, Event *event)
93 return FilterEventsExt(event);
96 int FilterEvents(const Event *event)
98 return FilterEventsExt(event);
102 /* to prevent delay problems, skip mouse motion events if the very next
103 event is also a mouse motion event (and therefore effectively only
104 handling the last of a row of mouse motion events in the event queue) */
106 boolean SkipPressedMouseMotionEvent(const Event *event)
108 /* nothing to do if the current event is not a mouse motion event */
109 if (event->type != EVENT_MOTIONNOTIFY)
112 /* only skip motion events with pressed button outside the game */
113 if (button_status == MB_RELEASED || game_status == GAME_MODE_PLAYING)
120 PeekEvent(&next_event);
122 /* if next event is also a mouse motion event, skip the current one */
123 if (next_event.type == EVENT_MOTIONNOTIFY)
130 /* this is only really needed for non-SDL targets to filter unwanted events;
131 when using SDL with properly installed event filter, this function can be
132 replaced with a simple "NextEvent()" call, but it doesn't hurt either */
134 boolean NextValidEvent(Event *event)
136 while (PendingEvent())
138 boolean handle_this_event = FALSE;
142 if (FilterEventsExt(event))
143 handle_this_event = TRUE;
145 if (SkipPressedMouseMotionEvent(event))
146 handle_this_event = FALSE;
148 if (handle_this_event)
157 static unsigned int sync_frame_delay = 0;
158 unsigned int sync_frame_delay_value = GAME_FRAME_DELAY;
162 if (PendingEvent()) /* got event */
164 // use separate frame delay counter to not reset main delay counter
165 unsigned int sync_frame_delay2 = 0;
166 unsigned int sync_frame_delay_value2 = sync_frame_delay_value;
169 ResetDelayCounter(&sync_frame_delay2);
171 while (NextValidEvent(&event))
175 case EVENT_BUTTONPRESS:
176 case EVENT_BUTTONRELEASE:
177 HandleButtonEvent((ButtonEvent *) &event);
180 case EVENT_MOTIONNOTIFY:
181 HandleMotionEvent((MotionEvent *) &event);
184 #if defined(TARGET_SDL2)
185 case SDL_WINDOWEVENT:
186 HandleWindowEvent((WindowEvent *) &event);
189 case EVENT_FINGERPRESS:
190 case EVENT_FINGERRELEASE:
191 case EVENT_FINGERMOTION:
192 HandleFingerEvent((FingerEvent *) &event);
195 case EVENT_TEXTINPUT:
196 HandleTextEvent((TextEvent *) &event);
199 case SDL_APP_WILLENTERBACKGROUND:
200 case SDL_APP_DIDENTERBACKGROUND:
201 case SDL_APP_WILLENTERFOREGROUND:
202 case SDL_APP_DIDENTERFOREGROUND:
203 HandlePauseResumeEvent((PauseResumeEvent *) &event);
208 case EVENT_KEYRELEASE:
209 HandleKeyEvent((KeyEvent *) &event);
213 HandleOtherEvents(&event);
217 // do not handle events for longer than standard frame delay period
218 if (DelayReached(&sync_frame_delay2, sync_frame_delay_value2))
223 // always handle non-event game actions for every game frame interval
225 if (game_status == GAME_MODE_TITLE)
227 /* when showing title screens, hide mouse pointer (if not moved) */
229 if (gfx.cursor_mode != CURSOR_NONE &&
230 DelayReached(&special_cursor_delay, special_cursor_delay_value))
232 SetMouseCursor(CURSOR_NONE);
235 else if (game_status == GAME_MODE_PLAYING && (!tape.pausing ||
238 /* when playing, display a special mouse pointer inside the playfield */
240 if (gfx.cursor_mode != CURSOR_PLAYFIELD &&
241 cursor_inside_playfield &&
242 DelayReached(&special_cursor_delay, special_cursor_delay_value))
244 SetMouseCursor(CURSOR_PLAYFIELD);
247 else if (gfx.cursor_mode != CURSOR_DEFAULT)
249 SetMouseCursor(CURSOR_DEFAULT);
252 /* this is set after all pending events have been processed */
253 cursor_mode_last = gfx.cursor_mode;
256 /* also execute after pending events have been processed before */
259 /* don't use all CPU time when idle; the main loop while playing
260 has its own synchronization and is CPU friendly, too */
262 if (game_status == GAME_MODE_PLAYING)
265 /* refresh window contents from drawing buffer, if needed */
268 if (game_status != GAME_MODE_PLAYING)
269 WaitUntilDelayReached(&sync_frame_delay, sync_frame_delay_value);
271 if (game_status == GAME_MODE_QUIT)
276 void HandleOtherEvents(Event *event)
281 HandleExposeEvent((ExposeEvent *) event);
284 case EVENT_UNMAPNOTIFY:
286 /* This causes the game to stop not only when iconified, but also
287 when on another virtual desktop, which might be not desired. */
288 SleepWhileUnmapped();
294 HandleFocusEvent((FocusChangeEvent *) event);
297 case EVENT_CLIENTMESSAGE:
298 HandleClientMessageEvent((ClientMessageEvent *) event);
301 #if defined(TARGET_SDL)
302 case SDL_JOYAXISMOTION:
303 case SDL_JOYBUTTONDOWN:
304 case SDL_JOYBUTTONUP:
305 HandleJoystickEvent(event);
309 HandleWindowManagerEvent(event);
318 void ClearEventQueue()
320 while (PendingEvent())
328 case EVENT_BUTTONRELEASE:
329 button_status = MB_RELEASED;
332 case EVENT_KEYRELEASE:
337 HandleOtherEvents(&event);
343 void ClearPlayerAction()
347 /* simulate key release events for still pressed keys */
348 key_joystick_mapping = 0;
349 for (i = 0; i < MAX_PLAYERS; i++)
350 stored_player[i].action = 0;
353 void SleepWhileUnmapped()
355 boolean window_unmapped = TRUE;
357 KeyboardAutoRepeatOn();
359 while (window_unmapped)
367 case EVENT_BUTTONRELEASE:
368 button_status = MB_RELEASED;
371 case EVENT_KEYRELEASE:
372 key_joystick_mapping = 0;
375 case EVENT_MAPNOTIFY:
376 window_unmapped = FALSE;
379 case EVENT_UNMAPNOTIFY:
380 /* this is only to surely prevent the 'should not happen' case
381 * of recursively looping between 'SleepWhileUnmapped()' and
382 * 'HandleOtherEvents()' which usually calls this funtion.
387 HandleOtherEvents(&event);
392 if (game_status == GAME_MODE_PLAYING)
393 KeyboardAutoRepeatOffUnlessAutoplay();
396 void HandleExposeEvent(ExposeEvent *event)
400 void HandleButtonEvent(ButtonEvent *event)
402 #if DEBUG_EVENTS_BUTTON
403 Error(ERR_DEBUG, "BUTTON EVENT: button %d %s, x/y %d/%d\n",
405 event->type == EVENT_BUTTONPRESS ? "pressed" : "released",
409 motion_status = FALSE;
411 if (event->type == EVENT_BUTTONPRESS)
412 button_status = event->button;
414 button_status = MB_RELEASED;
416 HandleButton(event->x, event->y, button_status, event->button);
419 void HandleMotionEvent(MotionEvent *event)
421 if (button_status == MB_RELEASED && game_status != GAME_MODE_EDITOR)
424 motion_status = TRUE;
426 #if DEBUG_EVENTS_MOTION
427 Error(ERR_DEBUG, "MOTION EVENT: button %d moved, x/y %d/%d\n",
428 button_status, event->x, event->y);
431 HandleButton(event->x, event->y, button_status, button_status);
434 #if defined(TARGET_SDL2)
436 void HandleWindowEvent(WindowEvent *event)
438 #if DEBUG_EVENTS_WINDOW
439 int subtype = event->event;
442 (subtype == SDL_WINDOWEVENT_SHOWN ? "SDL_WINDOWEVENT_SHOWN" :
443 subtype == SDL_WINDOWEVENT_HIDDEN ? "SDL_WINDOWEVENT_HIDDEN" :
444 subtype == SDL_WINDOWEVENT_EXPOSED ? "SDL_WINDOWEVENT_EXPOSED" :
445 subtype == SDL_WINDOWEVENT_MOVED ? "SDL_WINDOWEVENT_MOVED" :
446 subtype == SDL_WINDOWEVENT_SIZE_CHANGED ? "SDL_WINDOWEVENT_SIZE_CHANGED" :
447 subtype == SDL_WINDOWEVENT_RESIZED ? "SDL_WINDOWEVENT_RESIZED" :
448 subtype == SDL_WINDOWEVENT_MINIMIZED ? "SDL_WINDOWEVENT_MINIMIZED" :
449 subtype == SDL_WINDOWEVENT_MAXIMIZED ? "SDL_WINDOWEVENT_MAXIMIZED" :
450 subtype == SDL_WINDOWEVENT_RESTORED ? "SDL_WINDOWEVENT_RESTORED" :
451 subtype == SDL_WINDOWEVENT_ENTER ? "SDL_WINDOWEVENT_ENTER" :
452 subtype == SDL_WINDOWEVENT_LEAVE ? "SDL_WINDOWEVENT_LEAVE" :
453 subtype == SDL_WINDOWEVENT_FOCUS_GAINED ? "SDL_WINDOWEVENT_FOCUS_GAINED" :
454 subtype == SDL_WINDOWEVENT_FOCUS_LOST ? "SDL_WINDOWEVENT_FOCUS_LOST" :
455 subtype == SDL_WINDOWEVENT_CLOSE ? "SDL_WINDOWEVENT_CLOSE" :
458 Error(ERR_DEBUG, "WINDOW EVENT: '%s', %ld, %ld",
459 event_name, event->data1, event->data2);
462 if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED ||
463 event->event == SDL_WINDOWEVENT_RESIZED ||
464 event->event == SDL_WINDOWEVENT_EXPOSED)
467 if (event->event == SDL_WINDOWEVENT_RESIZED && !video.fullscreen_enabled)
469 int new_window_width = event->data1;
470 int new_window_height = event->data2;
472 // if window size has changed after resizing, calculate new scaling factor
473 if (new_window_width != video.window_width ||
474 new_window_height != video.window_height)
476 int new_xpercent = (100 * new_window_width / video.width);
477 int new_ypercent = (100 * new_window_height / video.height);
479 setup.window_scaling_percent = video.window_scaling_percent =
480 MIN(MAX(MIN_WINDOW_SCALING_PERCENT, MIN(new_xpercent, new_ypercent)),
481 MAX_WINDOW_SCALING_PERCENT);
483 video.window_width = new_window_width;
484 video.window_height = new_window_height;
486 if (game_status == GAME_MODE_SETUP)
487 RedrawSetupScreenAfterFullscreenToggle();
494 #define NUM_TOUCH_FINGERS 3
499 SDL_FingerID finger_id;
502 } touch_info[NUM_TOUCH_FINGERS];
504 void HandleFingerEvent(FingerEvent *event)
506 static Key motion_key_x = KSYM_UNDEFINED;
507 static Key motion_key_y = KSYM_UNDEFINED;
508 static Key button_key = KSYM_UNDEFINED;
509 static float motion_x1, motion_y1;
510 static float button_x1, button_y1;
511 static SDL_FingerID motion_id = -1;
512 static SDL_FingerID button_id = -1;
513 int move_trigger_distance_percent = 2; // percent of touchpad width/height
514 int drop_trigger_distance_percent = 5; // percent of touchpad width/height
515 float move_trigger_distance = (float)move_trigger_distance_percent / 100;
516 float drop_trigger_distance = (float)drop_trigger_distance_percent / 100;
517 float event_x = event->x;
518 float event_y = event->y;
520 #if DEBUG_EVENTS_FINGER
521 Error(ERR_DEBUG, "FINGER EVENT: finger was %s, touch ID %lld, finger ID %lld, x/y %f/%f, dx/dy %f/%f, pressure %f",
522 event->type == EVENT_FINGERPRESS ? "pressed" :
523 event->type == EVENT_FINGERRELEASE ? "released" : "moved",
527 event->dx, event->dy,
531 if (game_status != GAME_MODE_PLAYING)
534 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
536 int key_status = (event->type == EVENT_FINGERRELEASE ? KEY_RELEASED :
538 Key key = (event->x < 1.0 / 3.0 ?
539 (event->y < 1.0 / 2.0 ? setup.input[0].key.snap :
540 setup.input[0].key.drop) :
541 event->x > 2.0 / 3.0 ?
542 (event->y < 1.0 / 3.0 ? setup.input[0].key.up :
543 event->y > 2.0 / 3.0 ? setup.input[0].key.down :
544 event->x < 5.0 / 6.0 ? setup.input[0].key.left :
545 setup.input[0].key.right) :
547 char *key_status_name = (key_status == KEY_RELEASED ? "KEY_RELEASED" :
551 Error(ERR_DEBUG, "::: key '%s' was '%s' [fingerId: %lld]",
552 getKeyNameFromKey(key), key_status_name, event->fingerId);
554 // check if we already know this touch event's finger id
555 for (i = 0; i < NUM_TOUCH_FINGERS; i++)
557 if (touch_info[i].touched &&
558 touch_info[i].finger_id == event->fingerId)
560 // Error(ERR_DEBUG, "MARK 1: %d", i);
566 if (i >= NUM_TOUCH_FINGERS)
568 if (key_status == KEY_PRESSED)
570 int oldest_pos = 0, oldest_counter = touch_info[0].counter;
572 // unknown finger id -- get new, empty slot, if available
573 for (i = 0; i < NUM_TOUCH_FINGERS; i++)
575 if (touch_info[i].counter < oldest_counter)
578 oldest_counter = touch_info[i].counter;
580 // Error(ERR_DEBUG, "MARK 2: %d", i);
583 if (!touch_info[i].touched)
585 // Error(ERR_DEBUG, "MARK 3: %d", i);
591 if (i >= NUM_TOUCH_FINGERS)
593 // all slots allocated -- use oldest slot
596 // Error(ERR_DEBUG, "MARK 4: %d", i);
601 // release of previously unknown key (should not happen)
603 if (key != KSYM_UNDEFINED)
605 HandleKey(key, KEY_RELEASED);
607 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [1]",
608 getKeyNameFromKey(key), "KEY_RELEASED", i);
613 if (i < NUM_TOUCH_FINGERS)
615 if (key_status == KEY_PRESSED)
617 if (touch_info[i].key != key)
619 if (touch_info[i].key != KSYM_UNDEFINED)
621 HandleKey(touch_info[i].key, KEY_RELEASED);
623 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [2]",
624 getKeyNameFromKey(touch_info[i].key), "KEY_RELEASED", i);
627 if (key != KSYM_UNDEFINED)
629 HandleKey(key, KEY_PRESSED);
631 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [3]",
632 getKeyNameFromKey(key), "KEY_PRESSED", i);
636 touch_info[i].touched = TRUE;
637 touch_info[i].finger_id = event->fingerId;
638 touch_info[i].counter = Counter();
639 touch_info[i].key = key;
643 if (touch_info[i].key != KSYM_UNDEFINED)
645 HandleKey(touch_info[i].key, KEY_RELEASED);
647 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [4]",
648 getKeyNameFromKey(touch_info[i].key), "KEY_RELEASED", i);
651 touch_info[i].touched = FALSE;
652 touch_info[i].finger_id = 0;
653 touch_info[i].counter = 0;
654 touch_info[i].key = 0;
661 // use touch direction control
663 if (event->type == EVENT_FINGERPRESS)
665 if (event_x > 1.0 / 3.0)
669 motion_id = event->fingerId;
674 motion_key_x = KSYM_UNDEFINED;
675 motion_key_y = KSYM_UNDEFINED;
677 Error(ERR_DEBUG, "---------- MOVE STARTED (WAIT) ----------");
683 button_id = event->fingerId;
688 button_key = setup.input[0].key.snap;
690 HandleKey(button_key, KEY_PRESSED);
692 Error(ERR_DEBUG, "---------- SNAP STARTED ----------");
695 else if (event->type == EVENT_FINGERRELEASE)
697 if (event->fingerId == motion_id)
701 if (motion_key_x != KSYM_UNDEFINED)
702 HandleKey(motion_key_x, KEY_RELEASED);
703 if (motion_key_y != KSYM_UNDEFINED)
704 HandleKey(motion_key_y, KEY_RELEASED);
706 motion_key_x = KSYM_UNDEFINED;
707 motion_key_y = KSYM_UNDEFINED;
709 Error(ERR_DEBUG, "---------- MOVE STOPPED ----------");
711 else if (event->fingerId == button_id)
715 if (button_key != KSYM_UNDEFINED)
716 HandleKey(button_key, KEY_RELEASED);
718 button_key = KSYM_UNDEFINED;
720 Error(ERR_DEBUG, "---------- SNAP STOPPED ----------");
723 else if (event->type == EVENT_FINGERMOTION)
725 if (event->fingerId == motion_id)
727 float distance_x = ABS(event_x - motion_x1);
728 float distance_y = ABS(event_y - motion_y1);
729 Key new_motion_key_x = (event_x < motion_x1 ? setup.input[0].key.left :
730 event_x > motion_x1 ? setup.input[0].key.right :
732 Key new_motion_key_y = (event_y < motion_y1 ? setup.input[0].key.up :
733 event_y > motion_y1 ? setup.input[0].key.down :
736 if (distance_x < move_trigger_distance / 2 ||
737 distance_x < distance_y)
738 new_motion_key_x = KSYM_UNDEFINED;
740 if (distance_y < move_trigger_distance / 2 ||
741 distance_y < distance_x)
742 new_motion_key_y = KSYM_UNDEFINED;
744 if (distance_x > move_trigger_distance ||
745 distance_y > move_trigger_distance)
747 if (new_motion_key_x != motion_key_x)
749 if (motion_key_x != KSYM_UNDEFINED)
750 HandleKey(motion_key_x, KEY_RELEASED);
751 if (new_motion_key_x != KSYM_UNDEFINED)
752 HandleKey(new_motion_key_x, KEY_PRESSED);
755 if (new_motion_key_y != motion_key_y)
757 if (motion_key_y != KSYM_UNDEFINED)
758 HandleKey(motion_key_y, KEY_RELEASED);
759 if (new_motion_key_y != KSYM_UNDEFINED)
760 HandleKey(new_motion_key_y, KEY_PRESSED);
766 motion_key_x = new_motion_key_x;
767 motion_key_y = new_motion_key_y;
769 Error(ERR_DEBUG, "---------- MOVE STARTED (MOVE) ----------");
772 else if (event->fingerId == button_id)
774 float distance_x = ABS(event_x - button_x1);
775 float distance_y = ABS(event_y - button_y1);
777 if (distance_x < drop_trigger_distance / 2 &&
778 distance_y > drop_trigger_distance)
780 if (button_key == setup.input[0].key.snap)
781 HandleKey(button_key, KEY_RELEASED);
786 button_key = setup.input[0].key.drop;
788 HandleKey(button_key, KEY_PRESSED);
790 Error(ERR_DEBUG, "---------- DROP STARTED ----------");
796 static boolean checkTextInputKeyModState()
798 // when playing, only handle raw key events and ignore text input
799 if (game_status == GAME_MODE_PLAYING)
802 return ((GetKeyModState() & KMOD_TextInput) != KMOD_None);
805 void HandleTextEvent(TextEvent *event)
807 char *text = event->text;
808 Key key = getKeyFromKeyName(text);
810 #if DEBUG_EVENTS_TEXT
811 Error(ERR_DEBUG, "TEXT EVENT: text == '%s' [%d byte(s), '%c'/%d], resulting key == %d (%s) [%04x]",
814 text[0], (int)(text[0]),
816 getKeyNameFromKey(key),
820 #if defined(PLATFORM_ANDROID)
821 if (game_status == GAME_MODE_PSEUDO_TYPENAME)
823 HandleTypeName(0, key);
829 // only handle key input with text modifier keys pressed
830 if (checkTextInputKeyModState())
832 HandleKey(key, KEY_PRESSED);
833 HandleKey(key, KEY_RELEASED);
837 void HandlePauseResumeEvent(PauseResumeEvent *event)
839 if (event->type == SDL_APP_WILLENTERBACKGROUND)
843 else if (event->type == SDL_APP_DIDENTERFOREGROUND)
851 void HandleKeyEvent(KeyEvent *event)
853 int key_status = (event->type == EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
854 boolean with_modifiers = (game_status == GAME_MODE_PLAYING ? FALSE : TRUE);
855 Key key = GetEventKey(event, with_modifiers);
856 Key keymod = (with_modifiers ? GetEventKey(event, FALSE) : key);
859 Error(ERR_DEBUG, "KEY EVENT: key was %s, keysym.scancode == %d, keysym.sym == %d, keymod = %d, GetKeyModState() = 0x%04x, resulting key == %d (%s)",
860 event->type == EVENT_KEYPRESS ? "pressed" : "released",
861 event->keysym.scancode,
866 getKeyNameFromKey(key));
869 #if defined(PLATFORM_ANDROID)
870 // always map the "back" button to the "escape" key on Android devices
871 if (key == KSYM_Back)
875 HandleKeyModState(keymod, key_status);
877 #if defined(TARGET_SDL2)
878 // only handle raw key input without text modifier keys pressed
879 if (!checkTextInputKeyModState())
880 HandleKey(key, key_status);
882 HandleKey(key, key_status);
886 void HandleFocusEvent(FocusChangeEvent *event)
888 static int old_joystick_status = -1;
890 if (event->type == EVENT_FOCUSOUT)
892 KeyboardAutoRepeatOn();
893 old_joystick_status = joystick.status;
894 joystick.status = JOYSTICK_NOT_AVAILABLE;
898 else if (event->type == EVENT_FOCUSIN)
900 /* When there are two Rocks'n'Diamonds windows which overlap and
901 the player moves the pointer from one game window to the other,
902 a 'FocusOut' event is generated for the window the pointer is
903 leaving and a 'FocusIn' event is generated for the window the
904 pointer is entering. In some cases, it can happen that the
905 'FocusIn' event is handled by the one game process before the
906 'FocusOut' event by the other game process. In this case the
907 X11 environment would end up with activated keyboard auto repeat,
908 because unfortunately this is a global setting and not (which
909 would be far better) set for each X11 window individually.
910 The effect would be keyboard auto repeat while playing the game
911 (game_status == GAME_MODE_PLAYING), which is not desired.
912 To avoid this special case, we just wait 1/10 second before
913 processing the 'FocusIn' event.
916 if (game_status == GAME_MODE_PLAYING)
919 KeyboardAutoRepeatOffUnlessAutoplay();
922 if (old_joystick_status != -1)
923 joystick.status = old_joystick_status;
927 void HandleClientMessageEvent(ClientMessageEvent *event)
929 if (CheckCloseWindowEvent(event))
933 void HandleWindowManagerEvent(Event *event)
935 #if defined(TARGET_SDL)
936 SDLHandleWindowManagerEvent(event);
940 void HandleButton(int mx, int my, int button, int button_nr)
942 static int old_mx = 0, old_my = 0;
943 boolean button_hold = FALSE;
958 #if defined(PLATFORM_ANDROID)
959 // !!! for now, do not handle gadgets when playing -- maybe fix this !!!
960 if (game_status != GAME_MODE_PLAYING &&
961 HandleGadgets(mx, my, button))
963 /* do not handle this button event anymore */
964 mx = my = -32; /* force mouse event to be outside screen tiles */
967 if (HandleGadgets(mx, my, button))
969 /* do not handle this button event anymore */
970 mx = my = -32; /* force mouse event to be outside screen tiles */
974 if (button_hold && game_status == GAME_MODE_PLAYING && tape.pausing)
977 /* do not use scroll wheel button events for anything other than gadgets */
978 if (IS_WHEEL_BUTTON(button_nr))
983 case GAME_MODE_TITLE:
984 HandleTitleScreen(mx, my, 0, 0, button);
988 HandleMainMenu(mx, my, 0, 0, button);
991 case GAME_MODE_PSEUDO_TYPENAME:
992 HandleTypeName(0, KSYM_Return);
995 case GAME_MODE_LEVELS:
996 HandleChooseLevelSet(mx, my, 0, 0, button);
999 case GAME_MODE_LEVELNR:
1000 HandleChooseLevelNr(mx, my, 0, 0, button);
1003 case GAME_MODE_SCORES:
1004 HandleHallOfFame(0, 0, 0, 0, button);
1007 case GAME_MODE_EDITOR:
1008 HandleLevelEditorIdle();
1011 case GAME_MODE_INFO:
1012 HandleInfoScreen(mx, my, 0, 0, button);
1015 case GAME_MODE_SETUP:
1016 HandleSetupScreen(mx, my, 0, 0, button);
1019 case GAME_MODE_PLAYING:
1021 if (button == MB_PRESSED && !motion_status && IN_GFX_FIELD_PLAY(mx, my))
1022 DumpTile(LEVELX((mx - SX) / TILESIZE_VAR),
1023 LEVELY((my - SY) / TILESIZE_VAR));
1024 // DumpTile(LEVELX((mx - SX) / TILEX), LEVELY((my - SY) / TILEY));
1033 static boolean is_string_suffix(char *string, char *suffix)
1035 int string_len = strlen(string);
1036 int suffix_len = strlen(suffix);
1038 if (suffix_len > string_len)
1041 return (strEqual(&string[string_len - suffix_len], suffix));
1044 #define MAX_CHEAT_INPUT_LEN 32
1046 static void HandleKeysSpecial(Key key)
1048 static char cheat_input[2 * MAX_CHEAT_INPUT_LEN + 1] = "";
1049 char letter = getCharFromKey(key);
1050 int cheat_input_len = strlen(cheat_input);
1056 if (cheat_input_len >= 2 * MAX_CHEAT_INPUT_LEN)
1058 for (i = 0; i < MAX_CHEAT_INPUT_LEN + 1; i++)
1059 cheat_input[i] = cheat_input[MAX_CHEAT_INPUT_LEN + i];
1061 cheat_input_len = MAX_CHEAT_INPUT_LEN;
1064 cheat_input[cheat_input_len++] = letter;
1065 cheat_input[cheat_input_len] = '\0';
1067 #if DEBUG_EVENTS_KEY
1068 Error(ERR_DEBUG, "SPECIAL KEY '%s' [%d]\n", cheat_input, cheat_input_len);
1071 if (game_status == GAME_MODE_MAIN)
1073 if (is_string_suffix(cheat_input, ":insert-solution-tape") ||
1074 is_string_suffix(cheat_input, ":ist"))
1076 InsertSolutionTape();
1078 else if (is_string_suffix(cheat_input, ":reload-graphics") ||
1079 is_string_suffix(cheat_input, ":rg"))
1081 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS);
1084 else if (is_string_suffix(cheat_input, ":reload-sounds") ||
1085 is_string_suffix(cheat_input, ":rs"))
1087 ReloadCustomArtwork(1 << ARTWORK_TYPE_SOUNDS);
1090 else if (is_string_suffix(cheat_input, ":reload-music") ||
1091 is_string_suffix(cheat_input, ":rm"))
1093 ReloadCustomArtwork(1 << ARTWORK_TYPE_MUSIC);
1096 else if (is_string_suffix(cheat_input, ":reload-artwork") ||
1097 is_string_suffix(cheat_input, ":ra"))
1099 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS |
1100 1 << ARTWORK_TYPE_SOUNDS |
1101 1 << ARTWORK_TYPE_MUSIC);
1104 else if (is_string_suffix(cheat_input, ":dump-level") ||
1105 is_string_suffix(cheat_input, ":dl"))
1109 else if (is_string_suffix(cheat_input, ":dump-tape") ||
1110 is_string_suffix(cheat_input, ":dt"))
1114 else if (is_string_suffix(cheat_input, ":fix-tape") ||
1115 is_string_suffix(cheat_input, ":ft"))
1117 /* fix single-player tapes that contain player input for more than one
1118 player (due to a bug in 3.3.1.2 and earlier versions), which results
1119 in playing levels with more than one player in multi-player mode,
1120 even though the tape was originally recorded in single-player mode */
1122 /* remove player input actions for all players but the first one */
1123 for (i = 1; i < MAX_PLAYERS; i++)
1124 tape.player_participates[i] = FALSE;
1126 tape.changed = TRUE;
1128 else if (is_string_suffix(cheat_input, ":save-native-level") ||
1129 is_string_suffix(cheat_input, ":snl"))
1131 SaveNativeLevel(&level);
1134 else if (game_status == GAME_MODE_PLAYING)
1137 if (is_string_suffix(cheat_input, ".q"))
1138 DEBUG_SetMaximumDynamite();
1141 else if (game_status == GAME_MODE_EDITOR)
1143 if (is_string_suffix(cheat_input, ":dump-brush") ||
1144 is_string_suffix(cheat_input, ":DB"))
1148 else if (is_string_suffix(cheat_input, ":DDB"))
1155 void HandleKey(Key key, int key_status)
1157 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
1158 static struct SetupKeyboardInfo ski;
1159 static struct SetupShortcutInfo ssi;
1168 { &ski.left, &ssi.snap_left, DEFAULT_KEY_LEFT, JOY_LEFT },
1169 { &ski.right, &ssi.snap_right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
1170 { &ski.up, &ssi.snap_up, DEFAULT_KEY_UP, JOY_UP },
1171 { &ski.down, &ssi.snap_down, DEFAULT_KEY_DOWN, JOY_DOWN },
1172 { &ski.snap, NULL, DEFAULT_KEY_SNAP, JOY_BUTTON_SNAP },
1173 { &ski.drop, NULL, DEFAULT_KEY_DROP, JOY_BUTTON_DROP }
1178 if (game_status == GAME_MODE_PLAYING)
1180 /* only needed for single-step tape recording mode */
1181 static boolean clear_snap_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1182 static boolean clear_drop_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1183 static boolean element_snapped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1184 static boolean element_dropped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1187 for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
1189 byte key_action = 0;
1191 if (setup.input[pnr].use_joystick)
1194 ski = setup.input[pnr].key;
1196 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1197 if (key == *key_info[i].key_custom)
1198 key_action |= key_info[i].action;
1200 /* use combined snap+direction keys for the first player only */
1203 ssi = setup.shortcut;
1205 for (i = 0; i < NUM_DIRECTIONS; i++)
1206 if (key == *key_info[i].key_snap)
1207 key_action |= key_info[i].action | JOY_BUTTON_SNAP;
1210 /* clear delayed snap and drop actions in single step mode (see below) */
1211 if (tape.single_step)
1213 if (clear_snap_button[pnr])
1215 stored_player[pnr].action &= ~KEY_BUTTON_SNAP;
1216 clear_snap_button[pnr] = FALSE;
1219 if (clear_drop_button[pnr])
1221 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1222 clear_drop_button[pnr] = FALSE;
1226 if (key_status == KEY_PRESSED)
1227 stored_player[pnr].action |= key_action;
1229 stored_player[pnr].action &= ~key_action;
1231 if (tape.single_step && tape.recording && tape.pausing)
1233 if (key_status == KEY_PRESSED && key_action & KEY_MOTION)
1235 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1237 /* if snap key already pressed, don't snap when releasing (below) */
1238 if (stored_player[pnr].action & KEY_BUTTON_SNAP)
1239 element_snapped[pnr] = TRUE;
1241 /* if drop key already pressed, don't drop when releasing (below) */
1242 if (stored_player[pnr].action & KEY_BUTTON_DROP)
1243 element_dropped[pnr] = TRUE;
1245 else if (key_status == KEY_PRESSED && key_action & KEY_BUTTON_DROP)
1247 if (level.game_engine_type == GAME_ENGINE_TYPE_EM ||
1248 level.game_engine_type == GAME_ENGINE_TYPE_SP)
1251 if (level.game_engine_type == GAME_ENGINE_TYPE_SP &&
1252 getRedDiskReleaseFlag_SP() == 0)
1253 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1255 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1258 else if (key_status == KEY_RELEASED && key_action & KEY_BUTTON)
1260 if (key_action & KEY_BUTTON_SNAP)
1262 /* if snap key was released without moving (see above), snap now */
1263 if (!element_snapped[pnr])
1265 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1267 stored_player[pnr].action |= KEY_BUTTON_SNAP;
1269 /* clear delayed snap button on next event */
1270 clear_snap_button[pnr] = TRUE;
1273 element_snapped[pnr] = FALSE;
1276 if (key_action & KEY_BUTTON_DROP &&
1277 level.game_engine_type == GAME_ENGINE_TYPE_RND)
1279 /* if drop key was released without moving (see above), drop now */
1280 if (!element_dropped[pnr])
1282 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1284 if (level.game_engine_type != GAME_ENGINE_TYPE_SP ||
1285 getRedDiskReleaseFlag_SP() != 0)
1286 stored_player[pnr].action |= KEY_BUTTON_DROP;
1288 /* clear delayed drop button on next event */
1289 clear_drop_button[pnr] = TRUE;
1292 element_dropped[pnr] = FALSE;
1296 else if (tape.recording && tape.pausing)
1298 /* prevent key release events from un-pausing a paused game */
1299 if (key_status == KEY_PRESSED && key_action & KEY_ACTION)
1300 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1306 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1307 if (key == key_info[i].key_default)
1308 joy |= key_info[i].action;
1313 if (key_status == KEY_PRESSED)
1314 key_joystick_mapping |= joy;
1316 key_joystick_mapping &= ~joy;
1321 if (game_status != GAME_MODE_PLAYING)
1322 key_joystick_mapping = 0;
1324 if (key_status == KEY_RELEASED)
1327 if ((key == KSYM_F11 ||
1328 ((key == KSYM_Return ||
1329 key == KSYM_KP_Enter) && (GetKeyModState() & KMOD_Alt))) &&
1330 video.fullscreen_available)
1332 setup.fullscreen = !setup.fullscreen;
1334 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1336 if (game_status == GAME_MODE_SETUP)
1337 RedrawSetupScreenAfterFullscreenToggle();
1342 if ((key == KSYM_minus ||
1345 ((GetKeyModState() & KMOD_Control) ||
1346 (GetKeyModState() & KMOD_Alt)) &&
1347 video.window_scaling_available &&
1348 !video.fullscreen_enabled)
1351 setup.window_scaling_percent = STD_WINDOW_SCALING_PERCENT;
1353 setup.window_scaling_percent +=
1354 (key == KSYM_minus ? -1 : +1) * STEP_WINDOW_SCALING_PERCENT;
1356 if (setup.window_scaling_percent < MIN_WINDOW_SCALING_PERCENT)
1357 setup.window_scaling_percent = MIN_WINDOW_SCALING_PERCENT;
1358 else if (setup.window_scaling_percent > MAX_WINDOW_SCALING_PERCENT)
1359 setup.window_scaling_percent = MAX_WINDOW_SCALING_PERCENT;
1361 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1363 if (game_status == GAME_MODE_SETUP)
1364 RedrawSetupScreenAfterFullscreenToggle();
1369 if (game_status == GAME_MODE_PLAYING && AllPlayersGone &&
1370 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
1377 if (game_status == GAME_MODE_MAIN &&
1378 (key == setup.shortcut.toggle_pause || key == KSYM_space))
1380 StartGameActions(options.network, setup.autorecord, level.random_seed);
1385 if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING)
1387 if (key == setup.shortcut.save_game)
1389 else if (key == setup.shortcut.load_game)
1391 else if (key == setup.shortcut.toggle_pause)
1392 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1394 HandleTapeButtonKeys(key);
1395 HandleSoundButtonKeys(key);
1398 if (game_status == GAME_MODE_PLAYING && !network_playing)
1400 int centered_player_nr_next = -999;
1402 if (key == setup.shortcut.focus_player_all)
1403 centered_player_nr_next = -1;
1405 for (i = 0; i < MAX_PLAYERS; i++)
1406 if (key == setup.shortcut.focus_player[i])
1407 centered_player_nr_next = i;
1409 if (centered_player_nr_next != -999)
1411 game.centered_player_nr_next = centered_player_nr_next;
1412 game.set_centered_player = TRUE;
1416 tape.centered_player_nr_next = game.centered_player_nr_next;
1417 tape.set_centered_player = TRUE;
1422 HandleKeysSpecial(key);
1424 if (HandleGadgetsKeyInput(key))
1426 if (key != KSYM_Escape) /* always allow ESC key to be handled */
1427 key = KSYM_UNDEFINED;
1430 switch (game_status)
1432 case GAME_MODE_PSEUDO_TYPENAME:
1433 HandleTypeName(0, key);
1436 case GAME_MODE_TITLE:
1437 case GAME_MODE_MAIN:
1438 case GAME_MODE_LEVELS:
1439 case GAME_MODE_LEVELNR:
1440 case GAME_MODE_SETUP:
1441 case GAME_MODE_INFO:
1442 case GAME_MODE_SCORES:
1447 if (game_status == GAME_MODE_TITLE)
1448 HandleTitleScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1449 else if (game_status == GAME_MODE_MAIN)
1450 HandleMainMenu(0, 0, 0, 0, MB_MENU_CHOICE);
1451 else if (game_status == GAME_MODE_LEVELS)
1452 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_CHOICE);
1453 else if (game_status == GAME_MODE_LEVELNR)
1454 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_CHOICE);
1455 else if (game_status == GAME_MODE_SETUP)
1456 HandleSetupScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1457 else if (game_status == GAME_MODE_INFO)
1458 HandleInfoScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1459 else if (game_status == GAME_MODE_SCORES)
1460 HandleHallOfFame(0, 0, 0, 0, MB_MENU_CHOICE);
1464 if (game_status != GAME_MODE_MAIN)
1465 FadeSkipNextFadeIn();
1467 if (game_status == GAME_MODE_TITLE)
1468 HandleTitleScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1469 else if (game_status == GAME_MODE_LEVELS)
1470 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_LEAVE);
1471 else if (game_status == GAME_MODE_LEVELNR)
1472 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_LEAVE);
1473 else if (game_status == GAME_MODE_SETUP)
1474 HandleSetupScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1475 else if (game_status == GAME_MODE_INFO)
1476 HandleInfoScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1477 else if (game_status == GAME_MODE_SCORES)
1478 HandleHallOfFame(0, 0, 0, 0, MB_MENU_LEAVE);
1482 if (game_status == GAME_MODE_LEVELS)
1483 HandleChooseLevelSet(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1484 else if (game_status == GAME_MODE_LEVELNR)
1485 HandleChooseLevelNr(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1486 else if (game_status == GAME_MODE_SETUP)
1487 HandleSetupScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1488 else if (game_status == GAME_MODE_INFO)
1489 HandleInfoScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1490 else if (game_status == GAME_MODE_SCORES)
1491 HandleHallOfFame(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1494 case KSYM_Page_Down:
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);
1509 GameFrameDelay = (GameFrameDelay == 500 ? GAME_FRAME_DELAY : 500);
1513 setup.sp_show_border_elements = !setup.sp_show_border_elements;
1514 printf("Supaplex border elements %s\n",
1515 setup.sp_show_border_elements ? "enabled" : "disabled");
1524 case GAME_MODE_EDITOR:
1525 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
1526 HandleLevelEditorKeyInput(key);
1529 case GAME_MODE_PLAYING:
1534 RequestQuitGame(setup.ask_on_escape);
1541 if (GameFrameDelay == 500)
1542 GameFrameDelay = GAME_FRAME_DELAY;
1544 GameFrameDelay = 500;
1547 GameFrameDelay = (key - KSYM_0) * 10;
1548 printf("Game speed == %d%% (%d ms delay between two frames)\n",
1549 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
1555 options.debug = FALSE;
1556 printf("debug mode disabled\n");
1560 options.debug = TRUE;
1561 printf("debug mode enabled\n");
1566 printf("::: currently using game engine version %d\n",
1567 game.engine_version);
1578 if (key == KSYM_Escape)
1580 SetGameStatus(GAME_MODE_MAIN);
1589 void HandleNoEvent()
1591 // if (button_status && game_status != GAME_MODE_PLAYING)
1592 if (button_status && (game_status != GAME_MODE_PLAYING || tape.pausing))
1594 HandleButton(0, 0, -button_status, button_status);
1601 #if defined(NETWORK_AVALIABLE)
1602 if (options.network)
1606 switch (game_status)
1608 case GAME_MODE_MAIN:
1609 DrawPreviewLevelAnimation();
1613 case GAME_MODE_LEVELS:
1614 case GAME_MODE_LEVELNR:
1615 case GAME_MODE_SETUP:
1616 case GAME_MODE_INFO:
1617 case GAME_MODE_SCORES:
1621 case GAME_MODE_EDITOR:
1622 HandleLevelEditorIdle();
1630 static int HandleJoystickForAllPlayers()
1635 for (i = 0; i < MAX_PLAYERS; i++)
1637 byte joy_action = 0;
1640 if (!setup.input[i].use_joystick)
1644 joy_action = Joystick(i);
1645 result |= joy_action;
1647 if (!setup.input[i].use_joystick)
1650 stored_player[i].action = joy_action;
1656 void HandleJoystick()
1658 int joystick = HandleJoystickForAllPlayers();
1659 int keyboard = key_joystick_mapping;
1660 int joy = (joystick | keyboard);
1661 int left = joy & JOY_LEFT;
1662 int right = joy & JOY_RIGHT;
1663 int up = joy & JOY_UP;
1664 int down = joy & JOY_DOWN;
1665 int button = joy & JOY_BUTTON;
1666 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
1667 int dx = (left ? -1 : right ? 1 : 0);
1668 int dy = (up ? -1 : down ? 1 : 0);
1670 switch (game_status)
1672 case GAME_MODE_TITLE:
1673 case GAME_MODE_MAIN:
1674 case GAME_MODE_LEVELS:
1675 case GAME_MODE_LEVELNR:
1676 case GAME_MODE_SETUP:
1677 case GAME_MODE_INFO:
1679 static unsigned int joystickmove_delay = 0;
1681 if (joystick && !button &&
1682 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
1683 newbutton = dx = dy = 0;
1685 if (game_status == GAME_MODE_TITLE)
1686 HandleTitleScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1687 else if (game_status == GAME_MODE_MAIN)
1688 HandleMainMenu(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1689 else if (game_status == GAME_MODE_LEVELS)
1690 HandleChooseLevelSet(0,0,dx,dy,newbutton?MB_MENU_CHOICE : MB_MENU_MARK);
1691 else if (game_status == GAME_MODE_LEVELNR)
1692 HandleChooseLevelNr(0,0,dx,dy,newbutton? MB_MENU_CHOICE : MB_MENU_MARK);
1693 else if (game_status == GAME_MODE_SETUP)
1694 HandleSetupScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1695 else if (game_status == GAME_MODE_INFO)
1696 HandleInfoScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1700 case GAME_MODE_SCORES:
1701 HandleHallOfFame(0, 0, dx, dy, !newbutton);
1704 case GAME_MODE_PLAYING:
1705 if (tape.playing || keyboard)
1706 newbutton = ((joy & JOY_BUTTON) != 0);
1708 if (newbutton && AllPlayersGone)