changed comments from old to new style (one-line comments only)
[rocksndiamonds.git] / src / events.c
index ea5312aecb1efbe79e8239e20ab69115c36a74e4..5a0d57757190049faa3f55349d201346c48ce4cf 100644 (file)
@@ -40,7 +40,7 @@ static unsigned int special_cursor_delay = 0;
 static unsigned int special_cursor_delay_value = 1000;
 
 
-/* forward declarations for internal use */
+// forward declarations for internal use
 static void HandleNoEvent(void);
 static void HandleEventActions(void);
 
@@ -57,7 +57,7 @@ static int FilterEvents(const Event *event)
   MotionEvent *motion;
 
 #if defined(TARGET_SDL2)
-  /* skip repeated key press events if keyboard auto-repeat is disabled */
+  // skip repeated key press events if keyboard auto-repeat is disabled
   if (event->type == EVENT_KEYPRESS &&
       event->key.repeat &&
       !keyrepeat_status)
@@ -76,7 +76,7 @@ static int FilterEvents(const Event *event)
     ((MotionEvent *)event)->y -= video.screen_yoffset;
   }
 
-  /* non-motion events are directly passed to event handler functions */
+  // non-motion events are directly passed to event handler functions
   if (event->type != EVENT_MOTIONNOTIFY)
     return 1;
 
@@ -84,7 +84,7 @@ static int FilterEvents(const Event *event)
   cursor_inside_playfield = (motion->x >= SX && motion->x < SX + SXSIZE &&
                             motion->y >= SY && motion->y < SY + SYSIZE);
 
-  /* do no reset mouse cursor before all pending events have been processed */
+  // do no reset mouse cursor before all pending events have been processed
   if (gfx.cursor_mode == cursor_mode_last &&
       ((game_status == GAME_MODE_TITLE &&
        gfx.cursor_mode == CURSOR_NONE) ||
@@ -98,7 +98,7 @@ static int FilterEvents(const Event *event)
     cursor_mode_last = CURSOR_DEFAULT;
   }
 
-  /* skip mouse motion events without pressed button outside level editor */
+  // skip mouse motion events without pressed button outside level editor
   if (button_status == MB_RELEASED &&
       game_status != GAME_MODE_EDITOR && game_status != GAME_MODE_PLAYING)
     return 0;
@@ -112,11 +112,11 @@ static int FilterEvents(const Event *event)
 
 static boolean SkipPressedMouseMotionEvent(const Event *event)
 {
-  /* nothing to do if the current event is not a mouse motion event */
+  // nothing to do if the current event is not a mouse motion event
   if (event->type != EVENT_MOTIONNOTIFY)
     return FALSE;
 
-  /* only skip motion events with pressed button outside the game */
+  // only skip motion events with pressed button outside the game
   if (button_status == MB_RELEASED || game_status == GAME_MODE_PLAYING)
     return FALSE;
 
@@ -126,7 +126,7 @@ static boolean SkipPressedMouseMotionEvent(const Event *event)
 
     PeekEvent(&next_event);
 
-    /* if next event is also a mouse motion event, skip the current one */
+    // if next event is also a mouse motion event, skip the current one
     if (next_event.type == EVENT_MOTIONNOTIFY)
       return TRUE;
   }
@@ -164,7 +164,7 @@ boolean NextValidEvent(Event *event)
   return FALSE;
 }
 
-void HandleEvents()
+static void HandleEvents(void)
 {
   Event event;
   unsigned int event_frame_delay = 0;
@@ -262,7 +262,7 @@ void HandleOtherEvents(Event *event)
 
       HandleSpecialGameControllerButtons(event);
 
-      /* FALL THROUGH */
+      // FALL THROUGH
     case SDL_CONTROLLERDEVICEADDED:
     case SDL_CONTROLLERDEVICEREMOVED:
     case SDL_CONTROLLERAXISMOTION:
@@ -283,11 +283,11 @@ void HandleOtherEvents(Event *event)
   }
 }
 
