Support for keyboards over netplay.

This commit is contained in:
Gregor Richards 2017-09-13 20:51:57 -04:00
parent c01a199493
commit a96eb24247
11 changed files with 310 additions and 11 deletions

View File

@ -1508,6 +1508,7 @@ ifeq ($(HAVE_NETWORKING), 1)
network/netplay/netplay_handshake.o \
network/netplay/netplay_init.o \
network/netplay/netplay_io.o \
network/netplay/netplay_keyboard.o \
network/netplay/netplay_sync.o \
network/netplay/netplay_discovery.o \
network/netplay/netplay_buf.o \

View File

@ -1029,6 +1029,7 @@ NETPLAY
#include "../network/netplay/netplay_handshake.c"
#include "../network/netplay/netplay_init.c"
#include "../network/netplay/netplay_io.c"
#include "../network/netplay/netplay_keyboard.c"
#include "../network/netplay/netplay_sync.c"
#include "../network/netplay/netplay_discovery.c"
#include "../network/netplay/netplay_buf.c"

View File

@ -379,6 +379,9 @@ MOUSE
X: int16
}
KEYBOARD
(5 words, see netplay_keys.h)
LIGHTGUN
{
unused, unused, Trigger, Cursor, Turbo, Pause, Start

View File

@ -179,6 +179,7 @@ uint32_t netplay_expected_input_size(netplay_t *netplay, uint32_t devices)
* fixed size, documented in network/netplay/README */
case RETRO_DEVICE_JOYPAD: ret += 1; break;
case RETRO_DEVICE_MOUSE: ret += 2; break;
case RETRO_DEVICE_KEYBOARD: ret += 5; break;
case RETRO_DEVICE_LIGHTGUN: ret += 2; break;
case RETRO_DEVICE_ANALOG: ret += 3; break;
default: break; /* Unsupported */

View File

@ -201,6 +201,26 @@ static bool get_self_input_state(netplay_t *netplay)
}
break;
}
case RETRO_DEVICE_KEYBOARD:
{
unsigned key, word = 0, bit = 1;
for (key = 1; key < NETPLAY_KEY_LAST; key++)
{
state[word] |=
cb(local_device, RETRO_DEVICE_KEYBOARD, 0, netplay_key_ntoh(key)) ?
(1U << bit) : 0;
bit++;
if (bit >= 32)
{
bit = 0;
word++;
if (word >= istate->size)
break;
}
}
break;
}
}
}
}
@ -536,7 +556,8 @@ static int16_t netplay_input_state(netplay_t *netplay,
return 0;
/* If the port doesn't seem to correspond to the device, "correct" it. This
* is common with e.g. zappers. */
* is common with devices that typically only have one instance, such as
* keyboards, mice and lightguns. */
if (device != RETRO_DEVICE_JOYPAD &&
(netplay->config_devices[port]&RETRO_DEVICE_MASK) != device)
{
@ -582,6 +603,19 @@ static int16_t netplay_input_state(netplay_t *netplay,
return ((1 << id) & curr_input_state[0]) ? 1 : 0;
}
case RETRO_DEVICE_KEYBOARD:
{
unsigned key, word, bit;
key = netplay_key_hton(id);
if (key == NETPLAY_KEY_UNKNOWN)
return 0;
word = key/32;
bit = key%32;
if (word <= istate->size)
return ((1U<<bit) & curr_input_state[word]) ? 1 : 0;
return 0;
}
default:
return 0;
}

View File

@ -1022,6 +1022,8 @@ bool netplay_handshake_pre_sync(netplay_t *netplay,
pad.port = (unsigned)i;
pad.device = ntohl(device);
netplay->config_devices[i] = pad.device;
if ((pad.device&RETRO_DEVICE_MASK) == RETRO_DEVICE_KEYBOARD)
netplay_key_hton_init();
core_set_controller_port_device(&pad);
}

View File

@ -475,6 +475,8 @@ netplay_t *netplay_new(void *direct_host, const char *server, uint16_t port,
{
uint32_t dtype = input_config_get_device(i);
netplay->config_devices[i] = dtype;
if ((dtype&RETRO_DEVICE_MASK) == RETRO_DEVICE_KEYBOARD)
netplay_key_hton_init();
if (dtype != RETRO_DEVICE_NONE && !netplay_expected_input_size(netplay, 1<<i))
RARCH_WARN("Netplay does not support input device %u\n", i+1);
}

View File

@ -0,0 +1,53 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2017 - Gregor Richards
*
* 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 "netplay_private.h"
/* The mapping of keys from netplay (network) to libretro (host) */
const uint16_t netplay_key_ntoh_mapping[] = {
(uint16_t) RETROK_UNKNOWN,
#define K(k) (uint16_t) RETROK_ ## k,
#define KL(k,l) (uint16_t) l,
#include "netplay_keys.h"
#undef KL
#undef K
0
};
static bool mapping_defined = false;
static uint16_t mapping[RETROK_LAST];
/* The mapping of keys from libretro (host) to netplay (network) */
uint32_t netplay_key_hton(unsigned key)
{
if (key >= RETROK_LAST)
return NETPLAY_KEY_UNKNOWN;
return mapping[key];
}
/* Because the hton keymapping has to be generated, call this before using
* netplay_key_hton */
void netplay_key_hton_init(void)
{
if (!mapping_defined)
{
uint16_t i;
for (i = 0; i < NETPLAY_KEY_LAST; i++)
mapping[netplay_key_ntoh(i)] = i;
mapping_defined = true;
}
}

View File

@ -0,0 +1,169 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2016-2017 - Gregor Richards
*
* 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/>.
*/
/* This is an X-include file which defines the mapping of keycodes used by
* libretro to keycodes used by RetroArch Netplay. The keycodes are different
* because the keycodes supported by libretro are in discontiguous blocks,
* which would create gaps in the input data, requiring more space and more
* network bandwidth to represent them.
*
* If you want to add a new keycode, make sure you add it to the END. The order
* that the keys appear in this file defines their indices in the netplay
* protocol, so adding a key in the middle will break backwards compatibility.
* If you want to clean up the order and thereby break backwards compatibility,
* make sure you bump the protocol version in netplay_private.h.
*/
K(BACKSPACE)
K(TAB)
KL(LINEFEED, 10)
K(CLEAR)
K(RETURN)
K(PAUSE)
K(ESCAPE)
K(SPACE)
K(EXCLAIM)
K(QUOTEDBL)
K(HASH)
K(DOLLAR)
K(AMPERSAND)
K(QUOTE)
K(LEFTPAREN)
K(RIGHTPAREN)
K(ASTERISK)
K(PLUS)
K(COMMA)
K(MINUS)
K(PERIOD)
K(SLASH)
K(0)
K(1)
K(2)
K(3)
K(4)
K(5)
K(6)
K(7)
K(8)
K(9)
K(COLON)
K(SEMICOLON)
K(LESS)
K(EQUALS)
K(GREATER)
K(QUESTION)
K(AT)
K(LEFTBRACKET)
K(BACKSLASH)
K(RIGHTBRACKET)
K(CARET)
K(UNDERSCORE)
K(BACKQUOTE)
K(a)
K(b)
K(c)
K(d)
K(e)
K(f)
K(g)
K(h)
K(i)
K(j)
K(k)
K(l)
K(m)
K(n)
K(o)
K(p)
K(q)
K(r)
K(s)
K(t)
K(u)
K(v)
K(w)
K(x)
K(y)
K(z)
K(DELETE)
K(KP0)
K(KP1)
K(KP2)
K(KP3)
K(KP4)
K(KP5)
K(KP6)
K(KP7)
K(KP8)
K(KP9)
K(KP_PERIOD)
K(KP_DIVIDE)
K(KP_MULTIPLY)
K(KP_MINUS)
K(KP_PLUS)
K(KP_ENTER)
K(KP_EQUALS)
K(UP)
K(DOWN)
K(RIGHT)
K(LEFT)
K(INSERT)
K(HOME)
K(END)
K(PAGEUP)
K(PAGEDOWN)
K(F1)
K(F2)
K(F3)
K(F4)
K(F5)
K(F6)
K(F7)
K(F8)
K(F9)
K(F10)
K(F11)
K(F12)
K(F13)
K(F14)
K(F15)
K(NUMLOCK)
K(CAPSLOCK)
K(SCROLLOCK)
K(RSHIFT)
K(LSHIFT)
K(RCTRL)
K(LCTRL)
K(RALT)
K(LALT)
K(RMETA)
K(LMETA)
K(LSUPER)
K(RSUPER)
K(MODE)
K(COMPOSE)
K(HELP)
K(PRINT)
K(SYSREQ)
K(BREAK)
K(MENU)
K(POWER)
K(EURO)
K(UNDO)

View File

@ -48,10 +48,9 @@
#define MAX_CLIENTS 32
typedef uint32_t client_bitmap_t;
/* For now we only support the normal or analog gamepad */
#define NETPLAY_SUPPORTED_DEVICES ( \
(1<<RETRO_DEVICE_JOYPAD) | \
(1<<RETRO_DEVICE_ANALOG))
/* Because the callback keyboard reverses some assumptions, when the keyboard
* callbacks are in use, we assign a pseudodevice for it */
#define RETRO_DEVICE_NETPLAY_KEYBOARD RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_KEYBOARD, 65535)
#define NETPLAY_MAX_STALL_FRAMES 60
#define NETPLAY_FRAME_RUN_TIME_WINDOW 120
@ -916,6 +915,33 @@ void netplay_announce_nat_traversal(netplay_t *netplay);
void netplay_init_nat_traversal(netplay_t *netplay);
/***************************************************************
* NETPLAY-KEYBOARD.C
**************************************************************/
/* The keys supported by netplay */
enum netplay_keys {
NETPLAY_KEY_UNKNOWN = 0,
#define K(k) NETPLAY_KEY_ ## k,
#define KL(k,l) K(k)
#include "netplay_keys.h"
#undef KL
#undef K
NETPLAY_KEY_LAST
};
/* The mapping of keys from netplay (network) to libretro (host) */
extern const uint16_t netplay_key_ntoh_mapping[];
#define netplay_key_ntoh(k) (netplay_key_ntoh_mapping[k])
/* The mapping of keys from libretro (host) to netplay (network) */
uint32_t netplay_key_hton(unsigned key);
/* Because the hton keymapping has to be generated, call this before using
* netplay_key_hton */
void netplay_key_hton_init(void);
/***************************************************************
* NETPLAY-SYNC.C
**************************************************************/

View File

@ -277,12 +277,15 @@ static void netplay_merge_analog(netplay_t *netplay,
netplay_input_state_t resstate, struct delta_frame *simframe,
uint32_t device, uint32_t clients, unsigned dtype)
{
if (dtype == RETRO_DEVICE_JOYPAD)
/* Devices with no analog parts */
if (dtype == RETRO_DEVICE_JOYPAD || dtype == RETRO_DEVICE_KEYBOARD)
return;
/* All other devices have analog */
/* All other devices have at least one analog word */
merge_analog_part(netplay, resstate, simframe, device, clients, 1, 0);
merge_analog_part(netplay, resstate, simframe, device, clients, 1, 16);
/* And the ANALOG device has two (two sticks) */
if (dtype == RETRO_DEVICE_ANALOG)
{
merge_analog_part(netplay, resstate, simframe, device, clients, 2, 0);
@ -432,10 +435,14 @@ bool netplay_resolve_input(netplay_t *netplay, size_t sim_ptr, bool resim)
else
{
/* Merge them */
/* NOTE: As it happens, all of our devices keep the digital data in
* the first word, so this is fine, but it'll have to change when
* other devices are supported. */
static const uint32_t digital[3] = {-1, 0, 0};
/* Most devices have all the digital parts in the first word. */
static const uint32_t digital_common[3] = {-1, 0, 0};
static const uint32_t digital_keyboard[5] = {-1, -1, -1, -1, -1};
const uint32_t *digital;
if (dtype == RETRO_DEVICE_KEYBOARD)
digital = digital_keyboard;
else
digital = digital_common;
oldresstate = netplay_input_state_for(&simframe->resolved_input[device], 1, dsize, false, false);
if (!oldresstate)
continue;