Rewrite commands and add new command type (#12233)
* (OSX non-Metal build) Set disable execute page protection * Rewrite commands and add new command type This moves commands to a separate file and creates a consistent interface for them. It is now possible to use multiple command interfaces simultaneously (stdin, network and UDS). Implemented a new interface for Lakka, UDS based (so Linux only). This allow other Lakka servies to send certain commands to Retroarch in a secure and reliable way. Co-authored-by: twinaphex <libretro@gmail.com>
This commit is contained in:
parent
a989cfb987
commit
b830b33cf1
|
@ -233,6 +233,7 @@ endif
|
||||||
|
|
||||||
OBJ += frontend/frontend_driver.o \
|
OBJ += frontend/frontend_driver.o \
|
||||||
retroarch.o \
|
retroarch.o \
|
||||||
|
command.o \
|
||||||
msg_hash.o \
|
msg_hash.o \
|
||||||
intl/msg_hash_us.o \
|
intl/msg_hash_us.o \
|
||||||
$(LIBRETRO_COMM_DIR)/queues/task_queue.o \
|
$(LIBRETRO_COMM_DIR)/queues/task_queue.o \
|
||||||
|
|
|
@ -0,0 +1,514 @@
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#ifdef HAVE_NETWORKING
|
||||||
|
#include <net/net_compat.h>
|
||||||
|
#include <net/net_socket.h>
|
||||||
|
#endif
|
||||||
|
#include <streams/stdin_stream.h>
|
||||||
|
#include <string/stdstring.h>
|
||||||
|
|
||||||
|
#include "verbosity.h"
|
||||||
|
#include "command.h"
|
||||||
|
|
||||||
|
#define CMD_BUF_SIZE 4096
|
||||||
|
|
||||||
|
#if defined(HAVE_COMMAND)
|
||||||
|
|
||||||
|
/* Generic command parse utilities */
|
||||||
|
|
||||||
|
static bool command_get_arg(const char *tok,
|
||||||
|
const char **arg, unsigned *index)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(map); i++)
|
||||||
|
{
|
||||||
|
if (string_is_equal(tok, map[i].str))
|
||||||
|
{
|
||||||
|
if (arg)
|
||||||
|
*arg = NULL;
|
||||||
|
|
||||||
|
if (index)
|
||||||
|
*index = i;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 != ' ' && *argument != '\0')
|
||||||
|
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(handle, 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void command_parse_msg(
|
||||||
|
command_t *handle, char *buf)
|
||||||
|
{
|
||||||
|
char *save = NULL;
|
||||||
|
const char *tok = strtok_r(buf, "\n", &save);
|
||||||
|
|
||||||
|
while (tok)
|
||||||
|
{
|
||||||
|
command_parse_sub_msg(handle, tok);
|
||||||
|
tok = strtok_r(NULL, "\n", &save);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(HAVE_NETWORK_CMD)
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/* Network socket FD */
|
||||||
|
int net_fd;
|
||||||
|
/* Source address for the command received */
|
||||||
|
struct sockaddr_storage cmd_source;
|
||||||
|
/* Size of the previous structure in use */
|
||||||
|
socklen_t cmd_source_len;
|
||||||
|
} command_network_t;
|
||||||
|
|
||||||
|
static void network_command_reply(
|
||||||
|
command_t *cmd,
|
||||||
|
const char * data, size_t len)
|
||||||
|
{
|
||||||
|
command_network_t *netcmd = (command_network_t*)cmd->userptr;
|
||||||
|
/* Respond (fire and forget since it's UDP) */
|
||||||
|
sendto(netcmd->net_fd, data, len, 0,
|
||||||
|
(struct sockaddr*)&netcmd->cmd_source, netcmd->cmd_source_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void network_command_free(command_t *handle)
|
||||||
|
{
|
||||||
|
command_network_t *netcmd = (command_network_t*)handle->userptr;
|
||||||
|
|
||||||
|
if (netcmd->net_fd >= 0)
|
||||||
|
socket_close(netcmd->net_fd);
|
||||||
|
|
||||||
|
free(netcmd);
|
||||||
|
free(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void command_network_poll(command_t *handle)
|
||||||
|
{
|
||||||
|
fd_set fds;
|
||||||
|
struct timeval tmp_tv = {0};
|
||||||
|
command_network_t *netcmd = (command_network_t*)handle->userptr;
|
||||||
|
|
||||||
|
if (netcmd->net_fd < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(netcmd->net_fd, &fds);
|
||||||
|
|
||||||
|
if (socket_select(netcmd->net_fd + 1, &fds, NULL, NULL, &tmp_tv) <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!FD_ISSET(netcmd->net_fd, &fds))
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
ssize_t ret;
|
||||||
|
char buf[1024];
|
||||||
|
|
||||||
|
buf[0] = '\0';
|
||||||
|
ret = recvfrom(netcmd->net_fd, buf, sizeof(buf) - 1, 0,
|
||||||
|
(struct sockaddr*)&netcmd->cmd_source,
|
||||||
|
&netcmd->cmd_source_len);
|
||||||
|
|
||||||
|
if (ret <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
buf[ret] = '\0';
|
||||||
|
|
||||||
|
command_parse_msg(handle, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
command_t* command_network_new(uint16_t port)
|
||||||
|
{
|
||||||
|
struct addrinfo *res = NULL;
|
||||||
|
command_t *cmd = (command_t*)calloc(1, sizeof(command_t));
|
||||||
|
command_network_t *netcmd = (command_network_t*)calloc(
|
||||||
|
1, sizeof(command_network_t));
|
||||||
|
int fd = socket_init((void**)&res, port, NULL, SOCKET_TYPE_DATAGRAM);
|
||||||
|
|
||||||
|
RARCH_LOG("%s %hu.\n",
|
||||||
|
msg_hash_to_str(MSG_BRINGING_UP_COMMAND_INTERFACE_ON_PORT),
|
||||||
|
(unsigned short)port);
|
||||||
|
|
||||||
|
if (fd < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
netcmd->net_fd = fd;
|
||||||
|
cmd->userptr = netcmd;
|
||||||
|
cmd->poll = command_network_poll;
|
||||||
|
cmd->replier = network_command_reply;
|
||||||
|
cmd->destroy = network_command_free;
|
||||||
|
|
||||||
|
if (!socket_nonblock(netcmd->net_fd))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (!socket_bind(netcmd->net_fd, (void*)res))
|
||||||
|
{
|
||||||
|
RARCH_ERR("%s.\n",
|
||||||
|
msg_hash_to_str(MSG_FAILED_TO_BIND_SOCKET));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
freeaddrinfo_retro(res);
|
||||||
|
return cmd;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (res)
|
||||||
|
freeaddrinfo_retro(res);
|
||||||
|
free(netcmd);
|
||||||
|
free(cmd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(HAVE_STDIN_CMD)
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/* Buffer and pointer for stdin reads */
|
||||||
|
size_t stdin_buf_ptr;
|
||||||
|
char stdin_buf[CMD_BUF_SIZE];
|
||||||
|
} command_stdin_t;
|
||||||
|
|
||||||
|
static void stdin_command_reply(
|
||||||
|
command_t *cmd,
|
||||||
|
const char * data, size_t len)
|
||||||
|
{
|
||||||
|
/* Just write to stdout! */
|
||||||
|
fwrite(data, 1, len, stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stdin_command_free(command_t *handle)
|
||||||
|
{
|
||||||
|
free(handle->userptr);
|
||||||
|
free(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void command_stdin_poll(command_t *handle) {
|
||||||
|
ptrdiff_t msg_len;
|
||||||
|
char *last_newline = NULL;
|
||||||
|
command_stdin_t *stdincmd = (command_stdin_t*)handle->userptr;
|
||||||
|
ssize_t ret = read_stdin(
|
||||||
|
stdincmd->stdin_buf + stdincmd->stdin_buf_ptr,
|
||||||
|
CMD_BUF_SIZE - stdincmd->stdin_buf_ptr - 1);
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
stdincmd->stdin_buf_ptr += ret;
|
||||||
|
stdincmd->stdin_buf[stdincmd->stdin_buf_ptr] = '\0';
|
||||||
|
|
||||||
|
last_newline = strrchr(stdincmd->stdin_buf, '\n');
|
||||||
|
|
||||||
|
if (!last_newline)
|
||||||
|
{
|
||||||
|
/* We're receiving bogus data in pipe
|
||||||
|
* (no terminating newline), flush out the buffer. */
|
||||||
|
if (stdincmd->stdin_buf_ptr + 1 >= CMD_BUF_SIZE)
|
||||||
|
{
|
||||||
|
stdincmd->stdin_buf_ptr = 0;
|
||||||
|
stdincmd->stdin_buf[0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
*last_newline++ = '\0';
|
||||||
|
msg_len = last_newline - stdincmd->stdin_buf;
|
||||||
|
|
||||||
|
command_parse_msg(handle, stdincmd->stdin_buf);
|
||||||
|
|
||||||
|
memmove(stdincmd->stdin_buf, last_newline,
|
||||||
|
stdincmd->stdin_buf_ptr - msg_len);
|
||||||
|
stdincmd->stdin_buf_ptr -= msg_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
command_t* command_stdin_new(void)
|
||||||
|
{
|
||||||
|
command_t *cmd;
|
||||||
|
command_stdin_t *stdincmd;
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#ifdef HAVE_NETWORKING
|
||||||
|
if (!socket_nonblock(STDIN_FILENO))
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
cmd = (command_t*)calloc(1, sizeof(command_t));
|
||||||
|
stdincmd = (command_stdin_t*)calloc(1, sizeof(command_stdin_t));
|
||||||
|
cmd->userptr = stdincmd;
|
||||||
|
cmd->poll = command_stdin_poll;
|
||||||
|
cmd->replier = stdin_command_reply;
|
||||||
|
cmd->destroy = stdin_command_free;
|
||||||
|
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAVE_LAKKA)
|
||||||
|
#include <sys/un.h>
|
||||||
|
#define MAX_USER_CONNECTIONS 4
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/* File descriptor for the domain socket */
|
||||||
|
int sfd;
|
||||||
|
/* Client sockets */
|
||||||
|
int userfd[MAX_USER_CONNECTIONS];
|
||||||
|
/* Last received user socket */
|
||||||
|
int last_fd;
|
||||||
|
} command_uds_t;
|
||||||
|
|
||||||
|
static void uds_command_reply(
|
||||||
|
command_t *cmd,
|
||||||
|
const char * data, size_t len)
|
||||||
|
{
|
||||||
|
command_uds_t *subcmd = (command_uds_t*)cmd->userptr;
|
||||||
|
write(subcmd->last_fd, data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void uds_command_free(command_t *handle)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
command_uds_t *udscmd = (command_uds_t*)handle->userptr;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_USER_CONNECTIONS; i++)
|
||||||
|
if (udscmd->userfd[i] >= 0)
|
||||||
|
socket_close(udscmd->userfd[i]);
|
||||||
|
socket_close(udscmd->sfd);
|
||||||
|
|
||||||
|
free(handle->userptr);
|
||||||
|
free(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void command_uds_poll(command_t *handle) {
|
||||||
|
int i;
|
||||||
|
command_uds_t *udscmd = (command_uds_t*)handle->userptr;
|
||||||
|
int maxfd = udscmd->sfd;
|
||||||
|
fd_set fds;
|
||||||
|
struct timeval tmp_tv = {0};
|
||||||
|
|
||||||
|
if (udscmd->sfd < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(udscmd->sfd, &fds);
|
||||||
|
for (i = 0; i < MAX_USER_CONNECTIONS; i++)
|
||||||
|
{
|
||||||
|
if (udscmd->userfd[i] >= 0)
|
||||||
|
{
|
||||||
|
maxfd = MAX(udscmd->userfd[i], maxfd);
|
||||||
|
FD_SET(udscmd->userfd[i], &fds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (socket_select(maxfd + 1, &fds, NULL, NULL, &tmp_tv) <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Read data from clients and process commands */
|
||||||
|
for (i = 0; i < MAX_USER_CONNECTIONS; i++)
|
||||||
|
{
|
||||||
|
if (udscmd->userfd[i] >= 0 && FD_ISSET(udscmd->userfd[i], &fds))
|
||||||
|
{
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
char buf[2048];
|
||||||
|
ssize_t ret = recv(udscmd->userfd[i], buf, sizeof(buf) - 1, 0);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
break; /* no more data */
|
||||||
|
if (!ret)
|
||||||
|
{
|
||||||
|
socket_close(udscmd->userfd[i]);
|
||||||
|
udscmd->userfd[i] = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[ret] = 0;
|
||||||
|
udscmd->last_fd = udscmd->userfd[i];
|
||||||
|
command_parse_msg(handle, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FD_ISSET(udscmd->sfd, &fds))
|
||||||
|
{
|
||||||
|
/* Accepts new connections from clients */
|
||||||
|
int cfd = accept(udscmd->sfd, NULL, NULL);
|
||||||
|
if (cfd >= 0) {
|
||||||
|
if (!socket_nonblock(cfd))
|
||||||
|
socket_close(cfd);
|
||||||
|
else {
|
||||||
|
for (i = 0; i < MAX_USER_CONNECTIONS; i++)
|
||||||
|
if (udscmd->userfd[i] < 0)
|
||||||
|
{
|
||||||
|
udscmd->userfd[i] = cfd;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
command_t* command_uds_new(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
command_t *cmd;
|
||||||
|
command_uds_t *subcmd;
|
||||||
|
struct sockaddr_un addr;
|
||||||
|
const char *sp = "retroarch/cmd";
|
||||||
|
socklen_t addrsz = offsetof(struct sockaddr_un, sun_path) + strlen(sp) + 1;
|
||||||
|
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
if (fd < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* use an abstract socket for simplicity */
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
addr.sun_family = AF_UNIX;
|
||||||
|
strcpy(&addr.sun_path[1], sp);
|
||||||
|
|
||||||
|
if (bind(fd, (struct sockaddr*)&addr, addrsz) < 0 ||
|
||||||
|
listen(fd, MAX_USER_CONNECTIONS) < 0) {
|
||||||
|
socket_close(fd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!socket_nonblock(fd))
|
||||||
|
{
|
||||||
|
socket_close(fd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd = (command_t*)calloc(1, sizeof(command_t));
|
||||||
|
subcmd = (command_uds_t*)calloc(1, sizeof(command_uds_t));
|
||||||
|
subcmd->sfd = fd;
|
||||||
|
subcmd->last_fd = -1;
|
||||||
|
for (i = 0; i < MAX_USER_CONNECTIONS; i++)
|
||||||
|
subcmd->userfd[i] = -1;
|
||||||
|
|
||||||
|
cmd->userptr = subcmd;
|
||||||
|
cmd->poll = command_uds_poll;
|
||||||
|
cmd->replier = uds_command_reply;
|
||||||
|
cmd->destroy = uds_command_free;
|
||||||
|
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Routines used to invoke retroarch command ... */
|
||||||
|
|
||||||
|
#ifdef HAVE_NETWORK_CMD
|
||||||
|
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 < ARRAY_SIZE(map); i++)
|
||||||
|
RARCH_ERR("\t\t%s\n", map[i].str);
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(action_map); 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_)
|
||||||
|
{
|
||||||
|
char *command = NULL;
|
||||||
|
char *save = NULL;
|
||||||
|
const char *cmd = NULL;
|
||||||
|
|
||||||
|
if (!network_init())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!(command = strdup(cmd_)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
cmd = strtok_r(command, ";", &save);
|
||||||
|
if (cmd)
|
||||||
|
{
|
||||||
|
uint16_t port = DEFAULT_NETWORK_CMD_PORT;
|
||||||
|
const char *port_ = NULL;
|
||||||
|
const char *host = strtok_r(NULL, ";", &save);
|
||||||
|
if (host)
|
||||||
|
port_ = strtok_r(NULL, ";", &save);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
host = "127.0.0.1";
|
||||||
|
#else
|
||||||
|
host = "localhost";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (port_)
|
||||||
|
port = strtoul(port_, NULL, 0);
|
||||||
|
|
||||||
|
RARCH_LOG("%s: \"%s\" to %s:%hu\n",
|
||||||
|
msg_hash_to_str(MSG_SENDING_COMMAND),
|
||||||
|
cmd, host, (unsigned short)port);
|
||||||
|
|
||||||
|
if (command_verify(cmd) && udp_send_packet(host, port, cmd))
|
||||||
|
{
|
||||||
|
free(command);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(command);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
146
command.h
146
command.h
|
@ -23,12 +23,46 @@
|
||||||
#include <boolean.h>
|
#include <boolean.h>
|
||||||
#include <retro_common_api.h>
|
#include <retro_common_api.h>
|
||||||
|
|
||||||
|
#include "retroarch.h"
|
||||||
|
#include "input/input_defines.h"
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
RETRO_BEGIN_DECLS
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define MAX_CMD_DRIVERS 3
|
||||||
|
#define DEFAULT_NETWORK_CMD_PORT 55355
|
||||||
|
|
||||||
|
struct cmd_map
|
||||||
|
{
|
||||||
|
const char *str;
|
||||||
|
unsigned id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct command_handler;
|
||||||
|
|
||||||
|
typedef void (*command_poller_t)(struct command_handler *cmd);
|
||||||
|
typedef void (*command_replier_t)(struct command_handler *cmd, const char * data, size_t len);
|
||||||
|
typedef void (*command_destructor_t)(struct command_handler *cmd);
|
||||||
|
|
||||||
|
struct command_handler
|
||||||
|
{
|
||||||
|
/* Interface to poll the driver */
|
||||||
|
command_poller_t poll;
|
||||||
|
/* Interface to reply */
|
||||||
|
command_replier_t replier;
|
||||||
|
/* Interface to delete the underlying command */
|
||||||
|
command_destructor_t destroy;
|
||||||
|
/* Underlying command storage */
|
||||||
|
void *userptr;
|
||||||
|
/* State received */
|
||||||
|
bool state[RARCH_BIND_LIST_END];
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct command_handler command_t;
|
||||||
|
|
||||||
enum event_command
|
enum event_command
|
||||||
{
|
{
|
||||||
CMD_EVENT_NONE = 0,
|
CMD_EVENT_NONE = 0,
|
||||||
|
@ -209,14 +243,21 @@ enum event_command
|
||||||
CMD_EVENT_CONTROLLER_INIT
|
CMD_EVENT_CONTROLLER_INIT
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct command command_t;
|
|
||||||
|
|
||||||
typedef struct command_handle
|
typedef struct command_handle
|
||||||
{
|
{
|
||||||
command_t *handle;
|
command_t *handle;
|
||||||
unsigned id;
|
unsigned id;
|
||||||
} command_handle_t;
|
} command_handle_t;
|
||||||
|
|
||||||
|
enum cmd_source_t
|
||||||
|
{
|
||||||
|
CMD_NONE = 0,
|
||||||
|
CMD_STDIN,
|
||||||
|
CMD_NETWORK
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rarch_state;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* command_event:
|
* command_event:
|
||||||
* @cmd : Command index.
|
* @cmd : Command index.
|
||||||
|
@ -227,6 +268,107 @@ typedef struct command_handle
|
||||||
**/
|
**/
|
||||||
bool command_event(enum event_command action, void *data);
|
bool command_event(enum event_command action, void *data);
|
||||||
|
|
||||||
|
/* Constructors for the supported drivers */
|
||||||
|
command_t* command_network_new(uint16_t port);
|
||||||
|
command_t* command_stdin_new(void);
|
||||||
|
command_t* command_uds_new(void);
|
||||||
|
|
||||||
|
bool command_network_send(const char *cmd_);
|
||||||
|
|
||||||
|
/* These forward declarations need to be declared before
|
||||||
|
* the global state is declared */
|
||||||
|
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
|
||||||
|
bool command_set_shader(command_t *cmd, const char *arg);
|
||||||
|
#endif
|
||||||
|
#if defined(HAVE_COMMAND)
|
||||||
|
bool command_version(command_t *cmd, const char* arg);
|
||||||
|
bool command_get_status(command_t *cmd, const char* arg);
|
||||||
|
bool command_get_config_param(command_t *cmd, const char* arg);
|
||||||
|
bool command_show_osd_msg(command_t *cmd, const char* arg);
|
||||||
|
#ifdef HAVE_CHEEVOS
|
||||||
|
bool command_read_ram(command_t *cmd, const char *arg);
|
||||||
|
bool command_write_ram(command_t *cmd, const char *arg);
|
||||||
|
#endif
|
||||||
|
bool command_read_memory(command_t *cmd, const char *arg);
|
||||||
|
bool command_write_memory(command_t *cmd, const char *arg);
|
||||||
|
|
||||||
|
struct cmd_action_map
|
||||||
|
{
|
||||||
|
const char *str;
|
||||||
|
bool (*action)(command_t* cmd, const char *arg);
|
||||||
|
const char *arg_desc;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct cmd_action_map action_map[] = {
|
||||||
|
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
|
||||||
|
{ "SET_SHADER", command_set_shader, "<shader path>" },
|
||||||
|
#endif
|
||||||
|
{ "VERSION", command_version, "No argument"},
|
||||||
|
{ "GET_STATUS", command_get_status, "No argument" },
|
||||||
|
{ "GET_CONFIG_PARAM", command_get_config_param, "<param name>" },
|
||||||
|
{ "SHOW_MSG", command_show_osd_msg, "No argument" },
|
||||||
|
#if defined(HAVE_CHEEVOS)
|
||||||
|
/* These functions use achievement addresses and only work if a game with achievements is
|
||||||
|
* loaded. READ_CORE_MEMORY and WRITE_CORE_MEMORY are preferred and use system addresses. */
|
||||||
|
{ "READ_CORE_RAM", command_read_ram, "<address> <number of bytes>" },
|
||||||
|
{ "WRITE_CORE_RAM", command_write_ram, "<address> <byte1> <byte2> ..." },
|
||||||
|
#endif
|
||||||
|
{ "READ_CORE_MEMORY", command_read_memory, "<address> <number of bytes>" },
|
||||||
|
{ "WRITE_CORE_MEMORY",command_write_memory, "<address> <byte1> <byte2> ..." },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct cmd_map map[] = {
|
||||||
|
{ "FAST_FORWARD", RARCH_FAST_FORWARD_KEY },
|
||||||
|
{ "FAST_FORWARD_HOLD", RARCH_FAST_FORWARD_HOLD_KEY },
|
||||||
|
{ "SLOWMOTION", RARCH_SLOWMOTION_KEY },
|
||||||
|
{ "SLOWMOTION_HOLD", RARCH_SLOWMOTION_HOLD_KEY },
|
||||||
|
{ "LOAD_STATE", RARCH_LOAD_STATE_KEY },
|
||||||
|
{ "SAVE_STATE", RARCH_SAVE_STATE_KEY },
|
||||||
|
{ "FULLSCREEN_TOGGLE", RARCH_FULLSCREEN_TOGGLE_KEY },
|
||||||
|
{ "CLOSE_CONTENT", RARCH_CLOSE_CONTENT_KEY },
|
||||||
|
{ "QUIT", RARCH_QUIT_KEY },
|
||||||
|
{ "STATE_SLOT_PLUS", RARCH_STATE_SLOT_PLUS },
|
||||||
|
{ "STATE_SLOT_MINUS", RARCH_STATE_SLOT_MINUS },
|
||||||
|
{ "REWIND", RARCH_REWIND },
|
||||||
|
{ "BSV_RECORD_TOGGLE", RARCH_BSV_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 },
|
||||||
|
{ "FPS_TOGGLE", RARCH_FPS_TOGGLE },
|
||||||
|
{ "SEND_DEBUG_INFO", RARCH_SEND_DEBUG_INFO },
|
||||||
|
{ "NETPLAY_HOST_TOGGLE", RARCH_NETPLAY_HOST_TOGGLE },
|
||||||
|
{ "NETPLAY_GAME_WATCH", RARCH_NETPLAY_GAME_WATCH },
|
||||||
|
{ "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 },
|
||||||
|
{ "UI_COMPANION_TOGGLE", RARCH_UI_COMPANION_TOGGLE },
|
||||||
|
{ "GAME_FOCUS_TOGGLE", RARCH_GAME_FOCUS_TOGGLE },
|
||||||
|
{ "MENU_TOGGLE", RARCH_MENU_TOGGLE },
|
||||||
|
{ "RECORDING_TOGGLE", RARCH_RECORDING_TOGGLE },
|
||||||
|
{ "STREAMING_TOGGLE", RARCH_STREAMING_TOGGLE },
|
||||||
|
{ "RUNAHEAD_TOGGLE", RARCH_RUNAHEAD_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 },
|
||||||
|
{ "AI_SERVICE", RARCH_AI_SERVICE },
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
RETRO_END_DECLS
|
RETRO_END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1195,6 +1195,7 @@ GIT
|
||||||
RETROARCH
|
RETROARCH
|
||||||
============================================================ */
|
============================================================ */
|
||||||
#include "../retroarch.c"
|
#include "../retroarch.c"
|
||||||
|
#include "../command.c"
|
||||||
#include "../libretro-common/queues/task_queue.c"
|
#include "../libretro-common/queues/task_queue.c"
|
||||||
|
|
||||||
#include "../msg_hash.c"
|
#include "../msg_hash.c"
|
||||||
|
|
|
@ -62,6 +62,7 @@ HAVE_NETWORKING=auto # Networking features (recommended)
|
||||||
HAVE_NETWORKGAMEPAD=auto # Networked game pad (plus baked-in core)
|
HAVE_NETWORKGAMEPAD=auto # Networked game pad (plus baked-in core)
|
||||||
C89_NETWORKGAMEPAD=no
|
C89_NETWORKGAMEPAD=no
|
||||||
HAVE_NETPLAYDISCOVERY=yes # Add netplay discovery (room creation, etc.)
|
HAVE_NETPLAYDISCOVERY=yes # Add netplay discovery (room creation, etc.)
|
||||||
|
HAVE_COMMAND=no # Network command interface, to remote control RA
|
||||||
HAVE_MINIUPNPC=auto # Mini UPnP client library (for NAT traversal)
|
HAVE_MINIUPNPC=auto # Mini UPnP client library (for NAT traversal)
|
||||||
HAVE_BUILTINMINIUPNPC=auto # Bake in Mini UPnP client library (for NAT traversal)
|
HAVE_BUILTINMINIUPNPC=auto # Bake in Mini UPnP client library (for NAT traversal)
|
||||||
C89_BUILTINMINIUPNPC=no
|
C89_BUILTINMINIUPNPC=no
|
||||||
|
|
485
retroarch.c
485
retroarch.c
|
@ -65,7 +65,6 @@
|
||||||
#include <boolean.h>
|
#include <boolean.h>
|
||||||
#include <clamping.h>
|
#include <clamping.h>
|
||||||
#include <string/stdstring.h>
|
#include <string/stdstring.h>
|
||||||
#include <streams/stdin_stream.h>
|
|
||||||
#include <dynamic/dylib.h>
|
#include <dynamic/dylib.h>
|
||||||
#include <file/config_file.h>
|
#include <file/config_file.h>
|
||||||
#include <lists/string_list.h>
|
#include <lists/string_list.h>
|
||||||
|
@ -9777,7 +9776,7 @@ static void dir_check_shader(struct rarch_state *p_rarch,
|
||||||
#if defined(HAVE_MENU)
|
#if defined(HAVE_MENU)
|
||||||
menu_driver_set_last_shader_preset_path(set_shader_path);
|
menu_driver_set_last_shader_preset_path(set_shader_path);
|
||||||
#endif
|
#endif
|
||||||
command_set_shader(set_shader_path);
|
command_set_shader(NULL, set_shader_path);
|
||||||
dir_list->shader_loaded = true;
|
dir_list->shader_loaded = true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -10304,51 +10303,19 @@ static void retroarch_autosave_deinit(struct rarch_state *p_rarch)
|
||||||
|
|
||||||
/* COMMAND */
|
/* COMMAND */
|
||||||
|
|
||||||
#if defined(HAVE_COMMAND)
|
#ifdef HAVE_COMMAND
|
||||||
#if (defined(HAVE_STDIN_CMD) || defined(HAVE_NETWORK_CMD))
|
|
||||||
static void command_reply(
|
|
||||||
struct rarch_state *p_rarch,
|
|
||||||
const char * data, size_t len)
|
|
||||||
{
|
|
||||||
const enum cmd_source_t lastcmd_source = p_rarch->lastcmd_source;
|
|
||||||
|
|
||||||
switch (lastcmd_source)
|
bool command_version(command_t *cmd, const char* arg)
|
||||||
{
|
|
||||||
case CMD_STDIN:
|
|
||||||
#ifdef HAVE_STDIN_CMD
|
|
||||||
fwrite(data, 1,len, stdout);
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
case CMD_NETWORK:
|
|
||||||
#ifdef HAVE_NETWORK_CMD
|
|
||||||
sendto(p_rarch->lastcmd_net_fd, data, len, 0,
|
|
||||||
(struct sockaddr*)&p_rarch->lastcmd_net_source,
|
|
||||||
p_rarch->lastcmd_net_source_len);
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
case CMD_NONE:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static bool command_version(const char* arg)
|
|
||||||
{
|
{
|
||||||
char reply[256] = {0};
|
char reply[256] = {0};
|
||||||
#if (defined(HAVE_STDIN_CMD) || defined(HAVE_NETWORK_CMD))
|
|
||||||
struct rarch_state *p_rarch = &rarch_st;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
snprintf(reply, sizeof(reply), "%s\n", PACKAGE_VERSION);
|
snprintf(reply, sizeof(reply), "%s\n", PACKAGE_VERSION);
|
||||||
#if (defined(HAVE_STDIN_CMD) || defined(HAVE_NETWORK_CMD))
|
cmd->replier(cmd, reply, strlen(reply));
|
||||||
command_reply(p_rarch, reply, strlen(reply));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool command_get_status(const char* arg)
|
bool command_get_status(command_t *cmd, const char* arg)
|
||||||
{
|
{
|
||||||
char reply[4096] = {0};
|
char reply[4096] = {0};
|
||||||
bool contentless = false;
|
bool contentless = false;
|
||||||
|
@ -10380,19 +10347,19 @@ static bool command_get_status(const char* arg)
|
||||||
snprintf(reply, sizeof(reply), "GET_STATUS %s %s,%s,crc32=%x\n", status, system_id, content_name, content_crc32);
|
snprintf(reply, sizeof(reply), "GET_STATUS %s %s,%s,crc32=%x\n", status, system_id, content_name, content_crc32);
|
||||||
}
|
}
|
||||||
|
|
||||||
command_reply(p_rarch, reply, strlen(reply));
|
cmd->replier(cmd, reply, strlen(reply));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool command_show_osd_msg(const char* arg)
|
bool command_show_osd_msg(command_t *cmd, const char* arg)
|
||||||
{
|
{
|
||||||
runloop_msg_queue_push(arg, 1, 180, false, NULL,
|
runloop_msg_queue_push(arg, 1, 180, false, NULL,
|
||||||
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool command_get_config_param(const char* arg)
|
bool command_get_config_param(command_t *cmd, const char* arg)
|
||||||
{
|
{
|
||||||
char reply[8192] = {0};
|
char reply[8192] = {0};
|
||||||
struct rarch_state *p_rarch = &rarch_st;
|
struct rarch_state *p_rarch = &rarch_st;
|
||||||
|
@ -10429,12 +10396,12 @@ static bool command_get_config_param(const char* arg)
|
||||||
/* TODO: query any string */
|
/* TODO: query any string */
|
||||||
|
|
||||||
snprintf(reply, sizeof(reply), "GET_CONFIG_PARAM %s %s\n", arg, value);
|
snprintf(reply, sizeof(reply), "GET_CONFIG_PARAM %s %s\n", arg, value);
|
||||||
command_reply(p_rarch, reply, strlen(reply));
|
cmd->replier(cmd, reply, strlen(reply));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(HAVE_CHEEVOS)
|
#if defined(HAVE_CHEEVOS)
|
||||||
static bool command_read_ram(const char *arg)
|
bool command_read_ram(command_t *cmd, const char *arg)
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
char *reply = NULL;
|
char *reply = NULL;
|
||||||
|
@ -10444,7 +10411,6 @@ static bool command_read_ram(const char *arg)
|
||||||
unsigned int alloc_size = 0;
|
unsigned int alloc_size = 0;
|
||||||
unsigned int addr = -1;
|
unsigned int addr = -1;
|
||||||
unsigned int len = 0;
|
unsigned int len = 0;
|
||||||
struct rarch_state *p_rarch = &rarch_st;
|
|
||||||
|
|
||||||
if (sscanf(arg, "%x %u", &addr, &nbytes) != 2)
|
if (sscanf(arg, "%x %u", &addr, &nbytes) != 2)
|
||||||
return true;
|
return true;
|
||||||
|
@ -10467,12 +10433,12 @@ static bool command_read_ram(const char *arg)
|
||||||
strlcpy(reply_at, " -1\n", sizeof(reply) - strlen(reply));
|
strlcpy(reply_at, " -1\n", sizeof(reply) - strlen(reply));
|
||||||
len = reply_at + STRLEN_CONST(" -1\n") - reply;
|
len = reply_at + STRLEN_CONST(" -1\n") - reply;
|
||||||
}
|
}
|
||||||
command_reply(p_rarch, reply, len);
|
cmd->replier(cmd, reply, len);
|
||||||
free(reply);
|
free(reply);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool command_write_ram(const char *arg)
|
bool command_write_ram(command_t *cmd, const char *arg)
|
||||||
{
|
{
|
||||||
unsigned int addr = (unsigned int)strtoul(arg, (char**)&arg, 16);
|
unsigned int addr = (unsigned int)strtoul(arg, (char**)&arg, 16);
|
||||||
uint8_t *data = (uint8_t *)rcheevos_patch_address(addr);
|
uint8_t *data = (uint8_t *)rcheevos_patch_address(addr);
|
||||||
|
@ -10549,7 +10515,7 @@ static uint8_t* command_memory_get_pointer(unsigned address, unsigned int* max_b
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool command_read_memory(const char *arg)
|
bool command_read_memory(command_t *cmd, const char *arg)
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
char* reply = NULL;
|
char* reply = NULL;
|
||||||
|
@ -10559,7 +10525,6 @@ static bool command_read_memory(const char *arg)
|
||||||
unsigned int alloc_size = 0;
|
unsigned int alloc_size = 0;
|
||||||
unsigned int address = -1;
|
unsigned int address = -1;
|
||||||
unsigned int len = 0;
|
unsigned int len = 0;
|
||||||
struct rarch_state *p_rarch = &rarch_st;
|
|
||||||
unsigned int max_bytes = 0;
|
unsigned int max_bytes = 0;
|
||||||
|
|
||||||
if (sscanf(arg, "%x %u", &address, &nbytes) != 2)
|
if (sscanf(arg, "%x %u", &address, &nbytes) != 2)
|
||||||
|
@ -10586,16 +10551,15 @@ static bool command_read_memory(const char *arg)
|
||||||
else
|
else
|
||||||
len = strlen(reply);
|
len = strlen(reply);
|
||||||
|
|
||||||
command_reply(p_rarch, reply, len);
|
cmd->replier(cmd, reply, len);
|
||||||
free(reply);
|
free(reply);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool command_write_memory(const char *arg)
|
bool command_write_memory(command_t *cmd, const char *arg)
|
||||||
{
|
{
|
||||||
unsigned int address = (unsigned int)strtoul(arg, (char**)&arg, 16);
|
unsigned int address = (unsigned int)strtoul(arg, (char**)&arg, 16);
|
||||||
unsigned int max_bytes = 0;
|
unsigned int max_bytes = 0;
|
||||||
struct rarch_state *p_rarch = &rarch_st;
|
|
||||||
char reply[128] = "";
|
char reply[128] = "";
|
||||||
char *reply_at = reply + snprintf(reply, sizeof(reply) - 1, "WRITE_CORE_MEMORY %x", address);
|
char *reply_at = reply + snprintf(reply, sizeof(reply) - 1, "WRITE_CORE_MEMORY %x", address);
|
||||||
uint8_t *data = command_memory_get_pointer(address, &max_bytes, 1, reply_at, sizeof(reply) - strlen(reply) - 1);
|
uint8_t *data = command_memory_get_pointer(address, &max_bytes, 1, reply_at, sizeof(reply) - strlen(reply) - 1);
|
||||||
|
@ -10622,335 +10586,9 @@ static bool command_write_memory(const char *arg)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
command_reply(p_rarch, reply, strlen(reply));
|
cmd->replier(cmd, reply, strlen(reply));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_NETWORK_CMD
|
|
||||||
static bool command_get_arg(const char *tok,
|
|
||||||
const char **arg, unsigned *index)
|
|
||||||
{
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(map); i++)
|
|
||||||
{
|
|
||||||
if (string_is_equal(tok, map[i].str))
|
|
||||||
{
|
|
||||||
if (arg)
|
|
||||||
*arg = NULL;
|
|
||||||
|
|
||||||
if (index)
|
|
||||||
*index = i;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 != ' ' && *argument != '\0')
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (arg)
|
|
||||||
*arg = argument + 1;
|
|
||||||
|
|
||||||
if (index)
|
|
||||||
*index = i;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool command_network_init(command_t *handle, uint16_t port)
|
|
||||||
{
|
|
||||||
struct addrinfo *res = NULL;
|
|
||||||
int fd = socket_init((void**)&res, port,
|
|
||||||
NULL, SOCKET_TYPE_DATAGRAM);
|
|
||||||
|
|
||||||
RARCH_LOG("%s %hu.\n",
|
|
||||||
msg_hash_to_str(MSG_BRINGING_UP_COMMAND_INTERFACE_ON_PORT),
|
|
||||||
(unsigned short)port);
|
|
||||||
|
|
||||||
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))
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 < ARRAY_SIZE(map); i++)
|
|
||||||
RARCH_ERR("\t\t%s\n", map[i].str);
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(action_map); i++)
|
|
||||||
RARCH_ERR("\t\t%s %s\n", action_map[i].str, action_map[i].arg_desc);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool command_network_send(const char *cmd_)
|
|
||||||
{
|
|
||||||
char *command = NULL;
|
|
||||||
char *save = NULL;
|
|
||||||
const char *cmd = NULL;
|
|
||||||
|
|
||||||
if (!network_init())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!(command = strdup(cmd_)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
cmd = strtok_r(command, ";", &save);
|
|
||||||
if (cmd)
|
|
||||||
{
|
|
||||||
uint16_t port = DEFAULT_NETWORK_CMD_PORT;
|
|
||||||
const char *port_ = NULL;
|
|
||||||
const char *host = strtok_r(NULL, ";", &save);
|
|
||||||
if (host)
|
|
||||||
port_ = strtok_r(NULL, ";", &save);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
|
||||||
host = "127.0.0.1";
|
|
||||||
#else
|
|
||||||
host = "localhost";
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if (port_)
|
|
||||||
port = strtoul(port_, NULL, 0);
|
|
||||||
|
|
||||||
RARCH_LOG("%s: \"%s\" to %s:%hu\n",
|
|
||||||
msg_hash_to_str(MSG_SENDING_COMMAND),
|
|
||||||
cmd, host, (unsigned short)port);
|
|
||||||
|
|
||||||
if (command_verify(cmd) && udp_send_packet(host, port, cmd))
|
|
||||||
{
|
|
||||||
free(command);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(command);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(HAVE_NETWORKING) && defined(HAVE_NETWORK_CMD) && defined(HAVE_COMMAND)
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void command_parse_msg(
|
|
||||||
struct rarch_state *p_rarch,
|
|
||||||
command_t *handle,
|
|
||||||
char *buf, enum cmd_source_t source)
|
|
||||||
{
|
|
||||||
char *save = NULL;
|
|
||||||
const char *tok = strtok_r(buf, "\n", &save);
|
|
||||||
|
|
||||||
p_rarch->lastcmd_source = source;
|
|
||||||
|
|
||||||
while (tok)
|
|
||||||
{
|
|
||||||
command_parse_sub_msg(handle, tok);
|
|
||||||
tok = strtok_r(NULL, "\n", &save);
|
|
||||||
}
|
|
||||||
|
|
||||||
p_rarch->lastcmd_source = CMD_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void command_network_poll(
|
|
||||||
struct rarch_state *p_rarch,
|
|
||||||
command_t *handle)
|
|
||||||
{
|
|
||||||
fd_set fds;
|
|
||||||
struct timeval tmp_tv = {0};
|
|
||||||
|
|
||||||
if (handle->net_fd < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
FD_ZERO(&fds);
|
|
||||||
FD_SET(handle->net_fd, &fds);
|
|
||||||
|
|
||||||
if (socket_select(handle->net_fd + 1, &fds, NULL, NULL, &tmp_tv) <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!FD_ISSET(handle->net_fd, &fds))
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
ssize_t ret;
|
|
||||||
char buf[1024];
|
|
||||||
|
|
||||||
buf[0] = '\0';
|
|
||||||
|
|
||||||
p_rarch->lastcmd_net_fd = handle->net_fd;
|
|
||||||
p_rarch->lastcmd_net_source_len = sizeof(p_rarch->lastcmd_net_source);
|
|
||||||
ret = recvfrom(handle->net_fd, buf,
|
|
||||||
sizeof(buf) - 1, 0,
|
|
||||||
(struct sockaddr*)&p_rarch->lastcmd_net_source,
|
|
||||||
&p_rarch->lastcmd_net_source_len);
|
|
||||||
|
|
||||||
if (ret <= 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
buf[ret] = '\0';
|
|
||||||
|
|
||||||
command_parse_msg(p_rarch, handle, buf, CMD_NETWORK);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static bool command_free(command_t *handle)
|
|
||||||
{
|
|
||||||
#ifdef HAVE_NETWORK_CMD
|
|
||||||
if (handle && handle->net_fd >= 0)
|
|
||||||
socket_close(handle->net_fd);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
free(handle);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_STDIN_CMD
|
|
||||||
static bool command_stdin_init(command_t *handle)
|
|
||||||
{
|
|
||||||
#ifndef _WIN32
|
|
||||||
#ifdef HAVE_NETWORKING
|
|
||||||
if (!socket_nonblock(STDIN_FILENO))
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
handle->stdin_enable = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void command_stdin_poll(
|
|
||||||
struct rarch_state *p_rarch,
|
|
||||||
command_t *handle)
|
|
||||||
{
|
|
||||||
ptrdiff_t msg_len;
|
|
||||||
char *last_newline = NULL;
|
|
||||||
ssize_t ret = read_stdin(
|
|
||||||
handle->stdin_buf + handle->stdin_buf_ptr,
|
|
||||||
STDIN_BUF_SIZE - handle->stdin_buf_ptr - 1);
|
|
||||||
|
|
||||||
if (ret == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
handle->stdin_buf_ptr += ret;
|
|
||||||
handle->stdin_buf[handle->stdin_buf_ptr] = '\0';
|
|
||||||
|
|
||||||
last_newline =
|
|
||||||
strrchr(handle->stdin_buf, '\n');
|
|
||||||
|
|
||||||
if (!last_newline)
|
|
||||||
{
|
|
||||||
/* We're receiving bogus data in pipe
|
|
||||||
* (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';
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
*last_newline++ = '\0';
|
|
||||||
msg_len = last_newline - handle->stdin_buf;
|
|
||||||
|
|
||||||
#if defined(HAVE_NETWORKING)
|
|
||||||
command_parse_msg(p_rarch,
|
|
||||||
handle, handle->stdin_buf, CMD_STDIN);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
memmove(handle->stdin_buf, last_newline,
|
|
||||||
handle->stdin_buf_ptr - msg_len);
|
|
||||||
handle->stdin_buf_ptr -= msg_len;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static bool command_network_new(
|
|
||||||
command_t *handle,
|
|
||||||
bool stdin_enable,
|
|
||||||
bool network_enable,
|
|
||||||
uint16_t port)
|
|
||||||
{
|
|
||||||
#ifdef HAVE_NETWORK_CMD
|
|
||||||
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;
|
|
||||||
|
|
||||||
#if defined(HAVE_NETWORK_CMD) || defined(HAVE_STDIN_CMD)
|
|
||||||
error:
|
|
||||||
command_free(handle);
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static bool retroarch_apply_shader(
|
static bool retroarch_apply_shader(
|
||||||
|
@ -11049,7 +10687,7 @@ static bool retroarch_apply_shader(
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
|
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
|
||||||
static bool command_set_shader(const char *arg)
|
bool command_set_shader(command_t *cmd, const char *arg)
|
||||||
{
|
{
|
||||||
enum rarch_shader_type type = video_shader_parse_type(arg);
|
enum rarch_shader_type type = video_shader_parse_type(arg);
|
||||||
struct rarch_state *p_rarch = &rarch_st;
|
struct rarch_state *p_rarch = &rarch_st;
|
||||||
|
@ -22630,20 +22268,16 @@ static void input_driver_poll(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_COMMAND
|
#ifdef HAVE_COMMAND
|
||||||
if (p_rarch->input_driver_command)
|
for (i = 0; i < ARRAY_SIZE(p_rarch->input_driver_command); i++)
|
||||||
{
|
{
|
||||||
memset(p_rarch->input_driver_command->state,
|
if (p_rarch->input_driver_command[i])
|
||||||
0, sizeof(p_rarch->input_driver_command->state));
|
{
|
||||||
#if defined(HAVE_NETWORK_CMD) && defined(HAVE_COMMAND)
|
memset(p_rarch->input_driver_command[i]->state,
|
||||||
command_network_poll(p_rarch,
|
0, sizeof(p_rarch->input_driver_command[i]->state));
|
||||||
p_rarch->input_driver_command);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_STDIN_CMD
|
p_rarch->input_driver_command[i]->poll(
|
||||||
if (p_rarch->input_driver_command->stdin_enable)
|
p_rarch->input_driver_command[i]);
|
||||||
command_stdin_poll(p_rarch,
|
}
|
||||||
p_rarch->input_driver_command);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -24778,18 +24412,20 @@ static INLINE bool input_keys_pressed_other_sources(
|
||||||
unsigned i,
|
unsigned i,
|
||||||
input_bits_t* p_new_state)
|
input_bits_t* p_new_state)
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_COMMAND
|
||||||
|
int j;
|
||||||
|
for (j = 0; j < ARRAY_SIZE(p_rarch->input_driver_command); j++)
|
||||||
|
if ((i < RARCH_BIND_LIST_END) && p_rarch->input_driver_command[j]
|
||||||
|
&& p_rarch->input_driver_command[j]->state[i])
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_OVERLAY
|
#ifdef HAVE_OVERLAY
|
||||||
if (p_rarch->overlay_ptr &&
|
if (p_rarch->overlay_ptr &&
|
||||||
((BIT256_GET(p_rarch->overlay_ptr->overlay_state.buttons, i))))
|
((BIT256_GET(p_rarch->overlay_ptr->overlay_state.buttons, i))))
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_COMMAND
|
|
||||||
if (p_rarch->input_driver_command)
|
|
||||||
return ((i < RARCH_BIND_LIST_END)
|
|
||||||
&& p_rarch->input_driver_command->state[i]);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_NETWORKGAMEPAD
|
#ifdef HAVE_NETWORKGAMEPAD
|
||||||
/* Only process key presses related to game input if using Remote RetroPad */
|
/* Only process key presses related to game input if using Remote RetroPad */
|
||||||
if (i < RARCH_CUSTOM_BIND_LIST_END
|
if (i < RARCH_CUSTOM_BIND_LIST_END
|
||||||
|
@ -25046,7 +24682,7 @@ void input_driver_unset_nonblock_state(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_COMMAND
|
#ifdef HAVE_COMMAND
|
||||||
static bool input_driver_init_command(struct rarch_state *p_rarch)
|
static void input_driver_init_command(struct rarch_state *p_rarch)
|
||||||
{
|
{
|
||||||
settings_t *settings = p_rarch->configuration_settings;
|
settings_t *settings = p_rarch->configuration_settings;
|
||||||
bool input_stdin_cmd_enable = settings->bools.stdin_cmd_enable;
|
bool input_stdin_cmd_enable = settings->bools.stdin_cmd_enable;
|
||||||
|
@ -25055,35 +24691,50 @@ static bool input_driver_init_command(struct rarch_state *p_rarch)
|
||||||
bool grab_stdin = p_rarch->current_input->grab_stdin &&
|
bool grab_stdin = p_rarch->current_input->grab_stdin &&
|
||||||
p_rarch->current_input->grab_stdin(p_rarch->current_input_data);
|
p_rarch->current_input->grab_stdin(p_rarch->current_input_data);
|
||||||
|
|
||||||
if (!input_stdin_cmd_enable && !input_network_cmd_enable)
|
#ifdef HAVE_STDIN_CMD
|
||||||
return false;
|
if (input_stdin_cmd_enable)
|
||||||
|
{
|
||||||
if (input_stdin_cmd_enable && grab_stdin)
|
if (grab_stdin)
|
||||||
{
|
{
|
||||||
RARCH_WARN("stdin command interface is desired, but input driver has already claimed stdin.\n"
|
RARCH_WARN("stdin command interface is desired, but input driver has already claimed stdin.\n"
|
||||||
"Cannot use this command interface.\n");
|
"Cannot use this command interface.\n");
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
p_rarch->input_driver_command[0] = command_stdin_new();
|
||||||
|
if (!p_rarch->input_driver_command[1])
|
||||||
|
RARCH_ERR("Failed to initialize the stdin command interface.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
p_rarch->input_driver_command = (command_t*)
|
/* Initialize the network command interface */
|
||||||
calloc(1, sizeof(*p_rarch->input_driver_command));
|
#ifdef HAVE_NETWORK_CMD
|
||||||
|
if (input_network_cmd_enable)
|
||||||
|
{
|
||||||
|
p_rarch->input_driver_command[1] = command_network_new(network_cmd_port);
|
||||||
|
if (!p_rarch->input_driver_command[1])
|
||||||
|
RARCH_ERR("Failed to initialize the network command interface.\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (p_rarch->input_driver_command)
|
#ifdef HAVE_LAKKA
|
||||||
if (command_network_new(
|
p_rarch->input_driver_command[2] = command_uds_new();
|
||||||
p_rarch->input_driver_command,
|
if (!p_rarch->input_driver_command[2])
|
||||||
input_stdin_cmd_enable && !grab_stdin,
|
RARCH_ERR("Failed to initialize the UDS command interface.\n");
|
||||||
input_network_cmd_enable,
|
#endif
|
||||||
network_cmd_port))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
RARCH_ERR("Failed to initialize command interface.\n");
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void input_driver_deinit_command(struct rarch_state *p_rarch)
|
static void input_driver_deinit_command(struct rarch_state *p_rarch)
|
||||||
{
|
{
|
||||||
if (p_rarch->input_driver_command)
|
int i;
|
||||||
command_free(p_rarch->input_driver_command);
|
for (i = 0; i < ARRAY_SIZE(p_rarch->input_driver_command); i++)
|
||||||
p_rarch->input_driver_command = NULL;
|
{
|
||||||
|
if (p_rarch->input_driver_command[i])
|
||||||
|
p_rarch->input_driver_command[i]->destroy(
|
||||||
|
p_rarch->input_driver_command[i]);
|
||||||
|
|
||||||
|
p_rarch->input_driver_command[i] = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
139
retroarch_data.h
139
retroarch_data.h
|
@ -107,9 +107,6 @@
|
||||||
#define DECLARE_BIND(base, bind, desc) { #base, desc, 0, bind, true }
|
#define DECLARE_BIND(base, bind, desc) { #base, desc, 0, bind, true }
|
||||||
#define DECLARE_META_BIND(level, base, bind, desc) { #base, desc, level, bind, true }
|
#define DECLARE_META_BIND(level, base, bind, desc) { #base, desc, level, bind, true }
|
||||||
|
|
||||||
#define DEFAULT_NETWORK_CMD_PORT 55355
|
|
||||||
#define STDIN_BUF_SIZE 4096
|
|
||||||
|
|
||||||
#ifdef HAVE_THREADS
|
#ifdef HAVE_THREADS
|
||||||
#define VIDEO_DRIVER_IS_THREADED_INTERNAL() ((!video_driver_is_hw_context() && p_rarch->video_driver_threaded) ? true : false)
|
#define VIDEO_DRIVER_IS_THREADED_INTERNAL() ((!video_driver_is_hw_context() && p_rarch->video_driver_threaded) ? true : false)
|
||||||
#else
|
#else
|
||||||
|
@ -1301,13 +1298,6 @@ enum rarch_movie_type
|
||||||
RARCH_MOVIE_RECORD
|
RARCH_MOVIE_RECORD
|
||||||
};
|
};
|
||||||
|
|
||||||
enum cmd_source_t
|
|
||||||
{
|
|
||||||
CMD_NONE = 0,
|
|
||||||
CMD_STDIN,
|
|
||||||
CMD_NETWORK
|
|
||||||
};
|
|
||||||
|
|
||||||
enum poll_type_override_t
|
enum poll_type_override_t
|
||||||
{
|
{
|
||||||
POLL_TYPE_OVERRIDE_DONTCARE = 0,
|
POLL_TYPE_OVERRIDE_DONTCARE = 0,
|
||||||
|
@ -1485,36 +1475,6 @@ struct input_overlay
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct cmd_map
|
|
||||||
{
|
|
||||||
const char *str;
|
|
||||||
unsigned id;
|
|
||||||
};
|
|
||||||
|
|
||||||
#if defined(HAVE_COMMAND)
|
|
||||||
struct cmd_action_map
|
|
||||||
{
|
|
||||||
const char *str;
|
|
||||||
bool (*action)(const char *arg);
|
|
||||||
const char *arg_desc;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct command
|
|
||||||
{
|
|
||||||
#ifdef HAVE_STDIN_CMD
|
|
||||||
size_t stdin_buf_ptr;
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_NETWORK_CMD
|
|
||||||
int net_fd;
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_STDIN_CMD
|
|
||||||
char stdin_buf[STDIN_BUF_SIZE];
|
|
||||||
#endif
|
|
||||||
bool stdin_enable;
|
|
||||||
bool state[RARCH_BIND_LIST_END];
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Input config. */
|
/* Input config. */
|
||||||
struct input_bind_map
|
struct input_bind_map
|
||||||
{
|
{
|
||||||
|
@ -1751,11 +1711,6 @@ struct rarch_state
|
||||||
#ifdef HAVE_MENU
|
#ifdef HAVE_MENU
|
||||||
struct menu_state menu_driver_state; /* int64_t alignment */
|
struct menu_state menu_driver_state; /* int64_t alignment */
|
||||||
#endif
|
#endif
|
||||||
#if defined(HAVE_COMMAND)
|
|
||||||
#ifdef HAVE_NETWORK_CMD
|
|
||||||
struct sockaddr_storage lastcmd_net_source; /* int64_t alignment */
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_GFX_WIDGETS
|
#ifdef HAVE_GFX_WIDGETS
|
||||||
dispgfx_widget_t dispwidget_st; /* uint64_t alignment */
|
dispgfx_widget_t dispwidget_st; /* uint64_t alignment */
|
||||||
#endif
|
#endif
|
||||||
|
@ -1883,7 +1838,7 @@ struct rarch_state
|
||||||
void *keyboard_press_data;
|
void *keyboard_press_data;
|
||||||
|
|
||||||
#ifdef HAVE_COMMAND
|
#ifdef HAVE_COMMAND
|
||||||
command_t *input_driver_command;
|
command_t *input_driver_command[MAX_CMD_DRIVERS];
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_NETWORKGAMEPAD
|
#ifdef HAVE_NETWORKGAMEPAD
|
||||||
input_remote_t *input_driver_remote;
|
input_remote_t *input_driver_remote;
|
||||||
|
@ -2133,11 +2088,6 @@ struct rarch_state
|
||||||
* TODO - Dirty hack, fix it better
|
* TODO - Dirty hack, fix it better
|
||||||
*/
|
*/
|
||||||
gfx_ctx_flags_t deferred_flag_data; /* uint32_t alignment */
|
gfx_ctx_flags_t deferred_flag_data; /* uint32_t alignment */
|
||||||
#if defined(HAVE_COMMAND)
|
|
||||||
#ifdef HAVE_NETWORK_CMD
|
|
||||||
socklen_t lastcmd_net_source_len; /* uint32_t alignment */
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
retro_bits_t has_set_libretro_device; /* uint32_t alignment */
|
retro_bits_t has_set_libretro_device; /* uint32_t alignment */
|
||||||
input_mapper_t input_driver_mapper; /* uint32_t alignment */
|
input_mapper_t input_driver_mapper; /* uint32_t alignment */
|
||||||
|
|
||||||
|
@ -2691,93 +2641,6 @@ static enum rarch_shader_type shader_types[] =
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* These forward declarations need to be declared before
|
|
||||||
* the global state is declared */
|
|
||||||
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
|
|
||||||
static bool command_set_shader(const char *arg);
|
|
||||||
#endif
|
|
||||||
#if defined(HAVE_COMMAND)
|
|
||||||
static bool command_version(const char* arg);
|
|
||||||
static bool command_get_status(const char* arg);
|
|
||||||
static bool command_get_config_param(const char* arg);
|
|
||||||
static bool command_show_osd_msg(const char* arg);
|
|
||||||
#ifdef HAVE_CHEEVOS
|
|
||||||
static bool command_read_ram(const char *arg);
|
|
||||||
static bool command_write_ram(const char *arg);
|
|
||||||
#endif
|
|
||||||
static bool command_read_memory(const char *arg);
|
|
||||||
static bool command_write_memory(const char *arg);
|
|
||||||
|
|
||||||
static const struct cmd_action_map action_map[] = {
|
|
||||||
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
|
|
||||||
{ "SET_SHADER", command_set_shader, "<shader path>" },
|
|
||||||
#endif
|
|
||||||
{ "VERSION", command_version, "No argument"},
|
|
||||||
{ "GET_STATUS", command_get_status, "No argument" },
|
|
||||||
{ "GET_CONFIG_PARAM", command_get_config_param, "<param name>" },
|
|
||||||
{ "SHOW_MSG", command_show_osd_msg, "No argument" },
|
|
||||||
#if defined(HAVE_CHEEVOS)
|
|
||||||
/* These functions use achievement addresses and only work if a game with achievements is
|
|
||||||
* loaded. READ_CORE_MEMORY and WRITE_CORE_MEMORY are preferred and use system addresses. */
|
|
||||||
{ "READ_CORE_RAM", command_read_ram, "<address> <number of bytes>" },
|
|
||||||
{ "WRITE_CORE_RAM", command_write_ram, "<address> <byte1> <byte2> ..." },
|
|
||||||
#endif
|
|
||||||
{ "READ_CORE_MEMORY", command_read_memory, "<address> <number of bytes>" },
|
|
||||||
{ "WRITE_CORE_MEMORY",command_write_memory, "<address> <byte1> <byte2> ..." },
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct cmd_map map[] = {
|
|
||||||
{ "FAST_FORWARD", RARCH_FAST_FORWARD_KEY },
|
|
||||||
{ "FAST_FORWARD_HOLD", RARCH_FAST_FORWARD_HOLD_KEY },
|
|
||||||
{ "SLOWMOTION", RARCH_SLOWMOTION_KEY },
|
|
||||||
{ "SLOWMOTION_HOLD", RARCH_SLOWMOTION_HOLD_KEY },
|
|
||||||
{ "LOAD_STATE", RARCH_LOAD_STATE_KEY },
|
|
||||||
{ "SAVE_STATE", RARCH_SAVE_STATE_KEY },
|
|
||||||
{ "FULLSCREEN_TOGGLE", RARCH_FULLSCREEN_TOGGLE_KEY },
|
|
||||||
{ "CLOSE_CONTENT", RARCH_CLOSE_CONTENT_KEY },
|
|
||||||
{ "QUIT", RARCH_QUIT_KEY },
|
|
||||||
{ "STATE_SLOT_PLUS", RARCH_STATE_SLOT_PLUS },
|
|
||||||
{ "STATE_SLOT_MINUS", RARCH_STATE_SLOT_MINUS },
|
|
||||||
{ "REWIND", RARCH_REWIND },
|
|
||||||
{ "BSV_RECORD_TOGGLE", RARCH_BSV_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 },
|
|
||||||
{ "FPS_TOGGLE", RARCH_FPS_TOGGLE },
|
|
||||||
{ "SEND_DEBUG_INFO", RARCH_SEND_DEBUG_INFO },
|
|
||||||
{ "NETPLAY_HOST_TOGGLE", RARCH_NETPLAY_HOST_TOGGLE },
|
|
||||||
{ "NETPLAY_GAME_WATCH", RARCH_NETPLAY_GAME_WATCH },
|
|
||||||
{ "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 },
|
|
||||||
{ "UI_COMPANION_TOGGLE", RARCH_UI_COMPANION_TOGGLE },
|
|
||||||
{ "GAME_FOCUS_TOGGLE", RARCH_GAME_FOCUS_TOGGLE },
|
|
||||||
{ "MENU_TOGGLE", RARCH_MENU_TOGGLE },
|
|
||||||
{ "RECORDING_TOGGLE", RARCH_RECORDING_TOGGLE },
|
|
||||||
{ "STREAMING_TOGGLE", RARCH_STREAMING_TOGGLE },
|
|
||||||
{ "RUNAHEAD_TOGGLE", RARCH_RUNAHEAD_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 },
|
|
||||||
{ "AI_SERVICE", RARCH_AI_SERVICE },
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_MENU
|
#ifdef HAVE_MENU
|
||||||
static void *null_menu_init(void **userdata, bool video_is_threaded)
|
static void *null_menu_init(void **userdata, bool video_is_threaded)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue