def get_actions(self, run_config, controller):
    """Get actions from the UI, apply to controller, and return an ActionCmd."""
    if not self._initialized:
      return ActionCmd.STEP

    for event in pygame.event.get():
      ctrl = pygame.key.get_mods() & pygame.KMOD_CTRL
      shift = pygame.key.get_mods() & pygame.KMOD_SHIFT
      alt = pygame.key.get_mods() & pygame.KMOD_ALT
      if event.type == pygame.QUIT:
        return ActionCmd.QUIT
      elif event.type == pygame.KEYDOWN:
        if self._help:
          self._help = False
        elif event.key in (pygame.K_QUESTION, pygame.K_SLASH):
          self._help = True
        elif event.key == pygame.K_PAUSE:
          pause = True
          while pause:
            time.sleep(0.1)
            for event2 in pygame.event.get():
              if event2.type == pygame.KEYDOWN:
                if event2.key in (pygame.K_PAUSE, pygame.K_ESCAPE):
                  pause = False
                elif event2.key == pygame.K_F4:
                  return ActionCmd.QUIT
                elif event2.key == pygame.K_F5:
                  return ActionCmd.RESTART
        elif event.key == pygame.K_F4:
          return ActionCmd.QUIT
        elif event.key == pygame.K_F5:
          return ActionCmd.RESTART
        elif event.key == pygame.K_F9:  # Toggle rgb rendering.
          if self._rgb_screen_px and self._feature_screen_px:
            self._render_rgb = not self._render_rgb
            print("Rendering", self._render_rgb and "RGB" or "Feature Layers")
            self.init_window()
        elif event.key == pygame.K_F11:  # Toggle synchronous rendering.
          self._render_sync = not self._render_sync
          print("Rendering", self._render_sync and "Sync" or "Async")
        elif event.key == pygame.K_F12:
          self._raw_actions = not self._raw_actions
          print("Action space:", self._raw_actions and "Raw" or "Spatial")
        elif event.key == pygame.K_F10:  # Toggle player_relative layer.
          self._render_player_relative = not self._render_player_relative
        elif event.key == pygame.K_F8:  # Save a replay.
          self.save_replay(run_config, controller)
        elif event.key in (pygame.K_PLUS, pygame.K_EQUALS) and ctrl:
          self.zoom(1.1)  # zoom in
        elif event.key in (pygame.K_MINUS, pygame.K_UNDERSCORE) and ctrl:
          self.zoom(1 / 1.1)  # zoom out
        elif event.key in (pygame.K_PAGEUP, pygame.K_PAGEDOWN):
          if ctrl:
            if event.key == pygame.K_PAGEUP:
              self._step_mul += 1
            elif self._step_mul > 1:
              self._step_mul -= 1
            print("New step mul:", self._step_mul)
          else:
            self._fps *= 1.25 if event.key == pygame.K_PAGEUP else 1 / 1.25
            print("New max game speed: %.1f" % self._fps)
        elif event.key == pygame.K_F1:
          if self._obs.observation.player_common.idle_worker_count > 0:
            controller.act(self.select_idle_worker(ctrl, shift))
        elif event.key == pygame.K_F2:
          if self._obs.observation.player_common.army_count > 0:
            controller.act(self.select_army(shift))
        elif event.key == pygame.K_F3:
          if self._obs.observation.player_common.warp_gate_count > 0:
            controller.act(self.select_warp_gates(shift))
          if self._obs.observation.player_common.larva_count > 0:
            controller.act(self.select_larva())
        elif event.key in self.cmd_group_keys:
          controller.act(self.control_group(self.cmd_group_keys[event.key],
                                            ctrl, shift, alt))
        elif event.key in self.camera_actions:
          if self._obs:
            pt = point.Point.build(self._obs.observation.raw_data.player.camera)
            pt += self.camera_actions[event.key]
            controller.act(self.camera_action_raw(pt))
            controller.observer_act(self.camera_action_observer_pt(pt))
        elif event.key == pygame.K_ESCAPE:
          controller.observer_act(self.camera_action_observer_player(
              self._obs.observation.player_common.player_id))
          if self._queued_action:
            self.clear_queued_action()
          else:
            cmds = self._abilities(lambda cmd: cmd.hotkey == "escape")  # Cancel
            for cmd in cmds:  # There could be multiple cancels.
              assert not cmd.requires_point
              controller.act(self.unit_action(cmd, None, shift))
        else:
          if not self._queued_action:
            key = pygame.key.name(event.key).lower()
            new_cmd = self._queued_hotkey + key
            cmds = self._abilities(lambda cmd, n=new_cmd: (  # pylint: disable=g-long-lambda
                cmd.hotkey != "escape" and cmd.hotkey.startswith(n)))
            if cmds:
              self._queued_hotkey = new_cmd
              if len(cmds) == 1:
                cmd = cmds[0]
                if cmd.hotkey == self._queued_hotkey:
                  if cmd.requires_point:
                    self.clear_queued_action()
                    self._queued_action = cmd
                  else:
                    controller.act(self.unit_action(cmd, None, shift))
      elif event.type == pygame.MOUSEBUTTONDOWN:
        mouse_pos = self.get_mouse_pos(event.pos)
        if event.button == MouseButtons.LEFT and mouse_pos:
          if self._queued_action:
            controller.act(self.unit_action(
                self._queued_action, mouse_pos, shift))
          elif mouse_pos.surf.surf_type & SurfType.MINIMAP:
            controller.act(self.camera_action(mouse_pos))
            controller.observer_act(self.camera_action_observer_pt(
                mouse_pos.world_pos))
          else:
            self._select_start = mouse_pos
        elif event.button == MouseButtons.RIGHT:
          if self._queued_action:
            self.clear_queued_action()
          cmds = self._abilities(lambda cmd: cmd.name == "Smart")
          if cmds:
            controller.act(self.unit_action(cmds[0], mouse_pos, shift))
      elif event.type == pygame.MOUSEBUTTONUP:
        mouse_pos = self.get_mouse_pos(event.pos)
        if event.button == MouseButtons.LEFT and self._select_start:
          if (mouse_pos and mouse_pos.surf.surf_type & SurfType.SCREEN and
              mouse_pos.surf.surf_type == self._select_start.surf.surf_type):
            controller.act(self.select_action(
                self._select_start, mouse_pos, ctrl, shift))
          self._select_start = None
    return ActionCmd.STEP