-void HandleMouseCursor()
+static void HandleMouseCursor(void)
 {
   if (game_status == GAME_MODE_TITLE)
   {
-    /* when showing title screens, hide mouse pointer (if not moved) */
+    // when showing title screens, hide mouse pointer (if not moved)
 
     if (gfx.cursor_mode != CURSOR_NONE &&
        DelayReached(&special_cursor_delay, special_cursor_delay_value))
@@ -298,7 +298,7 @@ void HandleMouseCursor()
   else if (game_status == GAME_MODE_PLAYING && (!tape.pausing ||
                                                tape.single_step))
   {
-    /* when playing, display a special mouse pointer inside the playfield */
+    // when playing, display a special mouse pointer inside the playfield
 
     if (gfx.cursor_mode != CURSOR_PLAYFIELD &&
        cursor_inside_playfield &&
@@ -314,7 +314,7 @@ void HandleMouseCursor()
     SetMouseCursor(CURSOR_DEFAULT);
   }
 
-  /* this is set after all pending events have been processed */
+  // this is set after all pending events have been processed
   cursor_mode_last = gfx.cursor_mode;
 }
 
@@ -327,7 +327,7 @@ void EventLoop(void)
     else
       HandleNoEvent();
 
-    /* execute event related actions after pending events have been processed */
+    // execute event related actions after pending events have been processed
     HandleEventActions();
 
     /* don't use all CPU time when idle; the main loop while playing
@@ -336,10 +336,10 @@ void EventLoop(void)
     if (game_status == GAME_MODE_PLAYING)
       HandleGameActions();
 
-    /* always copy backbuffer to visible screen for every video frame */
+    // always copy backbuffer to visible screen for every video frame
     BackToFront();
 
-    /* reset video frame delay to default (may change again while playing) */
+    // reset video frame delay to default (may change again while playing)
     SetVideoFrameDelay(MenuFrameDelay);
 
     if (game_status == GAME_MODE_QUIT)
@@ -347,7 +347,26 @@ void EventLoop(void)
   }
 }
 
-void ClearEventQueue()
+void ClearAutoRepeatKeyEvents(void)
+{
+#if defined(TARGET_SDL2)
+  while (PendingEvent())
+  {
+    Event next_event;
+
+    PeekEvent(&next_event);
+
+    // if event is repeated key press event, remove it from event queue
+    if (next_event.type == EVENT_KEYPRESS &&
+       next_event.key.repeat)
+      WaitEvent(&next_event);
+    else
+      break;
+  }
+#endif
+}
+
+void ClearEventQueue(void)
 {
   Event event;
 
@@ -377,18 +396,18 @@ void ClearEventQueue()
   }
 }
 
-void ClearPlayerMouseAction()
+static void ClearPlayerMouseAction(void)
 {
   local_player->mouse_action.lx = 0;
   local_player->mouse_action.ly = 0;
   local_player->mouse_action.button = 0;
 }
 
-void ClearPlayerAction()
+void ClearPlayerAction(void)
 {
   int i;
 
-  /* simulate key release events for still pressed keys */
+  // simulate key release events for still pressed keys
   key_joystick_mapping = 0;
   for (i = 0; i < MAX_PLAYERS; i++)
     stored_player[i].action = 0;
@@ -397,12 +416,15 @@ void ClearPlayerAction()
   ClearPlayerMouseAction();
 }
 
-void SetPlayerMouseAction(int mx, int my, int button)
+static void SetPlayerMouseAction(int mx, int my, int button)
 {
   int lx = getLevelFromScreenX(mx);
   int ly = getLevelFromScreenY(my);
   int new_button = (!local_player->mouse_action.button && button);
 
+  if (local_player->mouse_action.button_hint)
+    button = local_player->mouse_action.button_hint;
+
   ClearPlayerMouseAction();
 
   if (!IN_GFX_FIELD_PLAY(mx, my) || !IN_LEV_FIELD(lx, ly))
@@ -414,7 +436,7 @@ void SetPlayerMouseAction(int mx, int my, int button)
 
   if (tape.recording && tape.pausing && tape.use_mouse)
   {
-    /* un-pause a paused game only if mouse button was newly pressed down */
+    // un-pause a paused game only if mouse button was newly pressed down
     if (new_button)
       TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
   }
@@ -422,7 +444,7 @@ void SetPlayerMouseAction(int mx, int my, int button)
   SetTileCursorXY(lx, ly);
 }
 
