RetroArch/command.c

2730 lines
75 KiB
C
Raw Normal View History

/* RetroArch - A frontend for libretro.
2017-03-22 02:09:18 +00:00
* Copyright (C) 2011-2017 - Daniel De Matteis
* Copyright (C) 2016-2017 - Brad Parker
2015-01-29 01:29:07 +00:00
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <string.h>
2016-05-09 18:30:47 +00:00
#include <ctype.h>
2016-05-09 18:30:47 +00:00
#ifdef _WIN32
#include <direct.h>
#else
#include <unistd.h>
#endif
2015-06-14 15:19:32 +00:00
#include <compat/strl.h>
#include <compat/posix_string.h>
#include <file/file_path.h>
2016-05-09 18:30:47 +00:00
#include <lists/dir_list.h>
#include <string/stdstring.h>
2016-09-08 04:07:43 +00:00
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
2016-05-09 18:30:47 +00:00
#ifdef HAVE_COMMAND
2017-01-20 23:23:45 +00:00
#ifdef HAVE_NETWORKING
#include <net/net_compat.h>
#include <net/net_socket.h>
#endif
2016-01-20 04:21:52 +00:00
#include <string/stdstring.h>
2016-05-09 18:30:47 +00:00
#endif
2015-07-01 22:29:02 +00:00
2016-09-08 06:08:42 +00:00
#ifdef HAVE_CHEEVOS
#include "tasks/task_cheevos.h"
2016-09-08 06:08:42 +00:00
#endif
#ifdef HAVE_MENU
#include "menu/menu_driver.h"
#include "menu/menu_content.h"
#include "menu/menu_display.h"
#include "menu/menu_shader.h"
#include "menu/widgets/menu_dialog.h"
2016-09-08 06:08:42 +00:00
#endif
#ifdef HAVE_NETWORKING
#include <net/net_compat.h>
2016-09-29 19:07:10 +00:00
#include "network/netplay/netplay.h"
2016-09-08 06:08:42 +00:00
#endif
2015-06-14 15:19:32 +00:00
#include "command.h"
2016-05-09 18:30:47 +00:00
#include "defaults.h"
2016-09-11 14:31:23 +00:00
#include "driver.h"
2017-04-25 15:14:46 +00:00
#include "input/input_config.h"
2016-05-09 18:30:47 +00:00
#include "frontend/frontend_driver.h"
#include "audio/audio_driver.h"
#include "record/record_driver.h"
#include "file_path_special.h"
2016-05-09 18:30:47 +00:00
#include "autosave.h"
#include "core_info.h"
#include "core_type.h"
2016-05-10 06:53:14 +00:00
#include "performance_counters.h"
2016-05-09 18:30:47 +00:00
#include "dynamic.h"
#include "content.h"
2016-09-23 01:21:33 +00:00
#include "dirs.h"
2016-05-09 18:30:47 +00:00
#include "movie.h"
#include "paths.h"
2016-05-09 18:30:47 +00:00
#include "msg_hash.h"
#include "retroarch.h"
#include "managers/cheat_manager.h"
#include "managers/state_manager.h"
#include "ui/ui_companion_driver.h"
2016-05-16 15:19:16 +00:00
#include "tasks/tasks_internal.h"
2016-05-09 18:30:47 +00:00
#include "list_special.h"
2016-09-08 04:07:43 +00:00
#include "core.h"
#include "verbosity.h"
#include "runloop.h"
#include "configuration.h"
#include "input/input_remapping.h"
#define DEFAULT_NETWORK_CMD_PORT 55355
2016-02-13 06:19:21 +00:00
#define STDIN_BUF_SIZE 4096
2016-05-09 18:10:08 +00:00
struct command
{
2016-05-09 19:25:37 +00:00
bool local_enable;
2012-07-24 00:47:28 +00:00
#ifdef HAVE_STDIN_CMD
bool stdin_enable;
char stdin_buf[STDIN_BUF_SIZE];
size_t stdin_buf_ptr;
#endif
2016-09-29 19:07:10 +00:00
#if defined(HAVE_NETWORKING) && defined(HAVE_NETWORK_CMD)
2012-07-24 00:47:28 +00:00
int net_fd;
#endif
bool state[RARCH_BIND_LIST_END];
};
2016-09-11 15:37:05 +00:00
enum cmd_source_t
{
CMD_NONE = 0,
CMD_STDIN,
CMD_NETWORK
};
2016-09-29 19:07:10 +00:00
#if defined(HAVE_STDIN_CMD) || defined(HAVE_NETWORK_CMD) && defined(HAVE_NETWORKING)
2016-06-04 15:51:27 +00:00
static enum cmd_source_t lastcmd_source;
2016-06-05 03:25:44 +00:00
#endif
2016-09-29 19:07:10 +00:00
#if defined(HAVE_NETWORKING) && defined(HAVE_NETWORK_CMD)
static int lastcmd_net_fd;
static struct sockaddr_storage lastcmd_net_source;
static socklen_t lastcmd_net_source_len;
#endif
2016-06-06 21:42:12 +00:00
#ifdef HAVE_CHEEVOS
2016-09-29 19:07:10 +00:00
#if defined(HAVE_STDIN_CMD) || defined(HAVE_NETWORK_CMD) && defined(HAVE_NETWORKING)
static bool command_reply(const char * data, size_t len)
{
#ifdef HAVE_STDIN_CMD
2016-09-11 15:37:05 +00:00
if (lastcmd_source == CMD_STDIN)
{
fwrite(data, 1,len, stdout);
return true;
}
#endif
2016-09-29 19:07:10 +00:00
#if defined(HAVE_NETWORKING) && defined(HAVE_NETWORK_CMD)
2016-09-11 15:37:05 +00:00
if (lastcmd_source == CMD_NETWORK)
{
2016-06-27 05:57:14 +00:00
sendto(lastcmd_net_fd, data, len, 0,
(struct sockaddr*)&lastcmd_net_source, lastcmd_net_source_len);
return true;
}
#endif
return false;
}
2016-06-05 03:25:44 +00:00
#endif
2016-06-06 21:42:12 +00:00
#endif
2016-02-13 06:19:21 +00:00
struct cmd_map
{
const char *str;
unsigned id;
};
struct cmd_action_map
{
const char *str;
bool (*action)(const char *arg);
const char *arg_desc;
};
2016-05-09 19:23:53 +00:00
#ifdef HAVE_COMMAND
2016-05-09 19:36:17 +00:00
static bool command_set_shader(const char *arg)
2016-05-09 19:23:53 +00:00
{
char msg[256];
enum rarch_shader_type type = RARCH_SHADER_NONE;
2016-06-20 20:04:59 +00:00
switch (msg_hash_to_file_type(msg_hash_calculate(path_get_extension(arg))))
2016-05-09 19:23:53 +00:00
{
2016-06-20 20:04:59 +00:00
case FILE_TYPE_SHADER_GLSL:
case FILE_TYPE_SHADER_PRESET_GLSLP:
2016-05-09 19:23:53 +00:00
type = RARCH_SHADER_GLSL;
break;
2016-06-20 20:04:59 +00:00
case FILE_TYPE_SHADER_CG:
case FILE_TYPE_SHADER_PRESET_CGP:
2016-05-09 19:23:53 +00:00
type = RARCH_SHADER_CG;
break;
2016-06-20 20:04:59 +00:00
case FILE_TYPE_SHADER_SLANG:
case FILE_TYPE_SHADER_PRESET_SLANGP:
2016-05-09 19:23:53 +00:00
type = RARCH_SHADER_SLANG;
break;
default:
return false;
}
snprintf(msg, sizeof(msg), "Shader: \"%s\"", arg);
runloop_msg_queue_push(msg, 1, 120, true);
2016-05-09 19:23:53 +00:00
RARCH_LOG("%s \"%s\".\n",
msg_hash_to_str(MSG_APPLYING_SHADER),
arg);
return video_driver_set_shader(type, arg);
}
2016-02-13 06:19:21 +00:00
2016-06-06 21:42:12 +00:00
#ifdef HAVE_CHEEVOS
static bool command_read_ram(const char *arg)
{
cheevos_var_t var;
2016-06-19 20:43:49 +00:00
unsigned i;
2017-04-28 11:43:47 +00:00
unsigned nbytes;
char reply[256];
2017-04-28 11:43:47 +00:00
const uint8_t * data = NULL;
char *reply_at = NULL;
reply[0] = '\0';
2016-06-06 22:03:07 +00:00
2016-06-27 06:07:19 +00:00
strlcpy(reply, "READ_CORE_RAM ", sizeof(reply));
2016-06-06 22:03:07 +00:00
reply_at = reply + strlen("READ_CORE_RAM ");
2016-06-27 19:15:26 +00:00
strlcpy(reply_at, arg, sizeof(reply)-strlen(reply));
cheevos_parse_guest_addr(&var, strtoul(reply_at, (char**)&reply_at, 16));
data = cheevos_get_memory(&var);
2016-06-04 16:25:30 +00:00
if (data)
{
2016-06-04 16:25:30 +00:00
unsigned nbytes = strtol(reply_at, NULL, 10);
2016-06-04 16:25:30 +00:00
for (i=0;i<nbytes;i++)
{
sprintf(reply_at+3*i, " %.2X", data[i]);
}
reply_at[3*nbytes] = '\n';
command_reply(reply, reply_at+3*nbytes+1 - reply);
}
else
{
2016-06-27 19:15:26 +00:00
strlcpy(reply_at, " -1\n", sizeof(reply)-strlen(reply));
2016-06-04 16:25:30 +00:00
command_reply(reply, reply_at+strlen(" -1\n") - reply);
}
return true;
}
static bool command_write_ram(const char *arg)
{
int i;
2016-06-28 09:02:51 +00:00
cheevos_var_t var;
unsigned nbytes;
uint8_t * data = NULL;
cheevos_parse_guest_addr(&var, strtoul(arg, (char**)&arg, 16));
2016-07-23 09:22:13 +00:00
data = cheevos_get_memory(&var);
2016-07-23 09:22:13 +00:00
if (!data)
return false;
2016-06-04 16:25:30 +00:00
while (*arg)
{
*data = strtoul(arg, (char**)&arg, 16);
data++;
}
return true;
}
2016-06-06 21:42:12 +00:00
#endif
2016-02-13 06:19:21 +00:00
static const struct cmd_action_map action_map[] = {
2016-05-09 19:36:17 +00:00
{ "SET_SHADER", command_set_shader, "<shader path>" },
#ifdef HAVE_CHEEVOS
{ "READ_CORE_RAM", command_read_ram, "<address> <number of bytes>" },
{ "WRITE_CORE_RAM", command_write_ram, "<address> <byte1> <byte2> ..." },
#endif
2016-02-13 06:19:21 +00:00
};
static const struct cmd_map map[] = {
{ "FAST_FORWARD", RARCH_FAST_FORWARD_KEY },
{ "FAST_FORWARD_HOLD", RARCH_FAST_FORWARD_HOLD_KEY },
{ "LOAD_STATE", RARCH_LOAD_STATE_KEY },
{ "SAVE_STATE", RARCH_SAVE_STATE_KEY },
{ "FULLSCREEN_TOGGLE", RARCH_FULLSCREEN_TOGGLE_KEY },
{ "QUIT", RARCH_QUIT_KEY },
{ "STATE_SLOT_PLUS", RARCH_STATE_SLOT_PLUS },
{ "STATE_SLOT_MINUS", RARCH_STATE_SLOT_MINUS },
{ "REWIND", RARCH_REWIND },
{ "MOVIE_RECORD_TOGGLE", RARCH_MOVIE_RECORD_TOGGLE },
{ "PAUSE_TOGGLE", RARCH_PAUSE_TOGGLE },
{ "FRAMEADVANCE", RARCH_FRAMEADVANCE },
{ "RESET", RARCH_RESET },
{ "SHADER_NEXT", RARCH_SHADER_NEXT },
{ "SHADER_PREV", RARCH_SHADER_PREV },
{ "CHEAT_INDEX_PLUS", RARCH_CHEAT_INDEX_PLUS },
{ "CHEAT_INDEX_MINUS", RARCH_CHEAT_INDEX_MINUS },
{ "CHEAT_TOGGLE", RARCH_CHEAT_TOGGLE },
{ "SCREENSHOT", RARCH_SCREENSHOT },
{ "MUTE", RARCH_MUTE },
{ "OSK", RARCH_OSK },
2016-02-13 06:19:21 +00:00
{ "NETPLAY_FLIP", RARCH_NETPLAY_FLIP },
{ "NETPLAY_GAME_WATCH", RARCH_NETPLAY_GAME_WATCH },
2016-02-13 06:19:21 +00:00
{ "SLOWMOTION", RARCH_SLOWMOTION },
{ "VOLUME_UP", RARCH_VOLUME_UP },
{ "VOLUME_DOWN", RARCH_VOLUME_DOWN },
{ "OVERLAY_NEXT", RARCH_OVERLAY_NEXT },
{ "DISK_EJECT_TOGGLE", RARCH_DISK_EJECT_TOGGLE },
{ "DISK_NEXT", RARCH_DISK_NEXT },
{ "DISK_PREV", RARCH_DISK_PREV },
{ "GRAB_MOUSE_TOGGLE", RARCH_GRAB_MOUSE_TOGGLE },
{ "GAME_FOCUS_TOGGLE", RARCH_GAME_FOCUS_TOGGLE },
2016-02-13 06:19:21 +00:00
{ "MENU_TOGGLE", RARCH_MENU_TOGGLE },
{ "MENU_UP", RETRO_DEVICE_ID_JOYPAD_UP },
{ "MENU_DOWN", RETRO_DEVICE_ID_JOYPAD_DOWN },
{ "MENU_LEFT", RETRO_DEVICE_ID_JOYPAD_LEFT },
{ "MENU_RIGHT", RETRO_DEVICE_ID_JOYPAD_RIGHT },
{ "MENU_A", RETRO_DEVICE_ID_JOYPAD_A },
{ "MENU_B", RETRO_DEVICE_ID_JOYPAD_B },
{ "MENU_B", RETRO_DEVICE_ID_JOYPAD_B },
2016-02-13 06:19:21 +00:00
};
2014-09-02 03:10:54 +00:00
static bool command_get_arg(const char *tok,
const char **arg, unsigned *index)
{
2013-10-22 19:26:33 +00:00
unsigned i;
2014-08-02 23:38:49 +00:00
2013-10-22 19:26:33 +00:00
for (i = 0; i < ARRAY_SIZE(map); i++)
{
2016-01-20 04:21:52 +00:00
if (string_is_equal(tok, map[i].str))
{
if (arg)
*arg = NULL;
if (index)
*index = i;
return true;
}
}
2013-10-22 19:26:33 +00:00
for (i = 0; i < ARRAY_SIZE(action_map); i++)
{
const char *str = strstr(tok, action_map[i].str);
if (str == tok)
{
const char *argument = str + strlen(action_map[i].str);
if (*argument != ' ')
return false;
if (arg)
*arg = argument + 1;
if (index)
*index = i;
return true;
}
}
return false;
}
static void command_parse_sub_msg(command_t *handle, const char *tok)
{
const char *arg = NULL;
unsigned index = 0;
if (command_get_arg(tok, &arg, &index))
{
if (arg)
{
if (!action_map[index].action(arg))
RARCH_ERR("Command \"%s\" failed.\n", arg);
}
else
handle->state[map[index].id] = true;
}
else
RARCH_WARN("%s \"%s\" %s.\n",
msg_hash_to_str(MSG_UNRECOGNIZED_COMMAND),
tok,
msg_hash_to_str(MSG_RECEIVED));
}
2016-06-04 15:51:27 +00:00
static void command_parse_msg(command_t *handle, char *buf, enum cmd_source_t source)
{
char *save = NULL;
const char *tok = strtok_r(buf, "\n", &save);
2016-06-04 15:51:27 +00:00
lastcmd_source = source;
while (tok)
{
command_parse_sub_msg(handle, tok);
tok = strtok_r(NULL, "\n", &save);
}
2016-09-11 15:37:05 +00:00
lastcmd_source = CMD_NONE;
}
2016-09-29 19:07:10 +00:00
#if defined(HAVE_NETWORKING) && defined(HAVE_NETWORK_CMD)
static bool command_network_init(command_t *handle, uint16_t port)
{
int fd;
struct addrinfo *res = NULL;
2016-08-22 00:38:19 +00:00
RARCH_LOG("%s %hu.\n",
2016-10-22 22:49:36 +00:00
msg_hash_to_str(MSG_BRINGING_UP_COMMAND_INTERFACE_ON_PORT),
(unsigned short)port);
fd = socket_init((void**)&res, port, NULL, SOCKET_TYPE_DATAGRAM);
if (fd < 0)
goto error;
handle->net_fd = fd;
if (!socket_nonblock(handle->net_fd))
goto error;
if (!socket_bind(handle->net_fd, (void*)res))
{
2016-10-20 16:23:34 +00:00
RARCH_ERR("%s.\n",
msg_hash_to_str(MSG_FAILED_TO_BIND_SOCKET));
goto error;
}
freeaddrinfo_retro(res);
return true;
error:
if (res)
freeaddrinfo_retro(res);
return false;
}
2016-05-09 19:36:17 +00:00
static bool send_udp_packet(const char *host,
uint16_t port, const char *msg)
{
char port_buf[16] = {0};
struct addrinfo hints = {0};
struct addrinfo *res = NULL;
const struct addrinfo *tmp = NULL;
int fd = -1;
bool ret = true;
hints.ai_socktype = SOCK_DGRAM;
snprintf(port_buf, sizeof(port_buf), "%hu", (unsigned short)port);
if (getaddrinfo_retro(host, port_buf, &hints, &res) < 0)
return false;
/* Send to all possible targets.
* "localhost" might resolve to several different IPs. */
tmp = (const struct addrinfo*)res;
while (tmp)
{
ssize_t len, ret_len;
fd = socket(tmp->ai_family, tmp->ai_socktype, tmp->ai_protocol);
if (fd < 0)
{
ret = false;
goto end;
}
len = strlen(msg);
ret_len = sendto(fd, msg, len, 0, tmp->ai_addr, tmp->ai_addrlen);
if (ret_len < len)
{
ret = false;
goto end;
}
socket_close(fd);
fd = -1;
tmp = tmp->ai_next;
}
end:
freeaddrinfo_retro(res);
if (fd >= 0)
socket_close(fd);
return ret;
}
static bool command_verify(const char *cmd)
{
unsigned i;
if (command_get_arg(cmd, NULL, NULL))
return true;
RARCH_ERR("Command \"%s\" is not recognized by the program.\n", cmd);
RARCH_ERR("\tValid commands:\n");
for (i = 0; i < sizeof(map) / sizeof(map[0]); i++)
RARCH_ERR("\t\t%s\n", map[i].str);
for (i = 0; i < sizeof(action_map) / sizeof(action_map[0]); i++)
RARCH_ERR("\t\t%s %s\n", action_map[i].str, action_map[i].arg_desc);
return false;
}
bool command_network_send(const char *cmd_)
{
bool ret = false;
2016-05-09 19:36:17 +00:00
char *command = NULL;
char *save = NULL;
const char *cmd = NULL;
const char *host = NULL;
const char *port_ = NULL;
uint16_t port = DEFAULT_NETWORK_CMD_PORT;
if (!network_init())
return false;
if (!(command = strdup(cmd_)))
return false;
cmd = strtok_r(command, ";", &save);
if (cmd)
host = strtok_r(NULL, ";", &save);
if (host)
port_ = strtok_r(NULL, ";", &save);
if (!host)
{
#ifdef _WIN32
host = "127.0.0.1";
#else
host = "localhost";
#endif
}
if (port_)
port = strtoul(port_, NULL, 0);
if (cmd)
{
RARCH_LOG("%s: \"%s\" to %s:%hu\n",
msg_hash_to_str(MSG_SENDING_COMMAND),
cmd, host, (unsigned short)port);
2016-05-09 19:36:17 +00:00
ret = command_verify(cmd) && send_udp_packet(host, port, cmd);
}
2016-05-09 19:36:17 +00:00
free(command);
return ret;
}
2017-01-17 14:35:51 +00:00
#ifdef HAVE_COMMAND
2016-05-09 19:23:53 +00:00
static void command_network_poll(command_t *handle)
{
2014-08-02 23:38:49 +00:00
fd_set fds;
struct timeval tmp_tv = {0};
2012-07-24 00:47:28 +00:00
if (handle->net_fd < 0)
return;
FD_ZERO(&fds);
2012-07-24 00:47:28 +00:00
FD_SET(handle->net_fd, &fds);
if (socket_select(handle->net_fd + 1, &fds, NULL, NULL, &tmp_tv) <= 0)
return;
2012-07-24 00:47:28 +00:00
if (!FD_ISSET(handle->net_fd, &fds))
return;
for (;;)
{
2016-06-06 22:03:07 +00:00
ssize_t ret;
char buf[1024];
2016-10-22 03:05:07 +00:00
buf[0] = '\0';
lastcmd_net_fd = handle->net_fd;
lastcmd_net_source_len = sizeof(lastcmd_net_source);
2016-06-06 22:03:07 +00:00
ret = recvfrom(handle->net_fd, buf,
sizeof(buf) - 1, 0, (struct sockaddr*)&lastcmd_net_source, &lastcmd_net_source_len);
2014-08-02 23:38:49 +00:00
if (ret <= 0)
break;
buf[ret] = '\0';
2016-09-11 15:37:05 +00:00
command_parse_msg(handle, buf, CMD_NETWORK);
}
}
2012-07-24 00:47:28 +00:00
#endif
2017-01-17 14:35:51 +00:00
#endif
2012-07-24 00:47:28 +00:00
2016-05-09 19:36:17 +00:00
#ifdef HAVE_STDIN_CMD
static bool command_stdin_init(command_t *handle)
{
#ifndef _WIN32
2016-09-29 19:07:10 +00:00
#ifdef HAVE_NETWORKING
2016-05-09 19:36:17 +00:00
if (!socket_nonblock(STDIN_FILENO))
return false;
#endif
#endif
handle->stdin_enable = true;
return true;
}
#endif
command_t *command_new(bool local_enable)
{
command_t *handle = (command_t*)calloc(1, sizeof(*handle));
if (!handle)
return NULL;
handle->local_enable = local_enable;
return handle;
}
bool command_network_new(
command_t *handle,
bool stdin_enable,
bool network_enable,
uint16_t port)
{
if (!handle)
return false;
2016-09-29 19:07:10 +00:00
#if defined(HAVE_NETWORKING) && defined(HAVE_NETWORK_CMD)
2016-05-09 19:36:17 +00:00
handle->net_fd = -1;
if (network_enable && !command_network_init(handle, port))
goto error;
#endif
#ifdef HAVE_STDIN_CMD
handle->stdin_enable = stdin_enable;
if (stdin_enable && !command_stdin_init(handle))
goto error;
#endif
return true;
2016-09-29 19:07:10 +00:00
#if (defined(HAVE_NETWORK_CMD) && defined(HAVE_NETWORKING)) || defined(HAVE_STDIN_CMD)
2016-05-09 19:36:17 +00:00
error:
command_free(handle);
return false;
#endif
}
2012-07-24 00:47:28 +00:00
#ifdef HAVE_STDIN_CMD
#ifdef _WIN32
static size_t read_stdin(char *buf, size_t size)
{
2013-10-22 19:26:33 +00:00
DWORD i;
2015-07-02 19:35:57 +00:00
DWORD has_read = 0;
2016-02-13 06:20:55 +00:00
DWORD avail = 0;
bool echo = false;
HANDLE hnd = GetStdHandle(STD_INPUT_HANDLE);
2015-07-02 19:35:57 +00:00
if (hnd == INVALID_HANDLE_VALUE)
return 0;
2014-09-02 03:10:54 +00:00
/* Check first if we're a pipe
* (not console). */
2014-09-02 03:10:54 +00:00
/* If not a pipe, check if we're running in a console. */
if (!PeekNamedPipe(hnd, NULL, 0, NULL, &avail, NULL))
{
2015-07-02 19:35:57 +00:00
INPUT_RECORD recs[256];
2016-10-22 03:05:07 +00:00
bool has_key = false;
DWORD mode = 0;
DWORD has_read = 0;
2015-07-02 19:35:57 +00:00
if (!GetConsoleMode(hnd, &mode))
return 0;
if ((mode & (ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT))
2014-09-02 03:10:54 +00:00
&& !SetConsoleMode(hnd,
mode & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT)))
return 0;
2014-09-02 03:10:54 +00:00
/* Win32, Y U NO SANE NONBLOCK READ!? */
if (!PeekConsoleInput(hnd, recs,
sizeof(recs) / sizeof(recs[0]), &has_read))
return 0;
2013-10-22 19:26:33 +00:00
for (i = 0; i < has_read; i++)
{
2014-09-02 03:10:54 +00:00
/* Very crude, but should get the job done. */
if (recs[i].EventType == KEY_EVENT &&
recs[i].Event.KeyEvent.bKeyDown &&
2014-09-02 03:10:54 +00:00
(isgraph(recs[i].Event.KeyEvent.wVirtualKeyCode) ||
recs[i].Event.KeyEvent.wVirtualKeyCode == VK_RETURN))
{
has_key = true;
echo = true;
avail = size;
break;
}
}
if (!has_key)
{
FlushConsoleInputBuffer(hnd);
return 0;
}
}
if (!avail)
return 0;
if (avail > size)
avail = size;
2012-08-07 19:31:43 +00:00
if (!ReadFile(hnd, buf, avail, &has_read, NULL))
return 0;
2013-10-22 19:26:33 +00:00
for (i = 0; i < has_read; i++)
if (buf[i] == '\r')
buf[i] = '\n';
2014-09-02 03:10:54 +00:00
/* Console won't echo for us while in non-line mode,
* so do it manually ... */
if (echo)
{
HANDLE hnd_out = GetStdHandle(STD_OUTPUT_HANDLE);
if (hnd_out != INVALID_HANDLE_VALUE)
{
DWORD has_written;
WriteConsole(hnd_out, buf, has_read, &has_written, NULL);
}
}
return has_read;
}
2012-07-24 00:47:28 +00:00
#else
2014-09-02 03:10:54 +00:00
2012-07-24 00:47:28 +00:00
static size_t read_stdin(char *buf, size_t size)
{
size_t has_read = 0;
2016-10-22 03:05:07 +00:00
2012-07-24 00:47:28 +00:00
while (size)
{
ssize_t ret = read(STDIN_FILENO, buf, size);
if (ret <= 0)
break;
buf += ret;
has_read += ret;
size -= ret;
}
return has_read;
}
#endif
2016-05-09 19:23:53 +00:00
static void command_stdin_poll(command_t *handle)
2012-07-24 00:47:28 +00:00
{
2014-08-02 23:38:49 +00:00
ssize_t ret;
ptrdiff_t msg_len;
2016-10-22 03:05:07 +00:00
char *last_newline = NULL;
2014-08-02 23:38:49 +00:00
2012-07-24 00:47:28 +00:00
if (!handle->stdin_enable)
return;
2014-09-02 03:10:54 +00:00
ret = read_stdin(handle->stdin_buf + handle->stdin_buf_ptr,
STDIN_BUF_SIZE - handle->stdin_buf_ptr - 1);
2012-07-24 00:47:28 +00:00
if (ret == 0)
return;
handle->stdin_buf_ptr += ret;
handle->stdin_buf[handle->stdin_buf_ptr] = '\0';
2014-08-02 23:38:49 +00:00
last_newline = strrchr(handle->stdin_buf, '\n');
2012-07-24 00:47:28 +00:00
if (!last_newline)
{
2015-01-29 01:29:07 +00:00
/* We're receiving bogus data in pipe
2014-09-02 03:10:54 +00:00
* (no terminating newline), flush out the buffer. */
if (handle->stdin_buf_ptr + 1 >= STDIN_BUF_SIZE)
{
handle->stdin_buf_ptr = 0;
handle->stdin_buf[0] = '\0';
}
2012-07-24 00:47:28 +00:00
return;
}
2012-07-24 00:47:28 +00:00
*last_newline++ = '\0';
2014-08-02 23:38:49 +00:00
msg_len = last_newline - handle->stdin_buf;
2016-09-11 15:37:05 +00:00
command_parse_msg(handle, handle->stdin_buf, CMD_STDIN);
2012-07-24 00:47:28 +00:00
2014-09-02 03:10:54 +00:00
memmove(handle->stdin_buf, last_newline,
handle->stdin_buf_ptr - msg_len);
2012-07-24 00:47:28 +00:00
handle->stdin_buf_ptr -= msg_len;
}
#endif
#endif
2016-05-09 19:36:17 +00:00
static void command_local_poll(command_t *handle)
{
if (!handle->local_enable)
return;
}
2016-05-09 19:23:53 +00:00
2016-05-09 18:10:08 +00:00
bool command_poll(command_t *handle)
2016-02-13 06:19:21 +00:00
{
2016-05-07 22:25:04 +00:00
memset(handle->state, 0, sizeof(handle->state));
2016-02-13 06:19:21 +00:00
2016-09-29 19:07:10 +00:00
#if defined(HAVE_NETWORKING) && defined(HAVE_NETWORK_CMD)
2017-01-17 14:35:51 +00:00
#ifdef HAVE_COMMAND
2016-05-09 19:23:53 +00:00
command_network_poll(handle);
2016-02-13 06:19:21 +00:00
#endif
2017-01-17 14:35:51 +00:00
#endif
2016-02-13 06:19:21 +00:00
#ifdef HAVE_STDIN_CMD
2016-05-09 19:23:53 +00:00
command_stdin_poll(handle);
2016-02-13 06:19:21 +00:00
#endif
2016-05-07 22:25:04 +00:00
2016-05-09 19:36:17 +00:00
command_local_poll(handle);
2016-05-07 22:25:04 +00:00
return true;
}
2016-05-09 19:23:53 +00:00
bool command_get(command_handle_t *handle)
{
if (!handle || !handle->handle)
return false;
return handle->id < RARCH_BIND_LIST_END
2016-05-09 19:23:53 +00:00
&& handle->handle->state[handle->id];
}
2016-05-09 18:10:08 +00:00
bool command_set(command_handle_t *handle)
2016-05-07 22:25:04 +00:00
{
if (!handle || !handle->handle)
return false;
if (handle->id < RARCH_BIND_LIST_END)
handle->handle->state[handle->id] = true;
return true;
}
2016-05-09 18:10:08 +00:00
bool command_free(command_t *handle)
2016-05-07 22:25:04 +00:00
{
2016-09-29 19:07:10 +00:00
#if defined(HAVE_NETWORKING) && defined(HAVE_NETWORK_CMD)
2017-01-17 14:39:14 +00:00
#ifdef HAVE_COMMAND
2016-05-07 22:25:04 +00:00
if (handle && handle->net_fd >= 0)
socket_close(handle->net_fd);
2017-01-17 14:39:14 +00:00
#endif
2016-02-13 06:19:21 +00:00
#endif
2016-05-07 22:25:04 +00:00
free(handle);
2016-02-13 06:19:21 +00:00
return true;
}
2016-05-07 22:25:04 +00:00
2016-05-09 18:30:47 +00:00
/**
2016-05-09 18:41:59 +00:00
* command_event_disk_control_set_eject:
2016-05-09 18:30:47 +00:00
* @new_state : Eject or close the virtual drive tray.
* false (0) : Close
* true (1) : Eject
* @print_log : Show message onscreen.
*
* Ejects/closes of the virtual drive tray.
**/
2016-05-09 18:41:59 +00:00
static void command_event_disk_control_set_eject(bool new_state, bool print_log)
2016-05-09 18:30:47 +00:00
{
2016-10-22 03:05:07 +00:00
char msg[128];
2016-05-09 18:30:47 +00:00
bool error = false;
const struct retro_disk_control_callback *control = NULL;
2017-04-23 14:41:26 +00:00
rarch_system_info_t *info = runloop_get_system_info();
2016-10-22 03:05:07 +00:00
msg[0] = '\0';
2016-05-09 18:30:47 +00:00
if (info)
control = (const struct retro_disk_control_callback*)&info->disk_control_cb;
if (!control || !control->get_num_images)
return;
if (control->set_eject_state(new_state))
snprintf(msg, sizeof(msg), "%s %s",
new_state ?
msg_hash_to_str(MSG_DISK_EJECTED) :
2016-06-27 06:19:39 +00:00
msg_hash_to_str(MSG_DISK_CLOSED),
2016-05-09 18:30:47 +00:00
msg_hash_to_str(MSG_VIRTUAL_DISK_TRAY));
else
{
error = true;
snprintf(msg, sizeof(msg), "%s %s %s",
msg_hash_to_str(MSG_FAILED_TO),
new_state ? "eject" : "close",
msg_hash_to_str(MSG_VIRTUAL_DISK_TRAY));
}
2016-06-28 09:02:51 +00:00
if (!string_is_empty(msg))
2016-05-09 18:30:47 +00:00
{
if (error)
RARCH_ERR("%s\n", msg);
else
RARCH_LOG("%s\n", msg);
/* Only noise in menu. */
if (print_log)
runloop_msg_queue_push(msg, 1, 180, true);
2016-05-09 18:30:47 +00:00
}
}
/**
2016-05-09 18:41:59 +00:00
* command_event_disk_control_set_index:
2016-05-09 18:30:47 +00:00
* @idx : Index of disk to set as current.
*
* Sets current disk to @index.
**/
2016-05-09 18:41:59 +00:00
static void command_event_disk_control_set_index(unsigned idx)
2016-05-09 18:30:47 +00:00
{
unsigned num_disks;
2016-10-22 03:05:07 +00:00
char msg[128];
2016-05-09 18:30:47 +00:00
bool error = false;
const struct retro_disk_control_callback *control = NULL;
2017-04-23 14:41:26 +00:00
rarch_system_info_t *info = runloop_get_system_info();
2016-10-22 03:05:07 +00:00
msg[0] = '\0';
2016-05-09 18:30:47 +00:00
if (info)
control = (const struct retro_disk_control_callback*)&info->disk_control_cb;
if (!control || !control->get_num_images)
return;
num_disks = control->get_num_images();
if (control->set_image_index(idx))
{
if (idx < num_disks)
2016-10-22 03:05:07 +00:00
snprintf(msg, sizeof(msg), "%s: %u/%u.",
msg_hash_to_str(MSG_SETTING_DISK_IN_TRAY),
2016-05-09 18:30:47 +00:00
idx + 1, num_disks);
else
strlcpy(msg,
msg_hash_to_str(MSG_REMOVED_DISK_FROM_TRAY),
sizeof(msg));
}
else
{
if (idx < num_disks)
2016-10-22 03:05:07 +00:00
snprintf(msg, sizeof(msg), "%s %u/%u.",
msg_hash_to_str(MSG_FAILED_TO_SET_DISK),
2016-05-09 18:30:47 +00:00
idx + 1, num_disks);
else
strlcpy(msg,
msg_hash_to_str(MSG_FAILED_TO_REMOVE_DISK_FROM_TRAY),
sizeof(msg));
error = true;
}
2016-06-28 09:02:51 +00:00
if (!string_is_empty(msg))
2016-05-09 18:30:47 +00:00
{
if (error)
RARCH_ERR("%s\n", msg);
else
RARCH_LOG("%s\n", msg);
runloop_msg_queue_push(msg, 1, 180, true);
2016-05-09 18:30:47 +00:00
}
}
/**
2016-05-09 18:41:59 +00:00
* command_event_disk_control_append_image:
2016-05-09 18:30:47 +00:00
* @path : Path to disk image.
*
* Appends disk image to disk image list.
**/
2016-05-09 18:41:59 +00:00
static bool command_event_disk_control_append_image(const char *path)
2016-05-09 18:30:47 +00:00
{
unsigned new_idx;
2016-10-22 03:05:07 +00:00
char msg[128];
2016-05-09 18:30:47 +00:00
struct retro_game_info info = {0};
const struct retro_disk_control_callback *control = NULL;
2017-04-23 14:41:26 +00:00
rarch_system_info_t *sysinfo = runloop_get_system_info();
2016-10-22 03:05:07 +00:00
msg[0] = '\0';
2016-05-09 18:30:47 +00:00
if (sysinfo)
control = (const struct retro_disk_control_callback*)
&sysinfo->disk_control_cb;
if (!control)
return false;
2016-05-09 18:41:59 +00:00
command_event_disk_control_set_eject(true, false);
2016-05-09 18:30:47 +00:00
control->add_image_index();
new_idx = control->get_num_images();
if (!new_idx)
return false;
new_idx--;
info.path = path;
control->replace_image_index(new_idx, &info);
snprintf(msg, sizeof(msg), "%s: ", msg_hash_to_str(MSG_APPENDED_DISK));
strlcat(msg, path, sizeof(msg));
RARCH_LOG("%s\n", msg);
runloop_msg_queue_push(msg, 0, 180, true);
2016-05-09 18:30:47 +00:00
2016-05-09 18:51:53 +00:00
command_event(CMD_EVENT_AUTOSAVE_DEINIT, NULL);
2016-05-09 18:30:47 +00:00
/* TODO: Need to figure out what to do with subsystems case. */
2016-09-30 02:43:16 +00:00
if (path_is_empty(RARCH_PATH_SUBSYSTEM))
2016-05-09 18:30:47 +00:00
{
/* Update paths for our new image.
* If we actually use append_image, we assume that we
* started out in a single disk case, and that this way
* of doing it makes the most sense. */
path_set(RARCH_PATH_NAMES, path);
path_fill_names();
2016-05-09 18:30:47 +00:00
}
2016-05-09 18:51:53 +00:00
command_event(CMD_EVENT_AUTOSAVE_INIT, NULL);
2016-05-09 18:41:59 +00:00
command_event_disk_control_set_index(new_idx);
command_event_disk_control_set_eject(false, false);
2016-05-09 18:30:47 +00:00
return true;
}
/**
2016-05-09 18:41:59 +00:00
* command_event_check_disk_prev:
2016-05-09 18:30:47 +00:00
* @control : Handle to disk control handle.
*
* Perform disk cycle to previous index action (Core Disk Options).
**/
2016-05-09 18:41:59 +00:00
static void command_event_check_disk_prev(
2016-05-09 18:30:47 +00:00
const struct retro_disk_control_callback *control)
{
unsigned num_disks = 0;
unsigned current = 0;
bool disk_prev_enable = false;
if (!control || !control->get_num_images)
return;
if (!control->get_image_index)
return;
num_disks = control->get_num_images();
current = control->get_image_index();
disk_prev_enable = num_disks && num_disks != UINT_MAX;
if (!disk_prev_enable)
{
RARCH_ERR("%s.\n", msg_hash_to_str(MSG_GOT_INVALID_DISK_INDEX));
return;
}
if (current > 0)
current--;
2016-05-09 18:41:59 +00:00
command_event_disk_control_set_index(current);
2016-05-09 18:30:47 +00:00
}
/**
2016-05-09 18:41:59 +00:00
* command_event_check_disk_next:
2016-05-09 18:30:47 +00:00
* @control : Handle to disk control handle.
*
* Perform disk cycle to next index action (Core Disk Options).
**/
2016-05-09 18:41:59 +00:00
static void command_event_check_disk_next(
2016-05-09 18:30:47 +00:00
const struct retro_disk_control_callback *control)
{
unsigned num_disks = 0;
unsigned current = 0;
bool disk_next_enable = false;
if (!control || !control->get_num_images)
return;
if (!control->get_image_index)
return;
num_disks = control->get_num_images();
current = control->get_image_index();
disk_next_enable = num_disks && num_disks != UINT_MAX;
if (!disk_next_enable)
{
RARCH_ERR("%s.\n", msg_hash_to_str(MSG_GOT_INVALID_DISK_INDEX));
return;
}
if (current < num_disks - 1)
current++;
2016-05-09 18:41:59 +00:00
command_event_disk_control_set_index(current);
2016-05-09 18:30:47 +00:00
}
/**
* event_set_volume:
* @gain : amount of gain to be applied to current volume level.
*
* Adjusts the current audio volume level.
*
**/
2016-05-09 18:41:59 +00:00
static void command_event_set_volume(float gain)
2016-05-09 18:30:47 +00:00
{
char msg[128];
settings_t *settings = config_get_ptr();
2017-04-28 12:57:55 +00:00
float new_volume = settings->floats.audio_volume + gain;
2016-05-09 18:30:47 +00:00
2017-04-23 15:36:25 +00:00
new_volume = MAX(new_volume, -80.0f);
2017-04-23 15:51:06 +00:00
new_volume = MIN(new_volume, 12.0f);
2017-04-23 15:36:25 +00:00
2017-04-28 12:57:55 +00:00
configuration_set_float(settings, settings->floats.audio_volume, new_volume);
2016-05-09 18:30:47 +00:00
2016-10-28 14:09:52 +00:00
snprintf(msg, sizeof(msg), "%s: %.1f dB",
2016-10-22 03:05:07 +00:00
msg_hash_to_str(MSG_AUDIO_VOLUME),
2017-04-23 15:36:25 +00:00
new_volume);
runloop_msg_queue_push(msg, 1, 180, true);
2016-05-09 18:30:47 +00:00
RARCH_LOG("%s\n", msg);
2017-04-23 15:36:25 +00:00
audio_driver_set_volume_gain(db_to_gain(new_volume));
2016-05-09 18:30:47 +00:00
}
/**
2016-05-09 18:41:59 +00:00
* command_event_init_controllers:
2016-05-09 18:30:47 +00:00
*
* Initialize libretro controllers.
**/
2016-05-09 18:41:59 +00:00
static void command_event_init_controllers(void)
2016-05-09 18:30:47 +00:00
{
unsigned i;
2017-04-23 14:41:26 +00:00
rarch_system_info_t *info = runloop_get_system_info();
2016-05-09 18:30:47 +00:00
for (i = 0; i < MAX_USERS; i++)
{
retro_ctx_controller_info_t pad;
2017-04-23 15:36:25 +00:00
const char *ident = NULL;
bool set_controller = false;
2016-05-09 18:30:47 +00:00
const struct retro_controller_description *desc = NULL;
2017-04-25 15:14:46 +00:00
unsigned device = input_config_get_device(i);
2016-05-09 18:30:47 +00:00
2016-06-01 03:18:59 +00:00
if (info)
{
if (i < info->ports.size)
desc = libretro_find_controller_description(
&info->ports.data[i], device);
}
2016-05-09 18:30:47 +00:00
if (desc)
ident = desc->desc;
if (!ident)
{
/* If we're trying to connect a completely unknown device,
* revert back to JOYPAD. */
if (device != RETRO_DEVICE_JOYPAD && device != RETRO_DEVICE_NONE)
{
2017-04-25 15:14:46 +00:00
/* Do not fix device,
2016-05-09 18:30:47 +00:00
* because any use of dummy core will reset this,
* which is not a good idea. */
RARCH_WARN("Input device ID %u is unknown to this "
"libretro implementation. Using RETRO_DEVICE_JOYPAD.\n",
device);
device = RETRO_DEVICE_JOYPAD;
}
ident = "Joypad";
}
switch (device)
{
case RETRO_DEVICE_NONE:
2016-08-22 00:38:19 +00:00
RARCH_LOG("%s %u.\n",
msg_hash_to_str(MSG_VALUE_DISCONNECTING_DEVICE_FROM_PORT),
i + 1);
2016-05-09 18:30:47 +00:00
set_controller = true;
break;
case RETRO_DEVICE_JOYPAD:
break;
default:
/* Some cores do not properly range check port argument.
* This is broken behavior of course, but avoid breaking
* cores needlessly. */
RARCH_LOG("%s %u: %s (ID: %u).\n",
msg_hash_to_str(MSG_CONNECTING_TO_PORT),
device, ident, i+1);
2016-05-09 18:30:47 +00:00
set_controller = true;
break;
}
if (set_controller)
{
pad.device = device;
pad.port = i;
core_set_controller_port_device(&pad);
}
}
}
2016-05-09 18:41:59 +00:00
static void command_event_deinit_core(bool reinit)
2016-05-09 18:30:47 +00:00
{
#ifdef HAVE_CHEEVOS
cheevos_unload();
#endif
core_unload_game();
core_unload();
2016-07-23 05:06:32 +00:00
core_uninit_symbols();
2016-05-09 18:30:47 +00:00
if (reinit)
{
int flags = DRIVERS_CMD_ALL;
driver_ctl(RARCH_DRIVER_CTL_UNINIT, &flags);
}
2016-05-20 22:54:29 +00:00
command_event(CMD_EVENT_DISABLE_OVERRIDES, NULL);
2016-07-30 19:36:01 +00:00
command_event(CMD_EVENT_RESTORE_DEFAULT_SHADER_PRESET, NULL);
2016-05-09 18:30:47 +00:00
}
static void command_event_init_cheats(void)
2016-05-09 18:30:47 +00:00
{
bool allow_cheats = true;
2016-09-29 19:07:10 +00:00
#ifdef HAVE_NETWORKING
2016-05-09 18:30:47 +00:00
allow_cheats &= !netplay_driver_ctl(
RARCH_NETPLAY_CTL_IS_DATA_INITED, NULL);
#endif
allow_cheats &= !bsv_movie_ctl(BSV_MOVIE_CTL_IS_INITED, NULL);
if (!allow_cheats)
return;
2016-05-09 18:30:47 +00:00
/* TODO/FIXME - add some stuff here. */
}
2016-05-09 18:41:59 +00:00
static void command_event_load_auto_state(void)
2016-05-09 18:30:47 +00:00
{
bool ret;
char msg[128] = {0};
char savestate_name_auto[PATH_MAX_LENGTH] = {0};
settings_t *settings = config_get_ptr();
global_t *global = global_get_ptr();
2016-05-09 18:30:47 +00:00
#ifdef HAVE_NETWORKING
if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL))
2016-05-09 18:30:47 +00:00
return;
#endif
#ifdef HAVE_CHEEVOS
2017-04-28 11:43:47 +00:00
if (settings->bools.cheevos_hardcore_mode_enable)
2016-05-09 18:30:47 +00:00
return;
#endif
2017-04-28 11:43:47 +00:00
if (!settings->bools.savestate_auto_load)
2016-05-09 18:30:47 +00:00
return;
if (global)
fill_pathname_noext(savestate_name_auto, global->name.savestate,
file_path_str(FILE_PATH_AUTO_EXTENSION),
sizeof(savestate_name_auto));
2016-05-09 18:30:47 +00:00
if (!path_file_exists(savestate_name_auto))
return;
2016-10-02 08:03:35 +00:00
ret = content_load_state(savestate_name_auto, false, true);
2016-05-09 18:30:47 +00:00
2016-10-20 16:23:34 +00:00
RARCH_LOG("%s: %s\n", msg_hash_to_str(MSG_FOUND_AUTO_SAVESTATE_IN),
savestate_name_auto);
2016-05-09 18:30:47 +00:00
2016-10-20 16:08:31 +00:00
snprintf(msg, sizeof(msg), "%s \"%s\" %s.",
msg_hash_to_str(MSG_AUTOLOADING_SAVESTATE_FROM),
2016-05-09 18:30:47 +00:00
savestate_name_auto, ret ? "succeeded" : "failed");
RARCH_LOG("%s\n", msg);
}
2016-05-09 18:41:59 +00:00
static void command_event_set_savestate_auto_index(void)
2016-05-09 18:30:47 +00:00
{
size_t i;
char state_dir[PATH_MAX_LENGTH] = {0};
char state_base[PATH_MAX_LENGTH] = {0};
struct string_list *dir_list = NULL;
unsigned max_idx = 0;
settings_t *settings = config_get_ptr();
global_t *global = global_get_ptr();
2016-05-09 18:30:47 +00:00
2017-04-28 11:43:47 +00:00
if (!settings->bools.savestate_auto_index)
2016-05-09 18:30:47 +00:00
return;
if (global)
{
/* Find the file in the same directory as global->savestate_name
* with the largest numeral suffix.
*
* E.g. /foo/path/content.state, will try to find
* /foo/path/content.state%d, where %d is the largest number available.
*/
fill_pathname_basedir(state_dir, global->name.savestate,
sizeof(state_dir));
fill_pathname_base(state_base, global->name.savestate,
sizeof(state_base));
}
2016-05-09 18:30:47 +00:00
dir_list = dir_list_new_special(state_dir, DIR_LIST_PLAIN, NULL);
2016-05-09 18:30:47 +00:00
if (!dir_list)
2016-05-09 18:30:47 +00:00
return;
for (i = 0; i < dir_list->size; i++)
{
unsigned idx;
char elem_base[128] = {0};
const char *end = NULL;
const char *dir_elem = dir_list->elems[i].data;
fill_pathname_base(elem_base, dir_elem, sizeof(elem_base));
if (strstr(elem_base, state_base) != elem_base)
continue;
end = dir_elem + strlen(dir_elem);
while ((end > dir_elem) && isdigit((int)end[-1]))
end--;
idx = (unsigned)strtoul(end, NULL, 0);
2016-05-09 18:30:47 +00:00
if (idx > max_idx)
max_idx = idx;
}
dir_list_free(dir_list);
2017-04-28 17:12:48 +00:00
configuration_set_int(settings, settings->ints.state_slot, max_idx);
2017-04-23 15:36:25 +00:00
2016-08-22 11:41:11 +00:00
RARCH_LOG("%s: #%d\n",
2016-10-22 22:35:40 +00:00
msg_hash_to_str(MSG_FOUND_LAST_STATE_SLOT),
2017-04-23 15:36:25 +00:00
max_idx);
2016-05-09 18:30:47 +00:00
}
static bool event_init_content(void)
{
2017-01-25 14:44:21 +00:00
bool contentless = false;
bool is_inited = false;
2017-01-25 14:44:21 +00:00
content_get_status(&contentless, &is_inited);
2017-01-25 14:44:21 +00:00
2016-05-09 18:30:47 +00:00
rarch_ctl(RARCH_CTL_SET_SRAM_ENABLE, NULL);
/* No content to be loaded for dummy core,
* just successfully exit. */
if (rarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL))
return true;
2017-01-25 14:44:21 +00:00
if (!contentless)
path_fill_names();
2016-05-09 18:30:47 +00:00
if (!content_init())
return false;
content_get_status(&contentless, &is_inited);
2017-01-25 14:44:21 +00:00
2016-05-09 18:41:59 +00:00
command_event_set_savestate_auto_index();
2016-05-09 18:30:47 +00:00
if (event_load_save_files())
RARCH_LOG("%s.\n",
msg_hash_to_str(MSG_SKIPPING_SRAM_LOAD));
2016-05-09 18:41:59 +00:00
command_event_load_auto_state();
2016-05-09 18:51:53 +00:00
command_event(CMD_EVENT_BSV_MOVIE_INIT, NULL);
command_event(CMD_EVENT_NETPLAY_INIT, NULL);
2016-05-09 18:30:47 +00:00
return true;
}
2016-05-09 19:36:17 +00:00
static bool command_event_init_core(enum rarch_core_type *data)
2016-05-09 18:30:47 +00:00
{
retro_ctx_environ_info_t info;
settings_t *settings = config_get_ptr();
if (!core_init_symbols(data))
return false;
runloop_ctl(RUNLOOP_CTL_SYSTEM_INFO_INIT, NULL);
2016-05-09 18:30:47 +00:00
/* auto overrides: apply overrides */
2017-04-28 11:43:47 +00:00
if(settings->bools.auto_overrides_enable)
2016-05-09 18:30:47 +00:00
{
if (config_load_override())
runloop_ctl(RUNLOOP_CTL_SET_OVERRIDES_ACTIVE, NULL);
else
runloop_ctl(RUNLOOP_CTL_UNSET_OVERRIDES_ACTIVE, NULL);
}
2016-07-30 18:55:50 +00:00
/* Auto-remap: apply shader preset files */
2017-04-28 11:43:47 +00:00
if(settings->bools.auto_shaders_enable)
2016-07-30 18:55:50 +00:00
config_load_shader_preset();
2016-05-09 18:30:47 +00:00
/* reset video format to libretro's default */
video_driver_set_pixel_format(RETRO_PIXEL_FORMAT_0RGB1555);
info.env = rarch_environment_cb;
core_set_environment(&info);
/* Auto-remap: apply remap files */
2017-04-28 11:43:47 +00:00
if(settings->bools.auto_remaps_enable)
2016-05-09 18:30:47 +00:00
config_load_remap();
/* Per-core saves: reset redirection paths */
rarch_ctl(RARCH_CTL_SET_PATHS_REDIRECT, NULL);
if (!core_init())
return false;
if (!event_init_content())
return false;
2017-04-28 19:03:04 +00:00
if (!core_load(settings->uints.input_poll_type_behavior))
2016-05-09 18:30:47 +00:00
return false;
2017-01-23 13:50:00 +00:00
runloop_ctl(RUNLOOP_CTL_SET_FRAME_LIMIT, NULL);
2016-05-09 18:30:47 +00:00
return true;
}
2016-05-20 22:54:29 +00:00
static void command_event_disable_overrides(void)
{
2016-09-23 01:50:10 +00:00
if (!runloop_ctl(RUNLOOP_CTL_IS_OVERRIDES_ACTIVE, NULL))
return;
/* reload the original config */
config_unload_override();
runloop_ctl(RUNLOOP_CTL_UNSET_OVERRIDES_ACTIVE, NULL);
2016-05-20 22:54:29 +00:00
}
2016-07-30 19:36:01 +00:00
static void command_event_restore_default_shader_preset(void)
{
2016-10-03 13:59:51 +00:00
if (!path_is_empty(RARCH_PATH_DEFAULT_SHADER_PRESET))
{
2016-10-03 13:59:51 +00:00
/* auto shader preset: reload the original shader */
2016-09-23 01:50:10 +00:00
settings_t *settings = config_get_ptr();
2016-10-20 16:23:34 +00:00
RARCH_LOG("%s %s\n",
msg_hash_to_str(MSG_RESTORING_DEFAULT_SHADER_PRESET_TO),
2016-10-03 13:59:51 +00:00
path_get(RARCH_PATH_DEFAULT_SHADER_PRESET));
2017-04-28 22:39:29 +00:00
strlcpy(settings->paths.path_shader,
2016-10-03 13:59:51 +00:00
path_get(RARCH_PATH_DEFAULT_SHADER_PRESET),
2017-04-28 22:39:29 +00:00
sizeof(settings->paths.path_shader));
}
2016-09-23 01:50:10 +00:00
2016-09-30 02:31:19 +00:00
path_clear(RARCH_PATH_DEFAULT_SHADER_PRESET);
2016-07-30 19:36:01 +00:00
}
2016-05-09 19:36:17 +00:00
static bool command_event_save_auto_state(void)
2016-05-09 18:30:47 +00:00
{
char savestate_name_auto[PATH_MAX_LENGTH] = {0};
2017-01-25 15:13:39 +00:00
bool ret = false;
2017-01-25 14:44:21 +00:00
bool contentless = false;
bool is_inited = false;
2016-05-09 18:30:47 +00:00
settings_t *settings = config_get_ptr();
global_t *global = global_get_ptr();
2016-05-09 18:30:47 +00:00
2017-04-28 11:43:47 +00:00
if (!settings || !settings->bools.savestate_auto_save)
return false;
if (!global)
return false;
2016-05-09 18:30:47 +00:00
if (rarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL))
return false;
2017-01-25 14:44:21 +00:00
content_get_status(&contentless, &is_inited);
2017-01-25 14:44:21 +00:00
if (contentless)
2016-05-09 18:30:47 +00:00
return false;
#ifdef HAVE_CHEEVOS
2017-04-28 11:43:47 +00:00
if (settings->bools.cheevos_hardcore_mode_enable)
2016-05-09 18:30:47 +00:00
return false;
#endif
fill_pathname_noext(savestate_name_auto, global->name.savestate,
2016-07-01 05:07:06 +00:00
file_path_str(FILE_PATH_AUTO_EXTENSION),
sizeof(savestate_name_auto));
2016-05-09 18:30:47 +00:00
ret = content_save_state((const char*)savestate_name_auto, true, true);
2016-10-28 14:09:52 +00:00
RARCH_LOG("%s \"%s\" %s.\n",
2016-10-20 16:23:34 +00:00
msg_hash_to_str(MSG_AUTO_SAVE_STATE_TO),
savestate_name_auto, ret ?
2016-05-09 18:30:47 +00:00
"succeeded" : "failed");
return true;
}
static bool command_event_save_config(const char *config_path,
char *s, size_t len)
{
if (string_is_empty(config_path) || !config_save_file(config_path))
{
snprintf(s, len, "%s \"%s\".",
msg_hash_to_str(MSG_FAILED_SAVING_CONFIG_TO),
2016-09-29 06:31:41 +00:00
path_get(RARCH_PATH_CONFIG));
RARCH_ERR("%s\n", s);
return false;
}
2016-09-24 14:54:01 +00:00
snprintf(s, len, "%s \"%s\".",
msg_hash_to_str(MSG_SAVED_NEW_CONFIG_TO),
2016-09-29 06:31:41 +00:00
path_get(RARCH_PATH_CONFIG));
RARCH_LOG("%s\n", s);
return true;
}
2016-05-09 18:30:47 +00:00
/**
2016-05-09 18:41:59 +00:00
* command_event_save_core_config:
2016-05-09 18:30:47 +00:00
*
* Saves a new (core) configuration to a file. Filename is based
* on heuristics to avoid typing.
*
* Returns: true (1) on success, otherwise false (0).
**/
2016-05-09 18:41:59 +00:00
static bool command_event_save_core_config(void)
2016-05-09 18:30:47 +00:00
{
2017-01-25 14:44:21 +00:00
char config_dir[PATH_MAX_LENGTH];
char config_name[PATH_MAX_LENGTH];
char config_path[PATH_MAX_LENGTH];
char msg[128];
2016-05-09 18:30:47 +00:00
bool ret = false;
bool found_path = false;
bool overrides_active = false;
settings_t *settings = config_get_ptr();
2017-01-25 14:44:21 +00:00
config_dir[0] = config_name[0] =
config_path[0] = msg[0] = '\0';
2017-04-28 22:39:29 +00:00
if (!string_is_empty(settings->paths.directory_menu_config))
strlcpy(config_dir, settings->paths.directory_menu_config,
2016-05-09 18:30:47 +00:00
sizeof(config_dir));
2016-09-30 02:43:16 +00:00
else if (!path_is_empty(RARCH_PATH_CONFIG)) /* Fallback */
2016-09-29 06:31:41 +00:00
fill_pathname_basedir(config_dir, path_get(RARCH_PATH_CONFIG),
2016-05-09 18:30:47 +00:00
sizeof(config_dir));
else
{
runloop_msg_queue_push(msg_hash_to_str(MSG_CONFIG_DIRECTORY_NOT_SET), 1, 180, true);
2016-05-09 18:30:47 +00:00
RARCH_ERR("%s\n", msg_hash_to_str(MSG_CONFIG_DIRECTORY_NOT_SET));
return false;
}
/* Infer file name based on libretro core. */
2016-09-29 06:23:41 +00:00
if (!string_is_empty(path_get(RARCH_PATH_CORE)) && path_file_exists(path_get(RARCH_PATH_CORE)))
2016-05-09 18:30:47 +00:00
{
unsigned i;
RARCH_LOG("%s\n", msg_hash_to_str(MSG_USING_CORE_NAME_FOR_NEW_CONFIG));
2016-05-09 18:30:47 +00:00
/* In case of collision, find an alternative name. */
for (i = 0; i < 16; i++)
{
char tmp[64] = {0};
2016-05-09 18:30:47 +00:00
fill_pathname_base_noext(
2016-05-09 18:30:47 +00:00
config_name,
2016-09-29 06:23:41 +00:00
path_get(RARCH_PATH_CORE),
2016-05-09 18:30:47 +00:00
sizeof(config_name));
fill_pathname_join(config_path, config_dir, config_name,
sizeof(config_path));
2016-05-09 18:30:47 +00:00
if (i)
2016-06-27 06:19:39 +00:00
snprintf(tmp, sizeof(tmp), "-%u%s",
i,
file_path_str(FILE_PATH_CONFIG_EXTENSION));
2016-05-09 18:30:47 +00:00
else
2016-06-27 06:19:39 +00:00
strlcpy(tmp,
file_path_str(FILE_PATH_CONFIG_EXTENSION),
sizeof(tmp));
2016-05-09 18:30:47 +00:00
strlcat(config_path, tmp, sizeof(config_path));
if (!path_file_exists(config_path))
{
found_path = true;
break;
}
}
}
if (!found_path)
{
/* Fallback to system time... */
RARCH_WARN("%s\n",
msg_hash_to_str(MSG_CANNOT_INFER_NEW_CONFIG_PATH));
2016-06-27 06:19:39 +00:00
fill_dated_filename(config_name,
file_path_str(FILE_PATH_CONFIG_EXTENSION),
sizeof(config_name));
2016-05-09 18:30:47 +00:00
fill_pathname_join(config_path, config_dir, config_name,
sizeof(config_path));
}
if (runloop_ctl(RUNLOOP_CTL_IS_OVERRIDES_ACTIVE, NULL))
{
/* Overrides block config file saving,
* make it appear as overrides weren't enabled
* for a manual save. */
2016-05-09 18:30:47 +00:00
runloop_ctl(RUNLOOP_CTL_UNSET_OVERRIDES_ACTIVE, NULL);
overrides_active = true;
}
command_event_save_config(config_path, msg, sizeof(msg));
2016-05-09 18:30:47 +00:00
runloop_msg_queue_push(msg, 1, 180, true);
2016-05-09 18:30:47 +00:00
if (overrides_active)
runloop_ctl(RUNLOOP_CTL_SET_OVERRIDES_ACTIVE, NULL);
else
runloop_ctl(RUNLOOP_CTL_UNSET_OVERRIDES_ACTIVE, NULL);
return ret;
}
/**
* event_save_current_config:
*
* Saves current configuration file to disk, and (optionally)
* autosave state.
**/
static void command_event_save_current_config(enum override_type type)
2016-05-09 18:30:47 +00:00
{
2017-01-25 14:44:21 +00:00
char msg[128];
msg[0] = '\0';
2016-05-09 18:30:47 +00:00
switch (type)
2016-08-25 06:34:51 +00:00
{
case OVERRIDE_NONE:
if (path_is_empty(RARCH_PATH_CONFIG))
strlcpy(msg, "Config directory not set, cannot save configuration.",
sizeof(msg));
else
command_event_save_config(path_get(RARCH_PATH_CONFIG), msg, sizeof(msg));
break;
case OVERRIDE_GAME:
case OVERRIDE_CORE:
if (config_save_overrides(type))
{
strlcpy(msg, msg_hash_to_str(MSG_OVERRIDES_SAVED_SUCCESSFULLY), sizeof(msg));
RARCH_LOG("[overrides] %s\n", msg);
/* set overrides to active so the original config can be
restored after closing content */
runloop_ctl(RUNLOOP_CTL_SET_OVERRIDES_ACTIVE, NULL);
}
else
{
strlcpy(msg, msg_hash_to_str(MSG_OVERRIDES_ERROR_SAVING), sizeof(msg));
RARCH_ERR("[overrides] %s\n", msg);
}
break;
}
2016-08-26 14:54:15 +00:00
if (!string_is_empty(msg))
runloop_msg_queue_push(msg, 1, 180, true);
2016-05-09 18:30:47 +00:00
}
static void command_event_undo_save_state(char *s, size_t len)
{
if (content_undo_save_buf_is_empty())
{
strlcpy(s,
msg_hash_to_str(MSG_NO_SAVE_STATE_HAS_BEEN_OVERWRITTEN_YET), len);
return;
}
if (!content_undo_save_state())
return;
}
static void command_event_undo_load_state(char *s, size_t len)
{
if (content_undo_load_buf_is_empty())
{
strlcpy(s,
msg_hash_to_str(MSG_NO_STATE_HAS_BEEN_LOADED_YET),
len);
return;
}
if (!content_undo_load_state())
{
snprintf(s, len, "%s \"%s\".",
msg_hash_to_str(MSG_FAILED_TO_UNDO_LOAD_STATE),
"RAM");
return;
}
2016-09-29 19:07:10 +00:00
#ifdef HAVE_NETWORKING
netplay_driver_ctl(RARCH_NETPLAY_CTL_LOAD_SAVESTATE, NULL);
#endif
strlcpy(s,
msg_hash_to_str(MSG_UNDID_LOAD_STATE), len);
2016-05-09 18:30:47 +00:00
}
2017-02-26 08:35:35 +00:00
static bool command_event_main_state(unsigned cmd)
2016-05-09 18:30:47 +00:00
{
retro_ctx_size_info_t info;
2017-01-25 14:44:21 +00:00
char path[PATH_MAX_LENGTH];
char msg[128];
2017-02-26 08:35:35 +00:00
bool ret = false;
global_t *global = global_get_ptr();
2016-10-02 08:03:35 +00:00
bool push_msg = true;
2016-05-09 18:30:47 +00:00
2017-01-25 14:44:21 +00:00
path[0] = msg[0] = '\0';
if (global)
{
settings_t *settings = config_get_ptr();
2017-04-28 17:12:48 +00:00
int state_slot = settings->ints.state_slot;
2017-01-25 14:44:21 +00:00
2017-04-28 17:12:48 +00:00
if (state_slot > 0)
2017-01-25 14:44:21 +00:00
snprintf(path, sizeof(path), "%s%d",
2017-04-28 17:12:48 +00:00
global->name.savestate, state_slot);
else if (state_slot < 0)
2017-01-25 14:44:21 +00:00
fill_pathname_join_delim(path,
global->name.savestate, "auto", '.', sizeof(path));
else
strlcpy(path, global->name.savestate, sizeof(path));
}
2016-05-09 18:30:47 +00:00
core_serialize_size(&info);
if (info.size)
{
switch (cmd)
{
2016-05-09 18:51:53 +00:00
case CMD_EVENT_SAVE_STATE:
content_save_state(path, true, false);
2017-02-26 08:35:35 +00:00
ret = true;
2016-10-02 08:03:35 +00:00
push_msg = false;
2016-05-09 18:30:47 +00:00
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_LOAD_STATE:
2016-10-03 01:30:34 +00:00
if (content_load_state(path, false, false))
{
2017-02-26 08:35:35 +00:00
ret = true;
2016-10-03 01:30:34 +00:00
#ifdef HAVE_NETWORKING
netplay_driver_ctl(RARCH_NETPLAY_CTL_LOAD_SAVESTATE, NULL);
#endif
}
2016-10-02 08:03:35 +00:00
push_msg = false;
break;
case CMD_EVENT_UNDO_LOAD_STATE:
command_event_undo_load_state(msg, sizeof(msg));
2017-02-26 08:35:35 +00:00
ret = true;
2016-05-09 18:30:47 +00:00
break;
2016-06-04 19:34:06 +00:00
case CMD_EVENT_UNDO_SAVE_STATE:
command_event_undo_save_state(msg, sizeof(msg));
2017-02-26 08:35:35 +00:00
ret = true;
2016-06-04 19:34:06 +00:00
break;
2016-05-09 18:30:47 +00:00
}
}
else
strlcpy(msg, msg_hash_to_str(
MSG_CORE_DOES_NOT_SUPPORT_SAVESTATES), sizeof(msg));
2016-10-02 08:03:35 +00:00
if (push_msg)
runloop_msg_queue_push(msg, 2, 180, true);
2016-05-09 18:30:47 +00:00
RARCH_LOG("%s\n", msg);
2017-02-26 08:35:35 +00:00
return ret;
2016-05-09 18:30:47 +00:00
}
2016-09-23 01:50:10 +00:00
void handle_quit_event(void)
{
command_event(CMD_EVENT_AUTOSAVE_STATE, NULL);
command_event(CMD_EVENT_DISABLE_OVERRIDES, NULL);
command_event(CMD_EVENT_RESTORE_DEFAULT_SHADER_PRESET, NULL);
#ifdef HAVE_DYNAMIC
2016-09-06 03:05:50 +00:00
#ifdef HAVE_MENU
menu_driver_ctl(RARCH_MENU_CTL_SYSTEM_INFO_DEINIT, NULL);
#endif
#endif
runloop_ctl(RUNLOOP_CTL_SET_SHUTDOWN, NULL);
#ifdef HAVE_MENU
rarch_ctl(RARCH_CTL_MENU_RUNNING_FINISHED, NULL);
#endif
}
static bool command_event_resize_windowed_scale(void)
{
unsigned idx = 0;
unsigned *window_scale = NULL;
settings_t *settings = config_get_ptr();
if (runloop_ctl(RUNLOOP_CTL_GET_WINDOWED_SCALE, &window_scale))
{
if (!window_scale || *window_scale == 0)
return false;
2017-04-28 12:57:55 +00:00
configuration_set_float(settings, settings->floats.video_scale, *window_scale);
}
2017-04-27 22:53:06 +00:00
if (!settings->bools.video_fullscreen)
command_event(CMD_EVENT_REINIT, NULL);
runloop_ctl(RUNLOOP_CTL_SET_WINDOWED_SCALE, &idx);
return true;
}
2016-05-09 18:30:47 +00:00
/**
* command_event:
* @cmd : Event command index.
*
* Performs program event command with index @cmd.
*
* Returns: true (1) on success, otherwise false (0).
**/
bool command_event(enum event_command cmd, void *data)
{
bool boolean = false;
switch (cmd)
{
2016-05-09 18:51:53 +00:00
case CMD_EVENT_MENU_REFRESH:
2016-05-09 18:30:47 +00:00
#ifdef HAVE_MENU
menu_driver_ctl(RARCH_MENU_CTL_REFRESH, NULL);
#endif
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_SET_PER_GAME_RESOLUTION:
2016-05-09 18:30:47 +00:00
#if defined(GEKKO)
{
unsigned width = 0, height = 0;
2016-05-09 18:51:53 +00:00
command_event(CMD_EVENT_VIDEO_SET_ASPECT_RATIO, NULL);
2016-05-09 18:30:47 +00:00
if (video_driver_get_video_output_size(&width, &height))
{
char msg[128] = {0};
video_driver_set_video_mode(width, height, true);
if (width == 0 || height == 0)
2016-10-28 14:09:52 +00:00
snprintf(msg, sizeof(msg), "%s: DEFAULT",
2016-10-20 16:23:34 +00:00
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCREEN_RESOLUTION));
2016-05-09 18:30:47 +00:00
else
2016-10-20 16:23:34 +00:00
snprintf(msg, sizeof(msg),"%s: %dx%d",
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCREEN_RESOLUTION),
width, height);
runloop_msg_queue_push(msg, 1, 100, true);
2016-05-09 18:30:47 +00:00
}
}
#endif
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_LOAD_CORE_PERSIST:
2016-05-09 18:30:47 +00:00
{
#ifdef HAVE_MENU
bool *ptr = NULL;
struct retro_system_info *system = NULL;
2016-09-06 03:05:50 +00:00
menu_driver_ctl(RARCH_MENU_CTL_SYSTEM_INFO_DEINIT, NULL);
2016-05-09 18:30:47 +00:00
menu_driver_ctl(RARCH_MENU_CTL_SYSTEM_INFO_GET, &system);
if (menu_driver_ctl(RARCH_MENU_CTL_LOAD_NO_CONTENT_GET, &ptr))
{
core_info_ctx_find_t info_find;
#if defined(HAVE_DYNAMIC)
2016-09-29 06:23:41 +00:00
if (string_is_empty(path_get(RARCH_PATH_CORE)))
2016-05-09 18:30:47 +00:00
return false;
2016-09-12 16:16:42 +00:00
#endif
2016-05-09 18:30:47 +00:00
libretro_get_system_info(
2016-09-29 06:23:41 +00:00
path_get(RARCH_PATH_CORE),
2016-05-09 18:30:47 +00:00
system,
ptr);
2016-09-29 06:23:41 +00:00
info_find.path = path_get(RARCH_PATH_CORE);
2016-05-09 18:30:47 +00:00
if (!core_info_load(&info_find))
2016-09-11 19:03:31 +00:00
{
#ifdef HAVE_DYNAMIC
2016-05-09 18:30:47 +00:00
return false;
2016-09-11 19:03:31 +00:00
#endif
}
2016-05-09 18:30:47 +00:00
}
#endif
}
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_LOAD_CORE:
command_event(CMD_EVENT_LOAD_CORE_PERSIST, NULL);
2016-05-09 18:30:47 +00:00
#ifndef HAVE_DYNAMIC
2016-05-09 18:51:53 +00:00
command_event(CMD_EVENT_QUIT, NULL);
2016-05-09 18:30:47 +00:00
#endif
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_LOAD_STATE:
{
#ifdef HAVE_CHEEVOS
settings_t *settings = config_get_ptr();
#endif
/* Immutable - disallow savestate load when
* we absolutely cannot change game state. */
if (bsv_movie_ctl(BSV_MOVIE_CTL_IS_INITED, NULL))
return false;
2016-05-09 18:30:47 +00:00
#ifdef HAVE_CHEEVOS
2017-04-28 11:43:47 +00:00
if (settings->bools.cheevos_hardcore_mode_enable)
return false;
2016-05-09 18:30:47 +00:00
#endif
2017-02-26 08:35:35 +00:00
return command_event_main_state(cmd);
}
break;
case CMD_EVENT_UNDO_LOAD_STATE:
2017-02-26 08:35:35 +00:00
return command_event_main_state(cmd);
2016-06-04 19:34:06 +00:00
case CMD_EVENT_UNDO_SAVE_STATE:
2017-02-26 08:35:35 +00:00
return command_event_main_state(cmd);
2016-05-09 18:51:53 +00:00
case CMD_EVENT_RESIZE_WINDOWED_SCALE:
return command_event_resize_windowed_scale();
2016-05-09 18:51:53 +00:00
case CMD_EVENT_MENU_TOGGLE:
2016-05-09 18:30:47 +00:00
#ifdef HAVE_MENU
2017-01-22 23:37:39 +00:00
if (menu_driver_is_alive())
2016-05-09 18:30:47 +00:00
rarch_ctl(RARCH_CTL_MENU_RUNNING_FINISHED, NULL);
else
rarch_ctl(RARCH_CTL_MENU_RUNNING, NULL);
#endif
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_CONTROLLERS_INIT:
2016-05-09 18:41:59 +00:00
command_event_init_controllers();
2016-05-09 18:30:47 +00:00
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_RESET:
2016-05-09 18:30:47 +00:00
RARCH_LOG("%s.\n", msg_hash_to_str(MSG_RESET));
runloop_msg_queue_push(msg_hash_to_str(MSG_RESET), 1, 120, true);
2016-05-09 18:30:47 +00:00
#ifdef HAVE_CHEEVOS
cheevos_set_cheats();
#endif
core_reset();
2017-01-23 13:50:00 +00:00
#ifdef HAVE_CHEEVOS
cheevos_reset_game();
#endif
#if HAVE_NETWORKING
netplay_driver_ctl(RARCH_NETPLAY_CTL_RESET, NULL);
2017-01-23 13:50:00 +00:00
#endif
2016-05-09 18:30:47 +00:00
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_SAVE_STATE:
{
settings_t *settings = config_get_ptr();
2016-05-09 18:30:47 +00:00
#ifdef HAVE_CHEEVOS
2017-04-28 11:43:47 +00:00
if (settings->bools.cheevos_hardcore_mode_enable)
return false;
2016-05-09 18:30:47 +00:00
#endif
2017-04-28 11:43:47 +00:00
if (settings->bools.savestate_auto_index)
2017-04-23 15:36:25 +00:00
{
2017-04-28 17:12:48 +00:00
int new_state_slot = settings->ints.state_slot + 1;
configuration_set_int(settings, settings->ints.state_slot, new_state_slot);
2017-04-23 15:36:25 +00:00
}
}
2017-02-26 08:35:35 +00:00
return command_event_main_state(cmd);
2016-05-09 18:51:53 +00:00
case CMD_EVENT_SAVE_STATE_DECREMENT:
{
settings_t *settings = config_get_ptr();
/* Slot -1 is (auto) slot. */
2017-04-28 17:12:48 +00:00
if (settings->ints.state_slot >= 0)
2017-04-23 15:36:25 +00:00
{
2017-04-28 17:12:48 +00:00
int new_state_slot = settings->ints.state_slot - 1;
configuration_set_int(settings, settings->ints.state_slot, new_state_slot);
2017-04-23 15:36:25 +00:00
}
}
2016-05-09 18:30:47 +00:00
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_SAVE_STATE_INCREMENT:
{
settings_t *settings = config_get_ptr();
2017-04-28 17:12:48 +00:00
int new_state_slot = settings->ints.state_slot + 1;
configuration_set_int(settings, settings->ints.state_slot, new_state_slot);
}
2016-05-09 18:30:47 +00:00
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_TAKE_SCREENSHOT:
2016-12-06 05:52:57 +00:00
if (!take_screenshot(path_get(RARCH_PATH_BASENAME), false))
2016-05-09 18:30:47 +00:00
return false;
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_UNLOAD_CORE:
2016-12-25 00:24:17 +00:00
{
bool contentless = false;
bool is_inited = false;
2016-12-25 00:24:17 +00:00
content_ctx_info_t content_info = {0};
content_get_status(&contentless, &is_inited);
2016-12-25 00:24:17 +00:00
command_event(CMD_EVENT_AUTOSAVE_STATE, NULL);
command_event(CMD_EVENT_DISABLE_OVERRIDES, NULL);
command_event(CMD_EVENT_RESTORE_DEFAULT_SHADER_PRESET, NULL);
if (is_inited)
2017-02-21 15:50:39 +00:00
if (!task_push_start_dummy_core(&content_info))
2016-12-25 00:24:17 +00:00
return false;
#ifdef HAVE_DYNAMIC
2016-09-06 03:05:50 +00:00
#ifdef HAVE_MENU
2016-12-25 00:24:17 +00:00
menu_driver_ctl(RARCH_MENU_CTL_SYSTEM_INFO_DEINIT, NULL);
2016-09-06 03:05:50 +00:00
#endif
2016-12-25 00:24:17 +00:00
path_clear(RARCH_PATH_CORE);
#else
2016-12-25 00:24:17 +00:00
core_unload_game();
core_unload();
#endif
2016-12-25 00:24:17 +00:00
}
2016-09-05 16:46:28 +00:00
break;
case CMD_EVENT_QUIT:
handle_quit_event();
2016-05-09 18:30:47 +00:00
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_CHEEVOS_HARDCORE_MODE_TOGGLE:
2016-05-09 18:30:47 +00:00
#ifdef HAVE_CHEEVOS
cheevos_toggle_hardcore_mode();
#endif
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_REINIT:
2016-11-06 13:18:29 +00:00
video_driver_reinit();
/* Poll input to avoid possibly stale data to corrupt things. */
input_driver_poll();
2017-01-02 01:16:29 +00:00
command_event(CMD_EVENT_GAME_FOCUS_TOGGLE, (void*)(intptr_t)-1);
2016-05-09 18:30:47 +00:00
#ifdef HAVE_MENU
2016-11-06 13:18:29 +00:00
menu_display_set_framebuffer_dirty_flag();
2017-01-22 23:37:39 +00:00
if (menu_driver_is_alive())
2016-11-06 13:18:29 +00:00
command_event(CMD_EVENT_VIDEO_SET_BLOCKING_STATE, NULL);
2016-05-09 18:30:47 +00:00
#endif
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_CHEATS_DEINIT:
2016-05-09 18:30:47 +00:00
cheat_manager_state_free();
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_CHEATS_INIT:
command_event(CMD_EVENT_CHEATS_DEINIT, NULL);
command_event_init_cheats();
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_CHEATS_APPLY:
2016-05-09 18:30:47 +00:00
cheat_manager_apply_cheats();
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_REWIND_DEINIT:
{
#ifdef HAVE_CHEEVOS
settings_t *settings = config_get_ptr();
2017-04-28 11:43:47 +00:00
if (settings->bools.cheevos_hardcore_mode_enable)
return false;
2016-05-09 18:30:47 +00:00
#endif
state_manager_event_deinit();
}
2016-05-09 18:30:47 +00:00
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_REWIND_INIT:
{
settings_t *settings = config_get_ptr();
2017-01-09 01:49:39 +00:00
#ifdef HAVE_CHEEVOS
2017-04-28 11:43:47 +00:00
if (settings->bools.cheevos_hardcore_mode_enable)
return false;
2016-05-09 18:30:47 +00:00
#endif
2017-01-09 01:49:39 +00:00
2017-04-28 11:43:47 +00:00
if (settings->bools.rewind_enable)
state_manager_event_init((unsigned)settings->rewind_buffer_size);
}
2016-05-09 18:30:47 +00:00
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_REWIND_TOGGLE:
{
settings_t *settings = config_get_ptr();
2017-04-28 11:43:47 +00:00
if (settings->bools.rewind_enable)
command_event(CMD_EVENT_REWIND_INIT, NULL);
else
command_event(CMD_EVENT_REWIND_DEINIT, NULL);
}
2016-05-09 18:30:47 +00:00
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_AUTOSAVE_DEINIT:
2016-05-09 18:30:47 +00:00
#ifdef HAVE_THREADS
if (!rarch_ctl(RARCH_CTL_IS_SRAM_USED, NULL))
return false;
autosave_deinit();
2016-05-09 18:30:47 +00:00
#endif
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_AUTOSAVE_INIT:
command_event(CMD_EVENT_AUTOSAVE_DEINIT, NULL);
2016-05-09 18:30:47 +00:00
#ifdef HAVE_THREADS
if (autosave_init())
runloop_set(RUNLOOP_ACTION_AUTOSAVE);
else
runloop_unset(RUNLOOP_ACTION_AUTOSAVE);
2017-05-07 15:52:48 +00:00
#else
2016-05-09 18:30:47 +00:00
break;
2017-05-07 15:52:48 +00:00
#endif
2016-05-09 18:51:53 +00:00
case CMD_EVENT_AUTOSAVE_STATE:
2016-05-09 19:36:17 +00:00
command_event_save_auto_state();
2016-05-09 18:30:47 +00:00
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_AUDIO_STOP:
return audio_driver_stop();
2016-05-09 18:51:53 +00:00
case CMD_EVENT_AUDIO_START:
return audio_driver_start(runloop_ctl(RUNLOOP_CTL_IS_SHUTDOWN, NULL));
2016-05-09 18:51:53 +00:00
case CMD_EVENT_AUDIO_MUTE_TOGGLE:
2016-05-09 18:30:47 +00:00
{
settings_t *settings = config_get_ptr();
2017-04-28 10:23:59 +00:00
const char *msg = !settings->bools.audio_mute_enable ?
2016-05-09 18:30:47 +00:00
msg_hash_to_str(MSG_AUDIO_MUTED):
msg_hash_to_str(MSG_AUDIO_UNMUTED);
if (!audio_driver_toggle_mute())
{
RARCH_ERR("%s.\n",
msg_hash_to_str(MSG_FAILED_TO_UNMUTE_AUDIO));
return false;
}
runloop_msg_queue_push(msg, 1, 180, true);
2016-05-09 18:30:47 +00:00
RARCH_LOG("%s\n", msg);
}
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_OVERLAY_DEINIT:
2016-05-09 18:30:47 +00:00
#ifdef HAVE_OVERLAY
2016-11-27 14:21:53 +00:00
input_overlay_free(overlay_ptr);
overlay_ptr = NULL;
2016-05-09 18:30:47 +00:00
#endif
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_OVERLAY_INIT:
{
settings_t *settings = config_get_ptr();
command_event(CMD_EVENT_OVERLAY_DEINIT, NULL);
2016-05-09 18:30:47 +00:00
#ifdef HAVE_OVERLAY
2017-04-28 11:43:47 +00:00
if (settings->bools.input_overlay_enable)
task_push_overlay_load_default(input_overlay_loaded, NULL);
2016-05-09 18:30:47 +00:00
#endif
}
2016-05-09 18:30:47 +00:00
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_OVERLAY_NEXT:
{
settings_t *settings = config_get_ptr();
2016-05-09 18:30:47 +00:00
#ifdef HAVE_OVERLAY
2017-04-28 12:57:55 +00:00
input_overlay_next(overlay_ptr, settings->floats.input_overlay_opacity);
2016-05-09 18:30:47 +00:00
#endif
}
2016-05-09 18:30:47 +00:00
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_DSP_FILTER_DEINIT:
2016-05-09 18:30:47 +00:00
audio_driver_dsp_filter_free();
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_DSP_FILTER_INIT:
{
settings_t *settings = config_get_ptr();
command_event(CMD_EVENT_DSP_FILTER_DEINIT, NULL);
2017-04-28 22:39:29 +00:00
if (string_is_empty(settings->paths.path_audio_dsp_plugin))
break;
2017-04-28 22:39:29 +00:00
audio_driver_dsp_filter_init(settings->paths.path_audio_dsp_plugin);
}
2016-05-09 18:30:47 +00:00
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_GPU_RECORD_DEINIT:
2016-05-09 18:30:47 +00:00
video_driver_gpu_record_deinit();
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_RECORD_DEINIT:
2016-05-09 18:30:47 +00:00
if (!recording_deinit())
return false;
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_RECORD_INIT:
command_event(CMD_EVENT_HISTORY_DEINIT, NULL);
2016-05-09 18:30:47 +00:00
if (!recording_init())
return false;
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_HISTORY_DEINIT:
if (g_defaults.content_history)
2016-05-09 18:30:47 +00:00
{
playlist_write_file(g_defaults.content_history);
playlist_free(g_defaults.content_history);
2016-05-09 18:30:47 +00:00
}
g_defaults.content_history = NULL;
#ifdef HAVE_FFMPEG
if (g_defaults.video_history)
{
playlist_write_file(g_defaults.video_history);
playlist_free(g_defaults.video_history);
}
g_defaults.video_history = NULL;
if (g_defaults.music_history)
{
playlist_write_file(g_defaults.music_history);
playlist_free(g_defaults.music_history);
}
g_defaults.music_history = NULL;
#endif
#ifdef HAVE_IMAGEVIEWER
if (g_defaults.image_history)
{
playlist_write_file(g_defaults.image_history);
playlist_free(g_defaults.image_history);
}
g_defaults.image_history = NULL;
#endif
2016-05-09 18:30:47 +00:00
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_HISTORY_INIT:
{
2017-04-28 19:03:04 +00:00
settings_t *settings = config_get_ptr();
unsigned content_history_size = settings->uints.content_history_size;
command_event(CMD_EVENT_HISTORY_DEINIT, NULL);
2017-04-28 19:03:04 +00:00
2017-04-28 11:43:47 +00:00
if (!settings->bools.history_list_enable)
return false;
RARCH_LOG("%s: [%s].\n",
msg_hash_to_str(MSG_LOADING_HISTORY_FILE),
2017-04-28 22:39:29 +00:00
settings->paths.path_content_history);
g_defaults.content_history = playlist_init(
2017-04-28 22:39:29 +00:00
settings->paths.path_content_history,
2017-04-28 19:03:04 +00:00
content_history_size);
#ifdef HAVE_FFMPEG
RARCH_LOG("%s: [%s].\n",
msg_hash_to_str(MSG_LOADING_HISTORY_FILE),
2017-04-28 22:39:29 +00:00
settings->paths.path_content_music_history);
g_defaults.music_history = playlist_init(
2017-04-28 22:39:29 +00:00
settings->paths.path_content_music_history,
2017-04-28 19:03:04 +00:00
content_history_size);
RARCH_LOG("%s: [%s].\n",
msg_hash_to_str(MSG_LOADING_HISTORY_FILE),
2017-04-28 22:39:29 +00:00
settings->paths.path_content_video_history);
g_defaults.video_history = playlist_init(
2017-04-28 22:39:29 +00:00
settings->paths.path_content_video_history,
2017-04-28 19:03:04 +00:00
content_history_size);
#endif
#ifdef HAVE_IMAGEVIEWER
RARCH_LOG("%s: [%s].\n",
msg_hash_to_str(MSG_LOADING_HISTORY_FILE),
2017-04-28 22:39:29 +00:00
settings->paths.path_content_image_history);
g_defaults.image_history = playlist_init(
2017-04-28 22:39:29 +00:00
settings->paths.path_content_image_history,
2017-04-28 19:03:04 +00:00
content_history_size);
#endif
}
2016-05-09 18:30:47 +00:00
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_CORE_INFO_DEINIT:
2016-05-09 18:30:47 +00:00
core_info_deinit_list();
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_CORE_INFO_INIT:
{
settings_t *settings = config_get_ptr();
command_event(CMD_EVENT_CORE_INFO_DEINIT, NULL);
2016-05-09 18:30:47 +00:00
2017-04-28 22:39:29 +00:00
if (!string_is_empty(settings->paths.directory_libretro))
core_info_init_list();
}
2016-05-09 18:30:47 +00:00
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_CORE_DEINIT:
2016-05-09 18:30:47 +00:00
{
2016-06-23 05:40:51 +00:00
struct retro_hw_render_callback *hwr = NULL;
content_reset_savestate_backups();
2016-06-23 05:40:51 +00:00
hwr = video_driver_get_hw_context();
2016-05-09 18:41:59 +00:00
command_event_deinit_core(true);
2016-05-09 18:30:47 +00:00
if (hwr)
memset(hwr, 0, sizeof(*hwr));
break;
}
2016-05-09 18:51:53 +00:00
case CMD_EVENT_CORE_INIT:
content_reset_savestate_backups();
2016-05-09 19:36:17 +00:00
if (!command_event_init_core((enum rarch_core_type*)data))
2016-05-09 18:30:47 +00:00
return false;
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_VIDEO_APPLY_STATE_CHANGES:
2016-05-09 18:30:47 +00:00
video_driver_apply_state_changes();
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_VIDEO_SET_NONBLOCKING_STATE:
2016-05-09 18:30:47 +00:00
boolean = true; /* fall-through */
2016-05-09 18:51:53 +00:00
case CMD_EVENT_VIDEO_SET_BLOCKING_STATE:
2016-05-09 18:30:47 +00:00
video_driver_set_nonblock_state(boolean);
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_VIDEO_SET_ASPECT_RATIO:
2016-05-09 18:30:47 +00:00
video_driver_set_aspect_ratio();
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_AUDIO_SET_NONBLOCKING_STATE:
2016-05-09 18:30:47 +00:00
boolean = true; /* fall-through */
2016-05-09 18:51:53 +00:00
case CMD_EVENT_AUDIO_SET_BLOCKING_STATE:
2016-05-09 18:30:47 +00:00
audio_driver_set_nonblocking_state(boolean);
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_OVERLAY_SET_SCALE_FACTOR:
{
2016-05-09 18:30:47 +00:00
#ifdef HAVE_OVERLAY
settings_t *settings = config_get_ptr();
2017-04-28 12:57:55 +00:00
input_overlay_set_scale_factor(overlay_ptr, settings->floats.input_overlay_scale);
2016-05-09 18:30:47 +00:00
#endif
}
2016-05-09 18:30:47 +00:00
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_OVERLAY_SET_ALPHA_MOD:
{
2016-05-09 18:30:47 +00:00
#ifdef HAVE_OVERLAY
settings_t *settings = config_get_ptr();
2017-04-28 12:57:55 +00:00
input_overlay_set_alpha_mod(overlay_ptr, settings->floats.input_overlay_opacity);
2016-05-09 18:30:47 +00:00
#endif
}
2016-05-09 18:30:47 +00:00
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_AUDIO_REINIT:
2016-05-09 18:30:47 +00:00
{
2016-12-05 00:47:56 +00:00
int flags = DRIVER_AUDIO_MASK;
2016-05-09 18:30:47 +00:00
driver_ctl(RARCH_DRIVER_CTL_UNINIT, &flags);
2017-01-16 21:04:57 +00:00
drivers_init(flags);
2016-05-09 18:30:47 +00:00
}
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_RESET_CONTEXT:
2016-05-09 18:30:47 +00:00
{
/* RARCH_DRIVER_CTL_UNINIT clears the callback struct so we
* need to make sure to keep a copy */
struct retro_hw_render_callback hwr_copy;
2016-12-22 20:56:54 +00:00
int flags = DRIVERS_CMD_ALL;
struct retro_hw_render_callback *hwr = video_driver_get_hw_context();
const struct retro_hw_render_context_negotiation_interface *iface =
video_driver_get_context_negotiation_interface();
2016-05-09 18:30:47 +00:00
memcpy(&hwr_copy, hwr, sizeof(hwr_copy));
driver_ctl(RARCH_DRIVER_CTL_UNINIT, &flags);
memcpy(hwr, &hwr_copy, sizeof(*hwr));
video_driver_set_context_negotiation_interface(iface);
2016-05-09 18:30:47 +00:00
2017-01-16 21:04:57 +00:00
drivers_init(flags);
2016-05-09 18:30:47 +00:00
}
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_SHUTDOWN:
2016-05-09 18:30:47 +00:00
#if defined(__linux__) && !defined(ANDROID)
runloop_msg_queue_push(msg_hash_to_str(MSG_VALUE_SHUTTING_DOWN), 1, 180, true);
2016-12-22 20:56:54 +00:00
command_event(CMD_EVENT_MENU_SAVE_CURRENT_CONFIG, NULL);
2016-05-11 18:53:28 +00:00
command_event(CMD_EVENT_QUIT, NULL);
2016-05-09 18:30:47 +00:00
system("shutdown -P now");
#endif
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_REBOOT:
2016-05-09 18:30:47 +00:00
#if defined(__linux__) && !defined(ANDROID)
runloop_msg_queue_push(msg_hash_to_str(MSG_VALUE_REBOOTING), 1, 180, true);
2016-12-22 20:56:54 +00:00
command_event(CMD_EVENT_MENU_SAVE_CURRENT_CONFIG, NULL);
2016-05-11 18:53:28 +00:00
command_event(CMD_EVENT_QUIT, NULL);
2016-05-09 18:30:47 +00:00
system("shutdown -r now");
#endif
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_RESUME:
2016-05-09 18:30:47 +00:00
rarch_ctl(RARCH_CTL_MENU_RUNNING_FINISHED, NULL);
if (ui_companion_is_on_foreground())
ui_companion_driver_toggle();
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_RESTART_RETROARCH:
2016-05-09 18:30:47 +00:00
if (!frontend_driver_set_fork(FRONTEND_FORK_RESTART))
return false;
#ifndef HAVE_DYNAMIC
command_event(CMD_EVENT_QUIT, NULL);
#endif
2016-05-09 18:30:47 +00:00
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_MENU_SAVE_CURRENT_CONFIG:
2016-08-26 05:44:05 +00:00
command_event_save_current_config(OVERRIDE_NONE);
2016-08-25 05:54:39 +00:00
break;
2016-08-26 14:43:29 +00:00
case CMD_EVENT_MENU_SAVE_CURRENT_CONFIG_OVERRIDE_CORE:
2016-08-26 05:44:05 +00:00
command_event_save_current_config(OVERRIDE_CORE);
2016-05-09 18:30:47 +00:00
break;
2016-08-26 14:43:29 +00:00
case CMD_EVENT_MENU_SAVE_CURRENT_CONFIG_OVERRIDE_GAME:
command_event_save_current_config(OVERRIDE_GAME);
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_MENU_SAVE_CONFIG:
2016-05-09 18:41:59 +00:00
if (!command_event_save_core_config())
2016-05-09 18:30:47 +00:00
return false;
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_SHADERS_APPLY_CHANGES:
2016-05-09 18:30:47 +00:00
#ifdef HAVE_MENU
menu_shader_manager_apply_changes();
#endif
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_PAUSE_CHECKS:
2016-05-09 18:30:47 +00:00
{
2017-01-23 14:19:46 +00:00
bool is_paused = false;
bool is_idle = false;
bool is_slowmotion = false;
2017-01-25 15:57:22 +00:00
bool is_perfcnt_enable = false;
2017-01-23 14:19:46 +00:00
2017-01-25 15:57:22 +00:00
runloop_get_status(&is_paused, &is_idle, &is_slowmotion,
&is_perfcnt_enable);
2017-01-23 14:19:46 +00:00
if (is_paused)
{
RARCH_LOG("%s\n", msg_hash_to_str(MSG_PAUSED));
command_event(CMD_EVENT_AUDIO_STOP, NULL);
2016-05-09 18:30:47 +00:00
2017-01-23 14:19:46 +00:00
runloop_msg_queue_push(msg_hash_to_str(MSG_PAUSED), 1,
2017-01-25 16:52:38 +00:00
1, true);
2016-10-28 14:09:52 +00:00
2017-01-25 16:52:58 +00:00
if (!is_idle)
2017-01-25 16:52:38 +00:00
video_driver_cached_frame();
2017-01-23 14:19:46 +00:00
}
else
{
2017-01-23 14:19:46 +00:00
RARCH_LOG("%s\n", msg_hash_to_str(MSG_UNPAUSED));
command_event(CMD_EVENT_AUDIO_START, NULL);
}
2016-05-09 18:30:47 +00:00
}
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_PAUSE_TOGGLE:
2016-05-09 18:30:47 +00:00
boolean = runloop_ctl(RUNLOOP_CTL_IS_PAUSED, NULL);
boolean = !boolean;
runloop_ctl(RUNLOOP_CTL_SET_PAUSED, &boolean);
2016-05-09 18:51:53 +00:00
command_event(CMD_EVENT_PAUSE_CHECKS, NULL);
2016-05-09 18:30:47 +00:00
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_UNPAUSE:
2016-05-09 18:30:47 +00:00
boolean = false;
runloop_ctl(RUNLOOP_CTL_SET_PAUSED, &boolean);
2016-05-09 18:51:53 +00:00
command_event(CMD_EVENT_PAUSE_CHECKS, NULL);
2016-05-09 18:30:47 +00:00
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_PAUSE:
2016-05-09 18:30:47 +00:00
boolean = true;
runloop_ctl(RUNLOOP_CTL_SET_PAUSED, &boolean);
2016-05-09 18:51:53 +00:00
command_event(CMD_EVENT_PAUSE_CHECKS, NULL);
2016-05-09 18:30:47 +00:00
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_MENU_PAUSE_LIBRETRO:
#ifdef HAVE_MENU
2017-01-23 14:19:46 +00:00
if (menu_driver_is_alive())
{
settings_t *settings = config_get_ptr();
2017-04-28 11:43:47 +00:00
if (settings->bools.menu_pause_libretro)
2017-01-23 14:19:46 +00:00
command_event(CMD_EVENT_AUDIO_STOP, NULL);
2016-05-09 18:30:47 +00:00
else
2017-01-23 14:19:46 +00:00
command_event(CMD_EVENT_AUDIO_START, NULL);
}
else
{
settings_t *settings = config_get_ptr();
2017-04-28 11:43:47 +00:00
if (settings->bools.menu_pause_libretro)
2017-01-23 14:19:46 +00:00
command_event(CMD_EVENT_AUDIO_START, NULL);
}
2017-01-23 14:19:46 +00:00
#endif
2016-05-09 18:30:47 +00:00
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_SHADER_DIR_DEINIT:
2016-09-23 01:19:33 +00:00
dir_free_shader();
2016-05-09 18:30:47 +00:00
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_SHADER_DIR_INIT:
command_event(CMD_EVENT_SHADER_DIR_DEINIT, NULL);
2016-05-09 18:30:47 +00:00
2016-09-23 01:19:33 +00:00
if (!dir_init_shader())
2016-05-09 18:30:47 +00:00
return false;
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_BSV_MOVIE_DEINIT:
2017-05-07 16:15:30 +00:00
bsv_movie_deinit();
2016-05-09 18:30:47 +00:00
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_BSV_MOVIE_INIT:
command_event(CMD_EVENT_BSV_MOVIE_DEINIT, NULL);
bsv_movie_init();
2016-05-09 18:30:47 +00:00
break;
2016-09-29 19:07:10 +00:00
#ifdef HAVE_NETWORKING
case CMD_EVENT_NETPLAY_DEINIT:
2016-05-09 18:30:47 +00:00
deinit_netplay();
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_NETWORK_DEINIT:
2016-05-09 18:30:47 +00:00
network_deinit();
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_NETWORK_INIT:
2016-05-09 18:30:47 +00:00
network_init();
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_NETPLAY_INIT:
{
2017-01-22 20:25:35 +00:00
char *hostname = (char *) data;
settings_t *settings = config_get_ptr();
2017-01-22 20:25:35 +00:00
command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
2017-01-22 20:25:35 +00:00
if (!init_netplay(
2017-04-28 22:39:29 +00:00
NULL, hostname ? hostname : settings->paths.netplay_server,
2017-04-28 19:03:04 +00:00
settings->uints.netplay_port))
{
command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
return false;
}
}
break;
case CMD_EVENT_NETPLAY_INIT_DIRECT:
{
settings_t *settings = config_get_ptr();
2017-01-22 20:25:35 +00:00
command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
2017-01-22 20:25:35 +00:00
if (!init_netplay(
2017-04-28 19:03:04 +00:00
data, NULL, settings->uints.netplay_port))
{
command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
return false;
}
}
2016-05-09 18:30:47 +00:00
break;
case CMD_EVENT_NETPLAY_INIT_DIRECT_DEFERRED:
{
/* buf is expected to be address:port, there must be a better way
to do this but for now I'll just use a string list */
2017-01-22 20:24:57 +00:00
char *buf = (char *)data;
static struct string_list *hostname = NULL;
2017-01-22 20:24:57 +00:00
hostname = string_split(buf, ":");
command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
2017-01-22 20:24:57 +00:00
if (!init_netplay_deferred(
hostname->elems[0].data, atoi(hostname->elems[1].data)))
{
string_list_free(hostname);
command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
return false;
}
string_list_free(hostname);
}
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_NETPLAY_FLIP_PLAYERS:
2016-05-09 18:30:47 +00:00
netplay_driver_ctl(RARCH_NETPLAY_CTL_FLIP_PLAYERS, NULL);
break;
case CMD_EVENT_NETPLAY_GAME_WATCH:
netplay_driver_ctl(RARCH_NETPLAY_CTL_GAME_WATCH, NULL);
2016-05-09 18:30:47 +00:00
break;
#else
case CMD_EVENT_NETPLAY_DEINIT:
case CMD_EVENT_NETWORK_DEINIT:
case CMD_EVENT_NETWORK_INIT:
case CMD_EVENT_NETPLAY_INIT:
case CMD_EVENT_NETPLAY_INIT_DIRECT:
case CMD_EVENT_NETPLAY_INIT_DIRECT_DEFERRED:
case CMD_EVENT_NETPLAY_FLIP_PLAYERS:
case CMD_EVENT_NETPLAY_GAME_WATCH:
return false;
#endif
2016-05-09 18:51:53 +00:00
case CMD_EVENT_FULLSCREEN_TOGGLE:
{
settings_t *settings = config_get_ptr();
2017-04-27 22:53:06 +00:00
bool new_fullscreen_state = !settings->bools.video_fullscreen;
if (!video_driver_has_windowed())
return false;
2016-05-09 18:30:47 +00:00
/* If we go fullscreen we drop all drivers and
* reinitialize to be safe. */
2017-04-27 22:53:06 +00:00
configuration_set_bool(settings, settings->bools.video_fullscreen,
2017-04-23 15:36:25 +00:00
new_fullscreen_state);
command_event(CMD_EVENT_REINIT, NULL);
2017-04-27 22:53:06 +00:00
if (settings->bools.video_fullscreen)
video_driver_hide_mouse();
else
video_driver_show_mouse();
}
2016-05-09 18:30:47 +00:00
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_COMMAND_DEINIT:
2016-05-09 18:30:47 +00:00
input_driver_deinit_command();
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_COMMAND_INIT:
command_event(CMD_EVENT_COMMAND_DEINIT, NULL);
2016-05-09 18:30:47 +00:00
input_driver_init_command();
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_REMOTE_DEINIT:
2016-05-09 18:30:47 +00:00
input_driver_deinit_remote();
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_REMOTE_INIT:
command_event(CMD_EVENT_REMOTE_DEINIT, NULL);
2016-05-09 18:30:47 +00:00
input_driver_init_remote();
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_TEMPORARY_CONTENT_DEINIT:
2016-05-09 18:30:47 +00:00
content_deinit();
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_LOG_FILE_DEINIT:
2016-05-09 18:30:47 +00:00
retro_main_log_file_deinit();
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_DISK_APPEND_IMAGE:
2016-05-09 18:30:47 +00:00
{
const char *path = (const char*)data;
if (string_is_empty(path))
return false;
2016-05-09 18:41:59 +00:00
return command_event_disk_control_append_image(path);
2016-05-09 18:30:47 +00:00
}
2016-05-09 18:51:53 +00:00
case CMD_EVENT_DISK_EJECT_TOGGLE:
2016-05-09 18:30:47 +00:00
{
2017-04-23 14:41:26 +00:00
rarch_system_info_t *info = runloop_get_system_info();
2016-05-09 18:30:47 +00:00
if (info && info->disk_control_cb.get_num_images)
2016-05-09 18:30:47 +00:00
{
const struct retro_disk_control_callback *control =
(const struct retro_disk_control_callback*)
&info->disk_control_cb;
if (control)
{
bool new_state = !control->get_eject_state();
command_event_disk_control_set_eject(new_state, true);
}
2016-05-09 18:30:47 +00:00
}
else
runloop_msg_queue_push(
msg_hash_to_str(MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS),
1, 120, true);
2016-05-09 18:30:47 +00:00
}
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_DISK_NEXT:
2016-05-09 18:30:47 +00:00
{
2017-04-23 14:41:26 +00:00
rarch_system_info_t *info = runloop_get_system_info();
2016-05-09 18:30:47 +00:00
if (info && info->disk_control_cb.get_num_images)
{
const struct retro_disk_control_callback *control =
(const struct retro_disk_control_callback*)
&info->disk_control_cb;
2016-05-09 18:30:47 +00:00
if (!control)
return false;
if (!control->get_eject_state())
return false;
2016-05-09 18:30:47 +00:00
command_event_check_disk_next(control);
}
else
runloop_msg_queue_push(
msg_hash_to_str(MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS),
1, 120, true);
2016-05-09 18:30:47 +00:00
}
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_DISK_PREV:
2016-05-09 18:30:47 +00:00
{
2017-04-23 14:41:26 +00:00
rarch_system_info_t *info = runloop_get_system_info();
2016-05-09 18:30:47 +00:00
if (info && info->disk_control_cb.get_num_images)
{
const struct retro_disk_control_callback *control =
(const struct retro_disk_control_callback*)
&info->disk_control_cb;
2016-05-09 18:30:47 +00:00
if (!control)
return false;
if (!control->get_eject_state())
return false;
2016-05-09 18:30:47 +00:00
command_event_check_disk_prev(control);
}
else
runloop_msg_queue_push(
msg_hash_to_str(MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS),
1, 120, true);
2016-05-09 18:30:47 +00:00
}
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_RUMBLE_STOP:
2016-05-09 18:30:47 +00:00
{
2016-12-25 00:24:17 +00:00
unsigned i;
for (i = 0; i < MAX_USERS; i++)
{
input_driver_set_rumble_state(i, RETRO_RUMBLE_STRONG, 0);
input_driver_set_rumble_state(i, RETRO_RUMBLE_WEAK, 0);
}
2016-05-09 18:30:47 +00:00
}
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_GRAB_MOUSE_TOGGLE:
2016-05-09 18:30:47 +00:00
{
bool ret = false;
static bool grab_mouse_state = false;
grab_mouse_state = !grab_mouse_state;
if (grab_mouse_state)
ret = input_driver_grab_mouse();
else
ret = input_driver_ungrab_mouse();
if (!ret)
return false;
RARCH_LOG("%s: %s.\n",
msg_hash_to_str(MSG_GRAB_MOUSE_STATE),
grab_mouse_state ? "yes" : "no");
if (grab_mouse_state)
video_driver_hide_mouse();
else
video_driver_show_mouse();
}
break;
case CMD_EVENT_GAME_FOCUS_TOGGLE:
{
static bool game_focus_state = false;
2017-01-02 01:16:29 +00:00
intptr_t mode = (intptr_t)data;
/* mode = -1: restores current game focus state
* mode = 1: force set game focus, instead of toggling
* any other: toggle
*/
if (mode == 1)
game_focus_state = true;
else if (mode != -1)
game_focus_state = !game_focus_state;
RARCH_LOG("%s: %s.\n",
"Game focus is: ",
game_focus_state ? "on" : "off");
if (game_focus_state)
{
input_driver_grab_mouse();
video_driver_hide_mouse();
input_driver_set_hotkey_block();
input_driver_keyboard_mapping_set_block(1);
if (mode != -1)
runloop_msg_queue_push(msg_hash_to_str(MSG_GAME_FOCUS_ON),
1, 120, true);
}
else
{
input_driver_ungrab_mouse();
video_driver_show_mouse();
input_driver_unset_hotkey_block();
input_driver_keyboard_mapping_set_block(0);
if (mode != -1)
runloop_msg_queue_push(msg_hash_to_str(MSG_GAME_FOCUS_OFF),
1, 120, true);
}
}
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_PERFCNT_REPORT_FRONTEND_LOG:
2016-05-09 18:30:47 +00:00
rarch_perf_log();
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_VOLUME_UP:
2016-05-09 18:41:59 +00:00
command_event_set_volume(0.5f);
2016-05-09 18:30:47 +00:00
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_VOLUME_DOWN:
2016-05-09 18:41:59 +00:00
command_event_set_volume(-0.5f);
2016-05-09 18:30:47 +00:00
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_SET_FRAME_LIMIT:
2016-05-09 18:30:47 +00:00
runloop_ctl(RUNLOOP_CTL_SET_FRAME_LIMIT, NULL);
break;
2016-05-20 22:54:29 +00:00
case CMD_EVENT_DISABLE_OVERRIDES:
command_event_disable_overrides();
break;
2016-07-30 19:36:01 +00:00
case CMD_EVENT_RESTORE_DEFAULT_SHADER_PRESET:
command_event_restore_default_shader_preset();
break;
2016-05-09 18:51:53 +00:00
case CMD_EVENT_NONE:
2016-05-09 18:30:47 +00:00
return false;
}
return true;
}