1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
27 #define DEBUG_EVENTS 0
30 static boolean cursor_inside_playfield = FALSE;
31 static boolean playfield_cursor_set = FALSE;
32 static unsigned int playfield_cursor_delay = 0;
35 /* event filter especially needed for SDL event filtering due to
36 delay problems with lots of mouse motion events when mouse button
37 not pressed (X11 can handle this with 'PointerMotionHintMask') */
39 /* event filter addition for SDL2: as SDL2 does not have a function to enable
40 or disable keyboard auto-repeat, filter repeated keyboard events instead */
42 static int FilterEventsExt(const Event *event)
46 #if defined(TARGET_SDL2)
47 /* skip repeated key press events if keyboard auto-repeat is disabled */
48 if (event->type == EVENT_KEYPRESS &&
54 /* non-motion events are directly passed to event handler functions */
55 if (event->type != EVENT_MOTIONNOTIFY)
58 motion = (MotionEvent *)event;
59 cursor_inside_playfield = (motion->x >= SX && motion->x < SX + SXSIZE &&
60 motion->y >= SY && motion->y < SY + SYSIZE);
62 if (game_status == GAME_MODE_PLAYING && playfield_cursor_set)
64 SetMouseCursor(CURSOR_DEFAULT);
65 playfield_cursor_set = FALSE;
66 DelayReached(&playfield_cursor_delay, 0);
69 /* skip mouse motion events without pressed button outside level editor */
70 if (button_status == MB_RELEASED &&
71 game_status != GAME_MODE_EDITOR && game_status != GAME_MODE_PLAYING)
77 #if defined(TARGET_SDL2)
78 int FilterEvents(void *userdata, Event *event)
80 return FilterEventsExt(event);
83 int FilterEvents(const Event *event)
85 return FilterEventsExt(event);
89 /* to prevent delay problems, skip mouse motion events if the very next
90 event is also a mouse motion event (and therefore effectively only
91 handling the last of a row of mouse motion events in the event queue) */
93 boolean SkipPressedMouseMotionEvent(const Event *event)
95 /* nothing to do if the current event is not a mouse motion event */
96 if (event->type != EVENT_MOTIONNOTIFY)
99 /* only skip motion events with pressed button outside level editor */
100 if (button_status == MB_RELEASED ||
101 game_status == GAME_MODE_EDITOR || game_status == GAME_MODE_PLAYING)
108 PeekEvent(&next_event);
110 /* if next event is also a mouse motion event, skip the current one */
111 if (next_event.type == EVENT_MOTIONNOTIFY)
118 /* this is only really needed for non-SDL targets to filter unwanted events;
119 when using SDL with properly installed event filter, this function can be
120 replaced with a simple "NextEvent()" call, but it doesn't hurt either */
122 static boolean NextValidEvent(Event *event)
124 while (PendingEvent())
126 boolean handle_this_event = FALSE;
130 if (FilterEventsExt(event))
131 handle_this_event = TRUE;
133 if (SkipPressedMouseMotionEvent(event))
134 handle_this_event = FALSE;
136 if (handle_this_event)
147 if (PendingEvent()) /* got event */
151 while (NextValidEvent(&event))
155 case EVENT_BUTTONPRESS:
156 case EVENT_BUTTONRELEASE:
157 HandleButtonEvent((ButtonEvent *) &event);
160 case EVENT_MOTIONNOTIFY:
161 HandleMotionEvent((MotionEvent *) &event);
164 #if defined(TARGET_SDL2)
165 case SDL_WINDOWEVENT:
166 HandleWindowEvent((WindowEvent *) &event);
169 case EVENT_FINGERPRESS:
170 case EVENT_FINGERRELEASE:
171 case EVENT_FINGERMOTION:
172 HandleFingerEvent((FingerEvent *) &event);
175 case EVENT_TEXTINPUT:
176 HandleTextEvent((TextEvent *) &event);
181 case EVENT_KEYRELEASE:
182 HandleKeyEvent((KeyEvent *) &event);
186 HandleOtherEvents(&event);
193 /* when playing, display a special mouse pointer inside the playfield */
194 if (game_status == GAME_MODE_PLAYING && !tape.pausing)
196 if (!playfield_cursor_set && cursor_inside_playfield &&
197 DelayReached(&playfield_cursor_delay, 1000))
199 SetMouseCursor(CURSOR_PLAYFIELD);
200 playfield_cursor_set = TRUE;
203 else if (playfield_cursor_set)
205 SetMouseCursor(CURSOR_DEFAULT);
206 playfield_cursor_set = FALSE;
218 /* don't use all CPU time when idle; the main loop while playing
219 has its own synchronization and is CPU friendly, too */
221 if (game_status == GAME_MODE_PLAYING)
228 if (!PendingEvent()) /* delay only if no pending events */
232 /* refresh window contents from drawing buffer, if needed */
235 if (game_status == GAME_MODE_QUIT)
240 void HandleOtherEvents(Event *event)
245 HandleExposeEvent((ExposeEvent *) event);
248 case EVENT_UNMAPNOTIFY:
250 /* This causes the game to stop not only when iconified, but also
251 when on another virtual desktop, which might be not desired. */
252 SleepWhileUnmapped();
258 HandleFocusEvent((FocusChangeEvent *) event);
261 case EVENT_CLIENTMESSAGE:
262 HandleClientMessageEvent((ClientMessageEvent *) event);
265 #if defined(TARGET_SDL)
266 case SDL_JOYAXISMOTION:
267 case SDL_JOYBUTTONDOWN:
268 case SDL_JOYBUTTONUP:
269 HandleJoystickEvent(event);
273 HandleWindowManagerEvent(event);
282 void ClearEventQueue()
284 while (PendingEvent())
292 case EVENT_BUTTONRELEASE:
293 button_status = MB_RELEASED;
296 case EVENT_KEYRELEASE:
300 key_joystick_mapping = 0;
305 HandleOtherEvents(&event);
311 void ClearPlayerAction()
315 /* simulate key release events for still pressed keys */
316 key_joystick_mapping = 0;
317 for (i = 0; i < MAX_PLAYERS; i++)
318 stored_player[i].action = 0;
321 void SleepWhileUnmapped()
323 boolean window_unmapped = TRUE;
325 KeyboardAutoRepeatOn();
327 while (window_unmapped)
335 case EVENT_BUTTONRELEASE:
336 button_status = MB_RELEASED;
339 case EVENT_KEYRELEASE:
340 key_joystick_mapping = 0;
343 case EVENT_MAPNOTIFY:
344 window_unmapped = FALSE;
347 case EVENT_UNMAPNOTIFY:
348 /* this is only to surely prevent the 'should not happen' case
349 * of recursively looping between 'SleepWhileUnmapped()' and
350 * 'HandleOtherEvents()' which usually calls this funtion.
355 HandleOtherEvents(&event);
360 if (game_status == GAME_MODE_PLAYING)
361 KeyboardAutoRepeatOffUnlessAutoplay();
364 void HandleExposeEvent(ExposeEvent *event)
366 #if !defined(TARGET_SDL)
367 RedrawPlayfield(FALSE, event->x, event->y, event->width, event->height);
372 void HandleButtonEvent(ButtonEvent *event)
375 Error(ERR_DEBUG, "BUTTON EVENT: button %d %s, x/y %d/%d\n",
377 event->type == EVENT_BUTTONPRESS ? "pressed" : "released",
381 motion_status = FALSE;
383 if (event->type == EVENT_BUTTONPRESS)
384 button_status = event->button;
386 button_status = MB_RELEASED;
388 HandleButton(event->x, event->y, button_status, event->button);
391 void HandleMotionEvent(MotionEvent *event)
393 if (!PointerInWindow(window))
394 return; /* window and pointer are on different screens */
396 if (button_status == MB_RELEASED && game_status != GAME_MODE_EDITOR)
399 motion_status = TRUE;
402 Error(ERR_DEBUG, "MOTION EVENT: button %d moved, x/y %d/%d\n",
403 button_status, event->x, event->y);
406 HandleButton(event->x, event->y, button_status, button_status);
409 #if defined(TARGET_SDL2)
410 void HandleWindowEvent(WindowEvent *event)
413 int subtype = event->event;
416 (subtype == SDL_WINDOWEVENT_SHOWN ? "SDL_WINDOWEVENT_SHOWN" :
417 subtype == SDL_WINDOWEVENT_HIDDEN ? "SDL_WINDOWEVENT_HIDDEN" :
418 subtype == SDL_WINDOWEVENT_EXPOSED ? "SDL_WINDOWEVENT_EXPOSED" :
419 subtype == SDL_WINDOWEVENT_MOVED ? "SDL_WINDOWEVENT_MOVED" :
420 subtype == SDL_WINDOWEVENT_SIZE_CHANGED ? "SDL_WINDOWEVENT_SIZE_CHANGED" :
421 subtype == SDL_WINDOWEVENT_RESIZED ? "SDL_WINDOWEVENT_RESIZED" :
422 subtype == SDL_WINDOWEVENT_MINIMIZED ? "SDL_WINDOWEVENT_MINIMIZED" :
423 subtype == SDL_WINDOWEVENT_MAXIMIZED ? "SDL_WINDOWEVENT_MAXIMIZED" :
424 subtype == SDL_WINDOWEVENT_RESTORED ? "SDL_WINDOWEVENT_RESTORED" :
425 subtype == SDL_WINDOWEVENT_ENTER ? "SDL_WINDOWEVENT_ENTER" :
426 subtype == SDL_WINDOWEVENT_LEAVE ? "SDL_WINDOWEVENT_LEAVE" :
427 subtype == SDL_WINDOWEVENT_FOCUS_GAINED ? "SDL_WINDOWEVENT_FOCUS_GAINED" :
428 subtype == SDL_WINDOWEVENT_FOCUS_LOST ? "SDL_WINDOWEVENT_FOCUS_LOST" :
429 subtype == SDL_WINDOWEVENT_CLOSE ? "SDL_WINDOWEVENT_CLOSE" :
432 Error(ERR_DEBUG, "WINDOW EVENT: '%s', %ld, %ld",
433 event_name, event->data1, event->data2);
436 if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED ||
437 event->event == SDL_WINDOWEVENT_RESIZED ||
438 event->event == SDL_WINDOWEVENT_EXPOSED)
442 if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED)
444 // if game started in fullscreen mode, window will also get fullscreen size
445 if (!video.fullscreen_enabled && video.fullscreen_initial)
447 SDLSetWindowScaling(setup.window_scaling_percent);
449 // only do this correction once
450 video.fullscreen_initial = FALSE;
455 if (event->event == SDL_WINDOWEVENT_RESIZED && !video.fullscreen_enabled)
458 int new_window_width = event->data1;
459 int new_window_height = event->data2;
461 // if window size has changed after resizing, calculate new scaling factor
462 if (new_window_width != video.window_width ||
463 new_window_height != video.window_height)
465 int new_xpercent = (100 * new_window_width / video.width);
466 int new_ypercent = (100 * new_window_height / video.height);
468 printf("::: RESIZED from %d, %d to %d, %d\n",
469 video.window_width, video.window_height,
470 new_window_width, new_window_height);
472 setup.window_scaling_percent = video.window_scaling_percent =
473 MIN(MAX(MIN_WINDOW_SCALING_PERCENT, MIN(new_xpercent, new_ypercent)),
474 MAX_WINDOW_SCALING_PERCENT);
476 video.window_width = new_window_width;
477 video.window_height = new_window_height;
479 printf("::: setup.window_scaling_percent set to %d\n",
480 setup.window_scaling_percent);
482 if (game_status == GAME_MODE_SETUP)
483 RedrawSetupScreenAfterFullscreenToggle();
486 // prevent slightly wrong scaling factor due to rounding differences
487 float scaling_factor = (float)setup.window_scaling_percent / 100;
488 int old_xsize = (int)(scaling_factor * video.width);
489 int old_ysize = (int)(scaling_factor * video.height);
490 int new_xsize = event->data1;
491 int new_ysize = event->data2;
493 // window size is unchanged when going from fullscreen to window mode,
494 // but reverse calculation of scaling factor might result in a scaling
495 // factor that is slightly different due to rounding differences;
496 // therefore compare old/new window size and not old/new scaling factor
497 if (old_xsize != new_xsize ||
498 old_ysize != new_ysize)
500 int new_xpercent = (100 * new_xsize / video.width);
501 int new_ypercent = (100 * new_ysize / video.height);
503 setup.window_scaling_percent = MIN(new_xpercent, new_ypercent);
505 if (setup.window_scaling_percent < MIN_WINDOW_SCALING_PERCENT)
506 setup.window_scaling_percent = MIN_WINDOW_SCALING_PERCENT;
507 else if (setup.window_scaling_percent > MAX_WINDOW_SCALING_PERCENT)
508 setup.window_scaling_percent = MAX_WINDOW_SCALING_PERCENT;
510 printf("::: setup.window_scaling_percent set to %d\n",
511 setup.window_scaling_percent);
519 #define NUM_TOUCH_FINGERS 3
523 SDL_FingerID finger_id;
526 } touch_info[NUM_TOUCH_FINGERS];
528 void HandleFingerEvent(FingerEvent *event)
530 static Key motion_key_x = KSYM_UNDEFINED;
531 static Key motion_key_y = KSYM_UNDEFINED;
532 static Key button_key = KSYM_UNDEFINED;
533 static float motion_x1, motion_y1;
534 static float button_x1, button_y1;
535 static SDL_FingerID motion_id = 0;
536 static SDL_FingerID button_id = 0;
537 int trigger_distance_percent = 1; // percent of touchpad width/height
538 float trigger_distance = (float)trigger_distance_percent / 100;
539 float event_x = event->x;
540 float event_y = event->y;
544 Error(ERR_DEBUG, "FINGER EVENT: finger was %s, touch ID %lld, finger ID %lld, x/y %f/%f, dx/dy %f/%f, pressure %f",
545 event->type == EVENT_FINGERPRESS ? "pressed" :
546 event->type == EVENT_FINGERRELEASE ? "released" : "moved",
550 event->dx, event->dy,
555 if (game_status != GAME_MODE_PLAYING)
560 int key_status = (event->type == EVENT_FINGERRELEASE ? KEY_RELEASED :
563 Key key = (event->x < 1.0 / 3.0 ?
564 (event->y < 1.0 / 2.0 ? setup.input[0].key.snap :
565 setup.input[0].key.drop) :
566 event->x > 2.0 / 3.0 ?
567 (event->y < 1.0 / 3.0 ? setup.input[0].key.up :
568 event->y > 2.0 / 3.0 ? setup.input[0].key.down :
569 event->x < 5.0 / 6.0 ? setup.input[0].key.left :
570 setup.input[0].key.right) :
573 Key key = (event->y < 1.0 / 3.0 ? setup.input[0].key.up :
574 event->y > 2.0 / 3.0 ? setup.input[0].key.down :
575 event->x < 1.0 / 3.0 ? setup.input[0].key.left :
576 event->x > 2.0 / 3.0 ? setup.input[0].key.right :
577 setup.input[0].key.snap);
581 // check if we already know this touch event's finger id
582 for (i = 0; i < NUM_TOUCH_FINGERS; i++)
584 if (touch_info[i].finger_id == event->fingerId)
588 if (i >= NUM_TOUCH_FINGERS)
590 if (key_status == KEY_PRESSED)
592 int oldest_pos = 0, oldest_counter = touch_info[0].counter;
594 // unknown finger id -- get new, empty slot, if available
595 for (i = 0; i < NUM_TOUCH_FINGERS; i++)
597 if (touch_info[i].counter < oldest_counter)
600 oldest_counter = touch_info[i].counter;
603 if (touch_info[i].finger_id == 0)
607 if (i >= NUM_TOUCH_FINGERS)
609 // all slots allocated -- use oldest slot
615 // release of previously unknown key (should not happen)
617 if (key != KSYM_UNDEFINED)
618 HandleKey(key, KEY_RELEASED);
622 if (i < NUM_TOUCH_FINGERS)
624 if (key_status == KEY_PRESSED)
626 if (touch_info[i].key != key)
628 if (touch_info[i].key != KSYM_UNDEFINED)
629 HandleKey(touch_info[i].key, KEY_RELEASED);
631 if (key != KSYM_UNDEFINED)
632 HandleKey(key, KEY_PRESSED);
635 touch_info[i].finger_id = event->fingerId;
636 touch_info[i].counter = Counter();
637 touch_info[i].key = key;
641 if (touch_info[i].key != KSYM_UNDEFINED)
642 HandleKey(touch_info[i].key, KEY_RELEASED);
644 touch_info[i].finger_id = 0;
645 touch_info[i].counter = 0;
646 touch_info[i].key = 0;
650 Error(ERR_DEBUG, "=> key == %d, key_status == %d", key, key_status);
655 if (event->type == EVENT_FINGERPRESS)
657 if (event_x > 1.0 / 3.0)
661 motion_id = event->fingerId;
666 motion_key_x = KSYM_UNDEFINED;
667 motion_key_y = KSYM_UNDEFINED;
669 Error(ERR_DEBUG, "---------- MOVE STARTED (WAIT) ----------");
675 button_id = event->fingerId;
680 button_key = setup.input[0].key.snap;
682 HandleKey(button_key, KEY_PRESSED);
684 Error(ERR_DEBUG, "---------- SNAP STARTED ----------");
687 else if (event->type == EVENT_FINGERRELEASE)
689 if (event->fingerId == motion_id)
693 if (motion_key_x != KSYM_UNDEFINED)
694 HandleKey(motion_key_x, KEY_RELEASED);
695 if (motion_key_y != KSYM_UNDEFINED)
696 HandleKey(motion_key_y, KEY_RELEASED);
698 motion_key_x = KSYM_UNDEFINED;
699 motion_key_y = KSYM_UNDEFINED;
701 Error(ERR_DEBUG, "---------- MOVE STOPPED ----------");
703 else if (event->fingerId == button_id)
707 if (button_key != KSYM_UNDEFINED)
708 HandleKey(button_key, KEY_RELEASED);
710 button_key = KSYM_UNDEFINED;
712 Error(ERR_DEBUG, "---------- SNAP STOPPED ----------");
715 else if (event->type == EVENT_FINGERMOTION)
717 if (event->fingerId == motion_id)
719 float distance_x = ABS(event_x - motion_x1);
720 float distance_y = ABS(event_y - motion_y1);
721 Key new_motion_key_x = (event_x < motion_x1 ? setup.input[0].key.left :
722 event_x > motion_x1 ? setup.input[0].key.right :
724 Key new_motion_key_y = (event_y < motion_y1 ? setup.input[0].key.up :
725 event_y > motion_y1 ? setup.input[0].key.down :
728 if (distance_x < trigger_distance / 2 ||
729 distance_x < distance_y)
730 new_motion_key_x = KSYM_UNDEFINED;
732 if (distance_y < trigger_distance / 2 ||
733 distance_y < distance_x)
734 new_motion_key_y = KSYM_UNDEFINED;
736 if (distance_x > trigger_distance ||
737 distance_y > trigger_distance)
739 if (new_motion_key_x != motion_key_x)
741 if (motion_key_x != KSYM_UNDEFINED)
742 HandleKey(motion_key_x, KEY_RELEASED);
743 if (new_motion_key_x != KSYM_UNDEFINED)
744 HandleKey(new_motion_key_x, KEY_PRESSED);
747 if (new_motion_key_y != motion_key_y)
749 if (motion_key_y != KSYM_UNDEFINED)
750 HandleKey(motion_key_y, KEY_RELEASED);
751 if (new_motion_key_y != KSYM_UNDEFINED)
752 HandleKey(new_motion_key_y, KEY_PRESSED);
758 motion_key_x = new_motion_key_x;
759 motion_key_y = new_motion_key_y;
761 Error(ERR_DEBUG, "---------- MOVE STARTED (MOVE) ----------");
764 else if (event->fingerId == button_id)
766 float distance_x = ABS(event_x - button_x1);
767 float distance_y = ABS(event_y - button_y1);
769 if (distance_x < trigger_distance / 2 &&
770 distance_y > trigger_distance)
772 if (button_key == setup.input[0].key.snap)
773 HandleKey(button_key, KEY_RELEASED);
778 button_key = setup.input[0].key.drop;
780 HandleKey(button_key, KEY_PRESSED);
782 Error(ERR_DEBUG, "---------- DROP STARTED ----------");
790 void HandleFingerEvent(FingerEvent *event)
793 static int num_events = 0;
799 Error(ERR_DEBUG, "FINGER EVENT: finger was %s, touch ID %lld, finger ID %lld, x/y %f/%f, dx/dy %f/%f, pressure %f",
800 event->type == EVENT_FINGERPRESS ? "pressed" :
801 event->type == EVENT_FINGERRELEASE ? "released" : "moved",
805 event->dx, event->dy,
811 int x = (int)(event->x * video.width);
812 int y = (int)(event->y * video.height);
813 int button = MB_LEFTBUTTON;
815 Error(ERR_DEBUG, "=> screen x/y %d/%d", x, y);
819 if (++num_events >= max_events)
825 if (event->type == EVENT_FINGERPRESS ||
826 event->type == EVENT_FINGERMOTION)
827 button_status = button;
829 button_status = MB_RELEASED;
831 int max_x = SX + SXSIZE;
832 int max_y = SY + SYSIZE;
836 if (game_status == GAME_MODE_PLAYING)
838 if (game_status == GAME_MODE_PLAYING &&
842 int key_status = (event->type == EVENT_FINGERRELEASE ? KEY_RELEASED :
845 Key key = (event->y < 1.0 / 3.0 ? setup.input[0].key.up :
846 event->y > 2.0 / 3.0 ? setup.input[0].key.down :
847 event->x < 1.0 / 3.0 ? setup.input[0].key.left :
848 event->x > 2.0 / 3.0 ? setup.input[0].key.right :
849 setup.input[0].key.drop);
851 Key key = (y < max_y / 3 ? setup.input[0].key.up :
852 y > 2 * max_y / 3 ? setup.input[0].key.down :
853 x < max_x / 3 ? setup.input[0].key.left :
854 x > 2 * max_x / 3 ? setup.input[0].key.right :
855 setup.input[0].key.drop);
858 Error(ERR_DEBUG, "=> key == %d, key_status == %d", key, key_status);
860 HandleKey(key, key_status);
865 Error(ERR_DEBUG, "::: button_status == %d, button == %d\n",
866 button_status, button);
868 HandleButton(x, y, button_status, button);
876 static boolean checkTextInputKeyModState()
878 // when playing, only handle raw key events and ignore text input
879 if (game_status == GAME_MODE_PLAYING)
882 return ((GetKeyModState() & KMOD_TextInput) != KMOD_None);
885 void HandleTextEvent(TextEvent *event)
887 char *text = event->text;
888 Key key = getKeyFromKeyName(text);
891 Error(ERR_DEBUG, "TEXT EVENT: text == '%s' [%d byte(s), '%c'/%d], resulting key == %d (%s) [%04x]",
894 text[0], (int)(text[0]),
896 getKeyNameFromKey(key),
900 // if (game_status != GAME_MODE_PLAYING && GetKeyModState() != KMOD_None)
902 if (game_status != GAME_MODE_PLAYING &&
903 (GetKeyModState() & KMOD_TextInput) != KMOD_None)
905 if (checkTextInputKeyModState())
907 HandleKey(key, KEY_PRESSED);
908 HandleKey(key, KEY_RELEASED);
913 void HandleKeyEvent(KeyEvent *event)
915 int key_status = (event->type == EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
916 boolean with_modifiers = (game_status == GAME_MODE_PLAYING ? FALSE : TRUE);
917 Key key = GetEventKey(event, with_modifiers);
918 Key keymod = (with_modifiers ? GetEventKey(event, FALSE) : key);
921 Error(ERR_DEBUG, "KEY EVENT: key was %s, keysym.scancode == %d, keysym.sym == %d, keymod = %d, GetKeyModState() = 0x%04x, resulting key == %d (%s)",
922 event->type == EVENT_KEYPRESS ? "pressed" : "released",
923 event->keysym.scancode,
928 getKeyNameFromKey(key));
932 if (key == KSYM_Menu)
933 Error(ERR_DEBUG, "menu key pressed");
934 else if (key == KSYM_Back)
935 Error(ERR_DEBUG, "back key pressed");
938 #if defined(PLATFORM_ANDROID)
939 // always map the "back" button to the "escape" key on Android devices
940 if (key == KSYM_Back)
944 HandleKeyModState(keymod, key_status);
946 #if defined(TARGET_SDL2)
948 // if (game_status == GAME_MODE_PLAYING || GetKeyModState() == KMOD_None)
950 if (game_status == GAME_MODE_PLAYING ||
951 (GetKeyModState() & KMOD_TextInput) == KMOD_None)
953 if (!checkTextInputKeyModState())
954 HandleKey(key, key_status);
956 HandleKey(key, key_status);
960 void HandleFocusEvent(FocusChangeEvent *event)
962 static int old_joystick_status = -1;
964 if (event->type == EVENT_FOCUSOUT)
966 KeyboardAutoRepeatOn();
967 old_joystick_status = joystick.status;
968 joystick.status = JOYSTICK_NOT_AVAILABLE;
972 else if (event->type == EVENT_FOCUSIN)
974 /* When there are two Rocks'n'Diamonds windows which overlap and
975 the player moves the pointer from one game window to the other,
976 a 'FocusOut' event is generated for the window the pointer is
977 leaving and a 'FocusIn' event is generated for the window the
978 pointer is entering. In some cases, it can happen that the
979 'FocusIn' event is handled by the one game process before the
980 'FocusOut' event by the other game process. In this case the
981 X11 environment would end up with activated keyboard auto repeat,
982 because unfortunately this is a global setting and not (which
983 would be far better) set for each X11 window individually.
984 The effect would be keyboard auto repeat while playing the game
985 (game_status == GAME_MODE_PLAYING), which is not desired.
986 To avoid this special case, we just wait 1/10 second before
987 processing the 'FocusIn' event.
990 if (game_status == GAME_MODE_PLAYING)
993 KeyboardAutoRepeatOffUnlessAutoplay();
996 if (old_joystick_status != -1)
997 joystick.status = old_joystick_status;
1001 void HandleClientMessageEvent(ClientMessageEvent *event)
1003 if (CheckCloseWindowEvent(event))
1007 void HandleWindowManagerEvent(Event *event)
1009 #if defined(TARGET_SDL)
1010 SDLHandleWindowManagerEvent(event);
1014 void HandleButton(int mx, int my, int button, int button_nr)
1016 static int old_mx = 0, old_my = 0;
1030 if (HandleGadgets(mx, my, button))
1032 /* do not handle this button event anymore */
1033 mx = my = -32; /* force mouse event to be outside screen tiles */
1036 /* do not use scroll wheel button events for anything other than gadgets */
1037 if (IS_WHEEL_BUTTON(button_nr))
1041 Error(ERR_DEBUG, "::: game_status == %d", game_status);
1044 switch (game_status)
1046 case GAME_MODE_TITLE:
1047 HandleTitleScreen(mx, my, 0, 0, button);
1050 case GAME_MODE_MAIN:
1051 HandleMainMenu(mx, my, 0, 0, button);
1054 case GAME_MODE_PSEUDO_TYPENAME:
1055 HandleTypeName(0, KSYM_Return);
1058 case GAME_MODE_LEVELS:
1059 HandleChooseLevelSet(mx, my, 0, 0, button);
1062 case GAME_MODE_LEVELNR:
1063 HandleChooseLevelNr(mx, my, 0, 0, button);
1066 case GAME_MODE_SCORES:
1067 HandleHallOfFame(0, 0, 0, 0, button);
1070 case GAME_MODE_EDITOR:
1071 HandleLevelEditorIdle();
1074 case GAME_MODE_INFO:
1075 HandleInfoScreen(mx, my, 0, 0, button);
1078 case GAME_MODE_SETUP:
1079 HandleSetupScreen(mx, my, 0, 0, button);
1082 case GAME_MODE_PLAYING:
1084 if (button == MB_PRESSED && !motion_status && IN_GFX_SCREEN(mx, my))
1085 DumpTile(LEVELX((mx - SX) / TILEX), LEVELY((my - SY) / TILEY));
1094 static boolean is_string_suffix(char *string, char *suffix)
1096 int string_len = strlen(string);
1097 int suffix_len = strlen(suffix);
1099 if (suffix_len > string_len)
1102 return (strEqual(&string[string_len - suffix_len], suffix));
1105 #define MAX_CHEAT_INPUT_LEN 32
1107 static void HandleKeysSpecial(Key key)
1109 static char cheat_input[2 * MAX_CHEAT_INPUT_LEN + 1] = "";
1110 char letter = getCharFromKey(key);
1111 int cheat_input_len = strlen(cheat_input);
1117 if (cheat_input_len >= 2 * MAX_CHEAT_INPUT_LEN)
1119 for (i = 0; i < MAX_CHEAT_INPUT_LEN + 1; i++)
1120 cheat_input[i] = cheat_input[MAX_CHEAT_INPUT_LEN + i];
1122 cheat_input_len = MAX_CHEAT_INPUT_LEN;
1125 cheat_input[cheat_input_len++] = letter;
1126 cheat_input[cheat_input_len] = '\0';
1129 Error(ERR_DEBUG, "SPECIAL KEY '%s' [%d]\n", cheat_input, cheat_input_len);
1132 if (game_status == GAME_MODE_MAIN)
1134 if (is_string_suffix(cheat_input, ":insert-solution-tape") ||
1135 is_string_suffix(cheat_input, ":ist"))
1137 InsertSolutionTape();
1139 else if (is_string_suffix(cheat_input, ":reload-graphics") ||
1140 is_string_suffix(cheat_input, ":rg"))
1142 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS);
1145 else if (is_string_suffix(cheat_input, ":reload-sounds") ||
1146 is_string_suffix(cheat_input, ":rs"))
1148 ReloadCustomArtwork(1 << ARTWORK_TYPE_SOUNDS);
1151 else if (is_string_suffix(cheat_input, ":reload-music") ||
1152 is_string_suffix(cheat_input, ":rm"))
1154 ReloadCustomArtwork(1 << ARTWORK_TYPE_MUSIC);
1157 else if (is_string_suffix(cheat_input, ":reload-artwork") ||
1158 is_string_suffix(cheat_input, ":ra"))
1160 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS |
1161 1 << ARTWORK_TYPE_SOUNDS |
1162 1 << ARTWORK_TYPE_MUSIC);
1165 else if (is_string_suffix(cheat_input, ":dump-level") ||
1166 is_string_suffix(cheat_input, ":dl"))
1170 else if (is_string_suffix(cheat_input, ":dump-tape") ||
1171 is_string_suffix(cheat_input, ":dt"))
1175 else if (is_string_suffix(cheat_input, ":save-native-level") ||
1176 is_string_suffix(cheat_input, ":snl"))
1178 SaveNativeLevel(&level);
1181 else if (game_status == GAME_MODE_PLAYING)
1184 if (is_string_suffix(cheat_input, ".q"))
1185 DEBUG_SetMaximumDynamite();
1188 else if (game_status == GAME_MODE_EDITOR)
1190 if (is_string_suffix(cheat_input, ":dump-brush") ||
1191 is_string_suffix(cheat_input, ":DB"))
1195 else if (is_string_suffix(cheat_input, ":DDB"))
1202 void HandleKey(Key key, int key_status)
1204 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
1205 static struct SetupKeyboardInfo ski;
1206 static struct SetupShortcutInfo ssi;
1215 { &ski.left, &ssi.snap_left, DEFAULT_KEY_LEFT, JOY_LEFT },
1216 { &ski.right, &ssi.snap_right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
1217 { &ski.up, &ssi.snap_up, DEFAULT_KEY_UP, JOY_UP },
1218 { &ski.down, &ssi.snap_down, DEFAULT_KEY_DOWN, JOY_DOWN },
1219 { &ski.snap, NULL, DEFAULT_KEY_SNAP, JOY_BUTTON_SNAP },
1220 { &ski.drop, NULL, DEFAULT_KEY_DROP, JOY_BUTTON_DROP }
1225 if (game_status == GAME_MODE_PLAYING)
1227 /* only needed for single-step tape recording mode */
1228 static boolean clear_snap_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1229 static boolean clear_drop_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1230 static boolean element_snapped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1231 static boolean element_dropped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1234 for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
1236 byte key_action = 0;
1238 if (setup.input[pnr].use_joystick)
1241 ski = setup.input[pnr].key;
1243 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1244 if (key == *key_info[i].key_custom)
1245 key_action |= key_info[i].action;
1247 /* use combined snap+direction keys for the first player only */
1250 ssi = setup.shortcut;
1252 for (i = 0; i < NUM_DIRECTIONS; i++)
1253 if (key == *key_info[i].key_snap)
1254 key_action |= key_info[i].action | JOY_BUTTON_SNAP;
1257 /* clear delayed snap and drop actions in single step mode (see below) */
1258 if (tape.single_step)
1260 if (clear_snap_button[pnr])
1262 stored_player[pnr].action &= ~KEY_BUTTON_SNAP;
1263 clear_snap_button[pnr] = FALSE;
1266 if (clear_drop_button[pnr])
1268 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1269 clear_drop_button[pnr] = FALSE;
1273 if (key_status == KEY_PRESSED)
1274 stored_player[pnr].action |= key_action;
1276 stored_player[pnr].action &= ~key_action;
1278 if (tape.single_step && tape.recording && tape.pausing)
1280 if (key_status == KEY_PRESSED && key_action & KEY_MOTION)
1282 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1284 /* if snap key already pressed, don't snap when releasing (below) */
1285 if (stored_player[pnr].action & KEY_BUTTON_SNAP)
1286 element_snapped[pnr] = TRUE;
1288 /* if drop key already pressed, don't drop when releasing (below) */
1289 if (stored_player[pnr].action & KEY_BUTTON_DROP)
1290 element_dropped[pnr] = TRUE;
1293 else if (key_status == KEY_PRESSED && key_action & KEY_BUTTON_DROP)
1295 if (level.game_engine_type == GAME_ENGINE_TYPE_EM ||
1296 level.game_engine_type == GAME_ENGINE_TYPE_SP)
1299 printf("::: drop key pressed\n");
1302 if (level.game_engine_type == GAME_ENGINE_TYPE_SP &&
1303 getRedDiskReleaseFlag_SP() == 0)
1304 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1306 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1310 else if (key_status == KEY_RELEASED && key_action & KEY_BUTTON)
1312 if (key_action & KEY_BUTTON_SNAP)
1314 /* if snap key was released without moving (see above), snap now */
1315 if (!element_snapped[pnr])
1317 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1319 stored_player[pnr].action |= KEY_BUTTON_SNAP;
1321 /* clear delayed snap button on next event */
1322 clear_snap_button[pnr] = TRUE;
1325 element_snapped[pnr] = FALSE;
1329 if (key_action & KEY_BUTTON_DROP &&
1330 level.game_engine_type == GAME_ENGINE_TYPE_RND)
1332 /* if drop key was released without moving (see above), drop now */
1333 if (!element_dropped[pnr])
1335 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1337 if (level.game_engine_type != GAME_ENGINE_TYPE_SP ||
1338 getRedDiskReleaseFlag_SP() != 0)
1339 stored_player[pnr].action |= KEY_BUTTON_DROP;
1341 /* clear delayed drop button on next event */
1342 clear_drop_button[pnr] = TRUE;
1345 element_dropped[pnr] = FALSE;
1350 else if (tape.recording && tape.pausing)
1352 /* prevent key release events from un-pausing a paused game */
1353 if (key_status == KEY_PRESSED && key_action & KEY_ACTION)
1354 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1360 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1361 if (key == key_info[i].key_default)
1362 joy |= key_info[i].action;
1367 if (key_status == KEY_PRESSED)
1368 key_joystick_mapping |= joy;
1370 key_joystick_mapping &= ~joy;
1375 if (game_status != GAME_MODE_PLAYING)
1376 key_joystick_mapping = 0;
1378 if (key_status == KEY_RELEASED)
1381 if ((key == KSYM_Return || key == KSYM_KP_Enter) &&
1382 (GetKeyModState() & KMOD_Alt) && video.fullscreen_available)
1384 setup.fullscreen = !setup.fullscreen;
1387 printf("::: %d\n", setup.window_scaling_percent);
1390 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1392 if (game_status == GAME_MODE_SETUP)
1393 RedrawSetupScreenAfterFullscreenToggle();
1398 if ((key == KSYM_minus || key == KSYM_plus || key == KSYM_0) &&
1399 (GetKeyModState() & KMOD_Alt) && video.window_scaling_available &&
1400 !video.fullscreen_enabled)
1403 setup.window_scaling_percent = STD_WINDOW_SCALING_PERCENT;
1405 setup.window_scaling_percent +=
1406 (key == KSYM_minus ? -1 : +1) * STEP_WINDOW_SCALING_PERCENT;
1408 if (setup.window_scaling_percent < MIN_WINDOW_SCALING_PERCENT)
1409 setup.window_scaling_percent = MIN_WINDOW_SCALING_PERCENT;
1410 else if (setup.window_scaling_percent > MAX_WINDOW_SCALING_PERCENT)
1411 setup.window_scaling_percent = MAX_WINDOW_SCALING_PERCENT;
1413 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1415 if (game_status == GAME_MODE_SETUP)
1416 RedrawSetupScreenAfterFullscreenToggle();
1422 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd &&
1423 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
1425 if (game_status == GAME_MODE_PLAYING && AllPlayersGone &&
1426 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
1434 if (game_status == GAME_MODE_MAIN &&
1435 (key == setup.shortcut.toggle_pause || key == KSYM_space))
1437 StartGameActions(options.network, setup.autorecord, level.random_seed);
1442 if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING)
1444 if (key == setup.shortcut.save_game)
1446 else if (key == setup.shortcut.load_game)
1448 else if (key == setup.shortcut.toggle_pause)
1449 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1451 HandleTapeButtonKeys(key);
1452 HandleSoundButtonKeys(key);
1455 if (game_status == GAME_MODE_PLAYING && !network_playing)
1457 int centered_player_nr_next = -999;
1459 if (key == setup.shortcut.focus_player_all)
1460 centered_player_nr_next = -1;
1462 for (i = 0; i < MAX_PLAYERS; i++)
1463 if (key == setup.shortcut.focus_player[i])
1464 centered_player_nr_next = i;
1466 if (centered_player_nr_next != -999)
1468 game.centered_player_nr_next = centered_player_nr_next;
1469 game.set_centered_player = TRUE;
1473 tape.centered_player_nr_next = game.centered_player_nr_next;
1474 tape.set_centered_player = TRUE;
1479 HandleKeysSpecial(key);
1481 if (HandleGadgetsKeyInput(key))
1483 if (key != KSYM_Escape) /* always allow ESC key to be handled */
1484 key = KSYM_UNDEFINED;
1487 switch (game_status)
1489 case GAME_MODE_PSEUDO_TYPENAME:
1490 HandleTypeName(0, key);
1493 case GAME_MODE_TITLE:
1494 case GAME_MODE_MAIN:
1495 case GAME_MODE_LEVELS:
1496 case GAME_MODE_LEVELNR:
1497 case GAME_MODE_SETUP:
1498 case GAME_MODE_INFO:
1499 case GAME_MODE_SCORES:
1504 if (game_status == GAME_MODE_TITLE)
1505 HandleTitleScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1506 else if (game_status == GAME_MODE_MAIN)
1507 HandleMainMenu(0, 0, 0, 0, MB_MENU_CHOICE);
1508 else if (game_status == GAME_MODE_LEVELS)
1509 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_CHOICE);
1510 else if (game_status == GAME_MODE_LEVELNR)
1511 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_CHOICE);
1512 else if (game_status == GAME_MODE_SETUP)
1513 HandleSetupScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1514 else if (game_status == GAME_MODE_INFO)
1515 HandleInfoScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1516 else if (game_status == GAME_MODE_SCORES)
1517 HandleHallOfFame(0, 0, 0, 0, MB_MENU_CHOICE);
1521 if (game_status != GAME_MODE_MAIN)
1522 FadeSkipNextFadeIn();
1524 if (game_status == GAME_MODE_TITLE)
1525 HandleTitleScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1526 else if (game_status == GAME_MODE_LEVELS)
1527 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_LEAVE);
1528 else if (game_status == GAME_MODE_LEVELNR)
1529 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_LEAVE);
1530 else if (game_status == GAME_MODE_SETUP)
1531 HandleSetupScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1532 else if (game_status == GAME_MODE_INFO)
1533 HandleInfoScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1534 else if (game_status == GAME_MODE_SCORES)
1535 HandleHallOfFame(0, 0, 0, 0, MB_MENU_LEAVE);
1539 if (game_status == GAME_MODE_LEVELS)
1540 HandleChooseLevelSet(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1541 else if (game_status == GAME_MODE_LEVELNR)
1542 HandleChooseLevelNr(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1543 else if (game_status == GAME_MODE_SETUP)
1544 HandleSetupScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1545 else if (game_status == GAME_MODE_INFO)
1546 HandleInfoScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1547 else if (game_status == GAME_MODE_SCORES)
1548 HandleHallOfFame(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1551 case KSYM_Page_Down:
1552 if (game_status == GAME_MODE_LEVELS)
1553 HandleChooseLevelSet(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1554 else if (game_status == GAME_MODE_LEVELNR)
1555 HandleChooseLevelNr(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1556 else if (game_status == GAME_MODE_SETUP)
1557 HandleSetupScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1558 else if (game_status == GAME_MODE_INFO)
1559 HandleInfoScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1560 else if (game_status == GAME_MODE_SCORES)
1561 HandleHallOfFame(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1566 GameFrameDelay = (GameFrameDelay == 500 ? GAME_FRAME_DELAY : 500);
1570 setup.sp_show_border_elements = !setup.sp_show_border_elements;
1571 printf("Supaplex border elements %s\n",
1572 setup.sp_show_border_elements ? "enabled" : "disabled");
1581 case GAME_MODE_EDITOR:
1582 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
1583 HandleLevelEditorKeyInput(key);
1586 case GAME_MODE_PLAYING:
1591 RequestQuitGame(setup.ask_on_escape);
1609 if (GameFrameDelay == 500)
1610 GameFrameDelay = GAME_FRAME_DELAY;
1612 GameFrameDelay = 500;
1615 GameFrameDelay = (key - KSYM_0) * 10;
1616 printf("Game speed == %d%% (%d ms delay between two frames)\n",
1617 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
1623 options.debug = FALSE;
1624 printf("debug mode disabled\n");
1628 options.debug = TRUE;
1629 printf("debug mode enabled\n");
1634 if (!global.fps_slowdown)
1636 global.fps_slowdown = TRUE;
1637 global.fps_slowdown_factor = 2;
1638 printf("fps slowdown enabled -- display only every 2nd frame\n");
1640 else if (global.fps_slowdown_factor == 2)
1642 global.fps_slowdown_factor = 4;
1643 printf("fps slowdown enabled -- display only every 4th frame\n");
1647 global.fps_slowdown = FALSE;
1648 global.fps_slowdown_factor = 1;
1649 printf("fps slowdown disabled\n");
1654 ScrollStepSize = TILEX / 8;
1655 printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
1659 ScrollStepSize = TILEX / 4;
1660 printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
1664 ScrollStepSize = TILEX / 2;
1665 printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
1669 ScrollStepSize = TILEX;
1670 printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
1674 printf("::: currently using game engine version %d\n",
1675 game.engine_version);
1686 if (key == KSYM_Escape)
1688 game_status = GAME_MODE_MAIN;
1696 void HandleNoEvent()
1698 if (button_status && game_status != GAME_MODE_PLAYING)
1700 HandleButton(0, 0, -button_status, button_status);
1711 #if defined(NETWORK_AVALIABLE)
1712 if (options.network)
1716 switch (game_status)
1718 case GAME_MODE_MAIN:
1719 DrawPreviewLevelAnimation();
1723 case GAME_MODE_LEVELS:
1724 case GAME_MODE_LEVELNR:
1725 case GAME_MODE_SETUP:
1726 case GAME_MODE_INFO:
1727 case GAME_MODE_SCORES:
1731 case GAME_MODE_EDITOR:
1732 HandleLevelEditorIdle();
1740 static int HandleJoystickForAllPlayers()
1745 for (i = 0; i < MAX_PLAYERS; i++)
1747 byte joy_action = 0;
1750 if (!setup.input[i].use_joystick)
1754 joy_action = Joystick(i);
1755 result |= joy_action;
1757 if (!setup.input[i].use_joystick)
1760 stored_player[i].action = joy_action;
1766 void HandleJoystick()
1768 int joystick = HandleJoystickForAllPlayers();
1769 int keyboard = key_joystick_mapping;
1770 int joy = (joystick | keyboard);
1771 int left = joy & JOY_LEFT;
1772 int right = joy & JOY_RIGHT;
1773 int up = joy & JOY_UP;
1774 int down = joy & JOY_DOWN;
1775 int button = joy & JOY_BUTTON;
1776 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
1777 int dx = (left ? -1 : right ? 1 : 0);
1778 int dy = (up ? -1 : down ? 1 : 0);
1780 switch (game_status)
1782 case GAME_MODE_TITLE:
1783 case GAME_MODE_MAIN:
1784 case GAME_MODE_LEVELS:
1785 case GAME_MODE_LEVELNR:
1786 case GAME_MODE_SETUP:
1787 case GAME_MODE_INFO:
1789 static unsigned int joystickmove_delay = 0;
1791 if (joystick && !button &&
1792 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
1793 newbutton = dx = dy = 0;
1795 if (game_status == GAME_MODE_TITLE)
1796 HandleTitleScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1797 else if (game_status == GAME_MODE_MAIN)
1798 HandleMainMenu(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1799 else if (game_status == GAME_MODE_LEVELS)
1800 HandleChooseLevelSet(0,0,dx,dy,newbutton?MB_MENU_CHOICE : MB_MENU_MARK);
1801 else if (game_status == GAME_MODE_LEVELNR)
1802 HandleChooseLevelNr(0,0,dx,dy,newbutton? MB_MENU_CHOICE : MB_MENU_MARK);
1803 else if (game_status == GAME_MODE_SETUP)
1804 HandleSetupScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1805 else if (game_status == GAME_MODE_INFO)
1806 HandleInfoScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1810 case GAME_MODE_SCORES:
1811 HandleHallOfFame(0, 0, dx, dy, !newbutton);
1815 case GAME_MODE_EDITOR:
1816 HandleLevelEditorIdle();
1820 case GAME_MODE_PLAYING:
1821 if (tape.playing || keyboard)
1822 newbutton = ((joy & JOY_BUTTON) != 0);
1825 if (newbutton && local_player->LevelSolved_GameEnd)
1827 if (newbutton && AllPlayersGone)