-void SleepWhileUnmapped()
+void SleepWhileUnmapped(void)
 {
   boolean window_unmapped = TRUE;
 
@@ -633,10 +655,30 @@ void HandleWindowEvent(WindowEvent *event)
       if (new_display_width  != video.display_width ||
          new_display_height != video.display_height)
       {
+       int nr = GRID_ACTIVE_NR();      // previous screen orientation
+
        video.display_width  = new_display_width;
        video.display_height = new_display_height;
 
        SDLSetScreenProperties();
+
+       // check if screen orientation has changed (should always be true here)
+       if (nr != GRID_ACTIVE_NR())
+       {
+         int x, y;
+
+         if (game_status == GAME_MODE_SETUP)
+           RedrawSetupScreenAfterScreenRotation(nr);
+
+         nr = GRID_ACTIVE_NR();
+
+         overlay.grid_xsize = setup.touch.grid_xsize[nr];
+         overlay.grid_ysize = setup.touch.grid_ysize[nr];
+
+         for (x = 0; x < MAX_GRID_XSIZE; x++)
+           for (y = 0; y < MAX_GRID_YSIZE; y++)
+             overlay.grid_button[x][y] = setup.touch.grid_button[nr][x][y];
+       }
       }
     }
 #endif
@@ -653,8 +695,21 @@ static struct
   Key key;
 } touch_info[NUM_TOUCH_FINGERS];
 
-void HandleFingerEvent_VirtualButtons(FingerEvent *event)
+static void HandleFingerEvent_VirtualButtons(FingerEvent *event)
 {
+#if 1
+  int x = event->x * overlay.grid_xsize;
+  int y = event->y * overlay.grid_ysize;
+  int grid_button = overlay.grid_button[x][y];
+  int grid_button_action = GET_ACTION_FROM_GRID_BUTTON(grid_button);
+  Key key = (grid_button == CHAR_GRID_BUTTON_LEFT  ? setup.input[0].key.left :
+            grid_button == CHAR_GRID_BUTTON_RIGHT ? setup.input[0].key.right :
+            grid_button == CHAR_GRID_BUTTON_UP    ? setup.input[0].key.up :
+            grid_button == CHAR_GRID_BUTTON_DOWN  ? setup.input[0].key.down :
+            grid_button == CHAR_GRID_BUTTON_SNAP  ? setup.input[0].key.snap :
+            grid_button == CHAR_GRID_BUTTON_DROP  ? setup.input[0].key.drop :
+            KSYM_UNDEFINED);
+#else
   float ypos = 1.0 - 1.0 / 3.0 * video.display_width / video.display_height;
   float event_x = (event->x);
   float event_y = (event->y - ypos) / (1 - ypos);
@@ -677,6 +732,7 @@ void HandleFingerEvent_VirtualButtons(FingerEvent *event)
             event_y > 2.0 / 3.0 && event_y < 1 ?
             setup.input[0].key.down :
             KSYM_UNDEFINED);
+#endif
   int key_status = (event->type == EVENT_FINGERRELEASE ? KEY_RELEASED :
                    KEY_PRESSED);
   char *key_status_name = (key_status == KEY_RELEASED ? "KEY_RELEASED" :
@@ -689,6 +745,11 @@ void HandleFingerEvent_VirtualButtons(FingerEvent *event)
   Error(ERR_DEBUG, "::: key '%s' was '%s' [fingerId: %lld]",
        getKeyNameFromKey(key), key_status_name, event->fingerId);
 
+  if (key_status == KEY_PRESSED)
+    overlay.grid_button_action |= grid_button_action;
+  else
+    overlay.grid_button_action &= ~grid_button_action;
+
   // check if we already know this touch event's finger id
   for (i = 0; i < NUM_TOUCH_FINGERS; i++)
   {
@@ -794,7 +855,7 @@ void HandleFingerEvent_VirtualButtons(FingerEvent *event)
   }
 }
 
-void HandleFingerEvent_WipeGestures(FingerEvent *event)
+static void HandleFingerEvent_WipeGestures(FingerEvent *event)
 {
   static Key motion_key_x = KSYM_UNDEFINED;
   static Key motion_key_y = KSYM_UNDEFINED;
@@ -960,7 +1021,16 @@ void HandleFingerEvent(FingerEvent *event)
     return;
 
   if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
+  {
+    if (strEqual(setup.touch.control_type, TOUCH_CONTROL_OFF))
+      local_player->mouse_action.button_hint =
+       (event->type == EVENT_FINGERRELEASE ? MB_NOT_PRESSED :
+        event->x < 0.5                     ? MB_LEFTBUTTON  :
+        event->x > 0.5                     ? MB_RIGHTBUTTON :
+        MB_NOT_PRESSED);
+
     return;
+  }
 
   if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
     HandleFingerEvent_VirtualButtons(event);
@@ -1319,6 +1389,8 @@ static void HandleButtonOrFinger(int mx, int my, int button)
       HandleButtonOrFinger_WipeGestures_MM(mx, my, button);
     else if (strEqual(setup.touch.control_type, TOUCH_CONTROL_FOLLOW_FINGER))
       HandleButtonOrFinger_FollowFinger_MM(mx, my, button);
+    else if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
+      SetPlayerMouseAction(mx, my, button);    // special case
   }
   else
   {
@@ -1329,7 +1401,7 @@ static void HandleButtonOrFinger(int mx, int my, int button)
 
 #if defined(TARGET_SDL2)
 
-static boolean checkTextInputKeyModState()
+static boolean checkTextInputKeyModState(void)
 {
   // when playing, only handle raw key events and ignore text input
   if (game_status == GAME_MODE_PLAYING)
@@ -1503,22 +1575,22 @@ void HandleButton(int mx, int my, int button, int button_nr)
      strEqual(setup.touch.control_type, TOUCH_CONTROL_FOLLOW_FINGER));
 #endif
 
-  if (handle_gadgets && HandleGadgets(mx, my, button))
+  if (HandleGlobalAnimClicks(mx, my, button))
   {
-    /* do not handle this button event anymore */
-    mx = my = -32;     /* force mouse event to be outside screen tiles */
+    // do not handle this button event anymore
+    return;            // force mouse event not to be handled at all
   }
 
-  if (HandleGlobalAnimClicks(mx, my, button))
+  if (handle_gadgets && HandleGadgets(mx, my, button))
   {
-    /* do not handle this button event anymore */
-    return;            /* force mouse event not to be handled at all */
+    // do not handle this button event anymore
+    mx = my = -32;     // force mouse event to be outside screen tiles
   }
 
   if (button_hold && game_status == GAME_MODE_PLAYING && tape.pausing)
     return;
 
-  /* do not use scroll wheel button events for anything other than gadgets */
+  // do not use scroll wheel button events for anything other than gadgets
   if (IS_WHEEL_BUTTON(button_nr))
     return;
 
@@ -1624,6 +1696,11 @@ static void HandleKeysSpecial(Key key)
     {
       InsertSolutionTape();
     }
+    else if (is_string_suffix(cheat_input, ":play-solution-tape") ||
+            is_string_suffix(cheat_input, ":pst"))
+    {
+      PlaySolutionTape();
+    }
     else if (is_string_suffix(cheat_input, ":reload-graphics") ||
             is_string_suffix(cheat_input, ":rg"))
     {
@@ -1668,7 +1745,7 @@ static void HandleKeysSpecial(Key key)
         in playing levels with more than one player in multi-player mode,
         even though the tape was originally recorded in single-player mode */
 
-      /* remove player input actions for all players but the first one */
+      // remove player input actions for all players but the first one
       for (i = 1; i < MAX_PLAYERS; i++)
        tape.player_participates[i] = FALSE;
 
@@ -1704,6 +1781,15 @@ static void HandleKeysSpecial(Key key)
       DumpBrush_Small();
     }
   }
+
+  // special key shortcuts for all game modes
+  if (is_string_suffix(cheat_input, ":dump-event-actions") ||
+      is_string_suffix(cheat_input, ":dea") ||
+      is_string_suffix(cheat_input, ":DEA"))
+  {
+    DumpGadgetIdentifiers();
+    DumpScreenIdentifiers();
+  }
 }
 
 void HandleKeysDebug(Key key)
@@ -1785,7 +1871,7 @@ void HandleKey(Key key, int key_status)
   int i;
 
 #if defined(TARGET_SDL2)
-  /* map special keys (media keys / remote control buttons) to default keys */
+  // map special keys (media keys / remote control buttons) to default keys
   if (key == KSYM_PlayPause)
     key = KSYM_space;
   else if (key == KSYM_Select)
@@ -1796,7 +1882,7 @@ void HandleKey(Key key, int key_status)
 
   if (game_status == GAME_MODE_PLAYING)
   {
-    /* only needed for single-step tape recording mode */
+    // only needed for single-step tape recording mode
     static boolean has_snapped[MAX_PLAYERS] = { FALSE, FALSE, FALSE, FALSE };
     int pnr;
 
@@ -1813,7 +1899,7 @@ void HandleKey(Key key, int key_status)
        if (key == *key_info[i].key_custom)
          key_action |= key_info[i].action;
 
-      /* use combined snap+direction keys for the first player only */
+      // use combined snap+direction keys for the first player only
       if (pnr == 0)
       {
        ssi = setup.shortcut;
@@ -1834,7 +1920,7 @@ void HandleKey(Key key, int key_status)
        {
          TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
 
-         /* if snap key already pressed, keep pause mode when releasing */
+         // if snap key already pressed, keep pause mode when releasing
          if (stored_player[pnr].action & KEY_BUTTON_SNAP)
            has_snapped[pnr] = TRUE;
        }
@@ -1845,14 +1931,14 @@ void HandleKey(Key key, int key_status)
          if (level.game_engine_type == GAME_ENGINE_TYPE_SP &&
              getRedDiskReleaseFlag_SP() == 0)
          {
-           /* add a single inactive frame before dropping starts */
+           // add a single inactive frame before dropping starts
            stored_player[pnr].action &= ~KEY_BUTTON_DROP;
            stored_player[pnr].force_dropping = TRUE;
          }
        }
        else if (key_status == KEY_RELEASED && key_action & KEY_BUTTON_SNAP)
        {
-         /* if snap key was pressed without direction, leave pause mode */
+         // if snap key was pressed without direction, leave pause mode
          if (!has_snapped[pnr])
            TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
 
@@ -1861,7 +1947,7 @@ void HandleKey(Key key, int key_status)
       }
       else if (tape.recording && tape.pausing && !tape.use_mouse)
       {
-       /* prevent key release events from un-pausing a paused game */
+       // prevent key release events from un-pausing a paused game
        if (key_status == KEY_PRESSED && key_action & KEY_ACTION)
          TapeTogglePause(TAPE_TOGGLE_MANUAL);
       }
@@ -1950,8 +2036,8 @@ void HandleKey(Key key, int key_status)
                                      key == KSYM_Return ||
                                      key == KSYM_Escape)))
   {
-    /* do not handle this key event anymore */
-    if (key != KSYM_Escape)    /* always allow ESC key to be handled */
+    // do not handle this key event anymore
+    if (key != KSYM_Escape)    // always allow ESC key to be handled
       return;
   }
 
@@ -1966,7 +2052,7 @@ void HandleKey(Key key, int key_status)
   if (game_status == GAME_MODE_MAIN &&
       (key == setup.shortcut.toggle_pause || key == KSYM_space))
   {
-    StartGameActions(options.network, setup.autorecord, level.random_seed);
+    StartGameActions(network.enabled, setup.autorecord, level.random_seed);
 
     return;
   }
@@ -2012,7 +2098,7 @@ void HandleKey(Key key, int key_status)
 
   if (HandleGadgetsKeyInput(key))
   {
-    if (key != KSYM_Escape)    /* always allow ESC key to be handled */
+    if (key != KSYM_Escape)    // always allow ESC key to be handled
       key = KSYM_UNDEFINED;
   }
 
@@ -2029,6 +2115,10 @@ void HandleKey(Key key, int key_status)
     case GAME_MODE_SETUP:
     case GAME_MODE_INFO:
     case GAME_MODE_SCORES:
+
+      if (anyTextGadgetActiveOrJustFinished && key != KSYM_Escape)
+       break;
+
       switch (key)
       {
        case KSYM_space:
@@ -2131,7 +2221,7 @@ void HandleKey(Key key, int key_status)
   HandleKeysDebug(key);
 }
 
-void HandleNoEvent()
+void HandleNoEvent(void)
 {
   HandleMouseCursor();
 
@@ -2143,7 +2233,7 @@ void HandleNoEvent()
   }
 }
 
-void HandleEventActions()
+void HandleEventActions(void)
 {
   // if (button_status && game_status != GAME_MODE_PLAYING)
   if (button_status && (game_status != GAME_MODE_PLAYING ||
@@ -2157,10 +2247,8 @@ void HandleEventActions()
     HandleJoystick();
   }
 
-#if defined(NETWORK_AVALIABLE)
-  if (options.network)
+  if (network.enabled)
     HandleNetworking();
-#endif
 
   switch (game_status)
   {
@@ -2208,7 +2296,7 @@ static void HandleTileCursor(int dx, int dy, int button)
   }
 }
 
-static int HandleJoystickForAllPlayers()
+static int HandleJoystickForAllPlayers(void)
 {
   int i;
   int result = 0;
@@ -2220,7 +2308,7 @@ static int HandleJoystickForAllPlayers()
     if (setup.input[i].use_joystick)
       no_joysticks_configured = FALSE;
 
-  /* if no joysticks configured, map connected joysticks to players */
+  // if no joysticks configured, map connected joysticks to players
   if (no_joysticks_configured)
     use_as_joystick_nr = TRUE;
 
@@ -2241,7 +2329,7 @@ static int HandleJoystickForAllPlayers()
   return result;
 }
 
-void HandleJoystick()
+void HandleJoystick(void)
 {
   static unsigned int joytest_delay = 0;
   static unsigned int joytest_delay_value = GADGET_FRAME_DELAY;
@@ -2264,7 +2352,7 @@ void HandleJoystick()
 
   if (HandleGlobalAnimClicks(-1, -1, newbutton))
   {
-    /* do not handle this button event anymore */
+    // do not handle this button event anymore
     return;
   }
 
@@ -2289,12 +2377,12 @@ void HandleJoystick()
 
   if (joytest && !button && !DelayReached(&joytest_delay, joytest_delay_value))
   {
-    /* delay joystick/keyboard actions if axes/keys continually pressed */
+    // delay joystick/keyboard actions if axes/keys continually pressed
     newbutton = dx = dy = 0;
   }
   else
   {
-    /* first start with longer delay, then continue with shorter delay */
+    // first start with longer delay, then continue with shorter delay
     joytest_delay_value =
       (use_delay_value_first ? delay_value_first : delay_value);
   }
@@ -2311,6 +2399,9 @@ void HandleJoystick()
     case GAME_MODE_INFO:
     case GAME_MODE_SCORES:
     {
+      if (anyTextGadgetActive())
+       break;
+
       if (game_status == GAME_MODE_TITLE)
        HandleTitleScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
       else if (game_status == GAME_MODE_MAIN)
@@ -2343,7 +2434,12 @@ void HandleJoystick()
        return;
       }
 
-      if (tape.recording && tape.pausing && !tape.use_mouse)
+      if (tape.single_step && tape.recording && tape.pausing && !tape.use_mouse)
+      {
+       if (joystick & JOY_ACTION)
+         TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
+      }
+      else if (tape.recording && tape.pausing && !tape.use_mouse)
       {
        if (joystick & JOY_ACTION)
          TapeTogglePause(TAPE_TOGGLE_MANUAL);
@@ -2362,24 +2458,38 @@ void HandleJoystick()
 void HandleSpecialGameControllerButtons(Event *event)
 {
 #if defined(TARGET_SDL2)
+  int key_status;
+  Key key;
+
   switch (event->type)
   {
     case SDL_CONTROLLERBUTTONDOWN:
-      if (event->cbutton.button == SDL_CONTROLLER_BUTTON_START)
-       HandleKey(KSYM_space, KEY_PRESSED);
-      else if (event->cbutton.button == SDL_CONTROLLER_BUTTON_BACK)
-       HandleKey(KSYM_Escape, KEY_PRESSED);
-
+      key_status = KEY_PRESSED;
       break;
 
     case SDL_CONTROLLERBUTTONUP:
-      if (event->cbutton.button == SDL_CONTROLLER_BUTTON_START)
-       HandleKey(KSYM_space, KEY_RELEASED);
-      else if (event->cbutton.button == SDL_CONTROLLER_BUTTON_BACK)
-       HandleKey(KSYM_Escape, KEY_RELEASED);
+      key_status = KEY_RELEASED;
+      break;
 
+    default:
+      return;
+  }
+
+  switch (event->cbutton.button)
+  {
+    case SDL_CONTROLLER_BUTTON_START:
+      key = KSYM_space;
+      break;
+
+    case SDL_CONTROLLER_BUTTON_BACK:
+      key = KSYM_Escape;
       break;
+
+    default:
+      return;
   }
+
+  HandleKey(key, key_status);
 #endif
 }
 
@@ -2389,7 +2499,7 @@ void HandleSpecialGameControllerKeys(Key key, int key_status)
 #if defined(KSYM_Rewind) && defined(KSYM_FastForward)
   int button = SDL_CONTROLLER_BUTTON_INVALID;
 
-  /* map keys to joystick buttons (special hack for Amazon Fire TV remote) */
+  // map keys to joystick buttons (special hack for Amazon Fire TV remote)
   if (key == KSYM_Rewind)
     button = SDL_CONTROLLER_BUTTON_A;
   else if (key == KSYM_FastForward || key == KSYM_Menu)
@@ -2402,7 +2512,7 @@ void HandleSpecialGameControllerKeys(Key key, int key_status)
     event.type = (key_status == KEY_PRESSED ? SDL_CONTROLLERBUTTONDOWN :
                  SDL_CONTROLLERBUTTONUP);
 
-    event.cbutton.which = 0;   /* first joystick (Amazon Fire TV remote) */
+    event.cbutton.which = 0;   // first joystick (Amazon Fire TV remote)
     event.cbutton.button = button;
     event.cbutton.state = (key_status == KEY_PRESSED ? SDL_PRESSED :
                           SDL_RELEASED);
@@ -2412,3 +2522,18 @@ void HandleSpecialGameControllerKeys(Key key, int key_status)
 #endif
 #endif
 }
+
+boolean DoKeysymAction(int keysym)
+{
+  if (keysym < 0)
+  {
+    Key key = (Key)(-keysym);
+
+    HandleKey(key, KEY_PRESSED);
+    HandleKey(key, KEY_RELEASED);
+
+    return TRUE;
+  }
+
+  return FALSE;
+}