mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-08-26 04:06:32 +00:00
even with 87dc83e
This commit is contained in:
parent
b3cd9324d4
commit
be07a173c3
5 changed files with 347 additions and 9 deletions
|
@ -46,7 +46,7 @@ option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence, show the current gam
|
|||
option(ENABLE_ANALYTICS "Enables opt-in Analytics collection" OFF)
|
||||
|
||||
# Enable Playback build for Slippi. TODO: turn off for normal builds
|
||||
option(SLIPPI_PLAYBACK "Enable Playback changes" ON)
|
||||
option(SLIPPI_PLAYBACK "Enable Playback changes" OFF)
|
||||
|
||||
option(ENCODE_FRAMEDUMPS "Encode framedumps in AVI format" ON)
|
||||
|
||||
|
|
257
Data/install_smashenabler.sh
Normal file
257
Data/install_smashenabler.sh
Normal file
|
@ -0,0 +1,257 @@
|
|||
#!/bin/sh
|
||||
# shellcheck shell=dash
|
||||
|
||||
# This is just a little script that can be downloaded from the internet to
|
||||
# install SmashEnabler.
|
||||
#
|
||||
# It runs on Unix shells like {a,ba,da,k,z}sh. It uses the common `local`
|
||||
# extension. Note: Most shells limit `local` to 1 var per line, contra bash.
|
||||
#
|
||||
# Borrow heavily and liberally from rustup's install script. ;P
|
||||
|
||||
set -u
|
||||
|
||||
usage() {
|
||||
cat 1>&2 <<EOF
|
||||
smashenabler-installer 0.0.1 (2020-07-20)
|
||||
The installer for SmashEnabler.kext
|
||||
USAGE:
|
||||
[FLAGS] [OPTIONS]
|
||||
EOF
|
||||
}
|
||||
|
||||
main() {
|
||||
downloader --check
|
||||
|
||||
local _url="https://forums.dolphin-emu.org/attachment.php?aid=16637"
|
||||
say "Downloading kext from ${_url}."
|
||||
|
||||
local _file="SmashEnabler.kext.zip"
|
||||
ensure downloader "$_url" "$_file"
|
||||
|
||||
say "Unzipping..."
|
||||
unzip "$_file"
|
||||
|
||||
say "Clearing out old versions if they exist. This may require your password."
|
||||
sudo rm -rf /Library/Extensions/SmashEnabler.kext
|
||||
|
||||
say "Installing kext. This may require your password."
|
||||
sudo mv SmashEnabler.kext /Library/Extensions/
|
||||
sudo chown -R root:wheel /Library/Extensions/SmashEnabler.kext
|
||||
sudo touch /Library/Extensions
|
||||
|
||||
say "Cleaning up..."
|
||||
rm "${_file}"
|
||||
|
||||
say "Kext installed. You should boot into recovery mode and re-enable SIP to be safe."
|
||||
|
||||
local _retval=$?
|
||||
return "$_retval"
|
||||
}
|
||||
|
||||
say() {
|
||||
printf 'smashenabler-installer: %s\n' "$1"
|
||||
}
|
||||
|
||||
err() {
|
||||
say "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
need_cmd() {
|
||||
if ! check_cmd "$1"; then
|
||||
err "need '$1' (command not found)"
|
||||
fi
|
||||
}
|
||||
|
||||
check_cmd() {
|
||||
command -v "$1" > /dev/null 2>&1
|
||||
}
|
||||
|
||||
assert_nz() {
|
||||
if [ -z "$1" ]; then err "assert_nz $2"; fi
|
||||
}
|
||||
|
||||
# Run a command that should never fail. If the command fails execution
|
||||
# will immediately terminate with an error showing the failing
|
||||
# command.
|
||||
ensure() {
|
||||
if ! "$@"; then err "command failed: $*"; fi
|
||||
}
|
||||
|
||||
# This is just for indicating that commands' results are being
|
||||
# intentionally ignored. Usually, because it's being executed
|
||||
# as part of error handling.
|
||||
ignore() {
|
||||
"$@"
|
||||
}
|
||||
|
||||
# This wraps curl or wget. Try curl first, if not installed,
|
||||
# use wget instead.
|
||||
downloader() {
|
||||
local _dld
|
||||
local _ciphersuites
|
||||
if check_cmd curl; then
|
||||
_dld=curl
|
||||
elif check_cmd wget; then
|
||||
_dld=wget
|
||||
else
|
||||
_dld='curl or wget' # to be used in error message of need_cmd
|
||||
fi
|
||||
|
||||
if [ "$1" = --check ]; then
|
||||
need_cmd "$_dld"
|
||||
elif [ "$_dld" = curl ]; then
|
||||
get_ciphersuites_for_curl
|
||||
_ciphersuites="$RETVAL"
|
||||
if [ -n "$_ciphersuites" ]; then
|
||||
curl --proto '=https' --tlsv1.2 --ciphers "$_ciphersuites" --silent --show-error --fail --location "$1" --output "$2"
|
||||
else
|
||||
echo "Warning: Not enforcing strong cipher suites for TLS, this is potentially less secure"
|
||||
if ! check_help_for "$3" curl --proto --tlsv1.2; then
|
||||
echo "Warning: Not enforcing TLS v1.2, this is potentially less secure"
|
||||
curl --silent --show-error --fail --location "$1" --output "$2"
|
||||
else
|
||||
curl --proto '=https' --tlsv1.2 --silent --show-error --fail --location "$1" --output "$2"
|
||||
fi
|
||||
fi
|
||||
elif [ "$_dld" = wget ]; then
|
||||
get_ciphersuites_for_wget
|
||||
_ciphersuites="$RETVAL"
|
||||
if [ -n "$_ciphersuites" ]; then
|
||||
wget --https-only --secure-protocol=TLSv1_2 --ciphers "$_ciphersuites" "$1" -O "$2"
|
||||
else
|
||||
echo "Warning: Not enforcing strong cipher suites for TLS, this is potentially less secure"
|
||||
if ! check_help_for "$3" wget --https-only --secure-protocol; then
|
||||
echo "Warning: Not enforcing TLS v1.2, this is potentially less secure"
|
||||
wget "$1" -O "$2"
|
||||
else
|
||||
wget --https-only --secure-protocol=TLSv1_2 "$1" -O "$2"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
err "Unknown downloader" # should not reach here
|
||||
fi
|
||||
}
|
||||
|
||||
check_help_for() {
|
||||
local _arch
|
||||
local _cmd
|
||||
local _arg
|
||||
_arch="$1"
|
||||
shift
|
||||
_cmd="$1"
|
||||
shift
|
||||
|
||||
case "$_arch" in
|
||||
# If we're running on OS-X, older than 10.13, then we always
|
||||
# fail to find these options to force fallback
|
||||
*darwin*)
|
||||
if check_cmd sw_vers; then
|
||||
if [ "$(sw_vers -productVersion | cut -d. -f2)" -lt 13 ]; then
|
||||
# Older than 10.13
|
||||
echo "Warning: Detected OS X platform older than 10.13"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
for _arg in "$@"; do
|
||||
if ! "$_cmd" --help | grep -q -- "$_arg"; then
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
|
||||
true # not strictly needed
|
||||
}
|
||||
|
||||
# Return cipher suite string specified by user, otherwise return strong TLS 1.2-1.3 cipher suites
|
||||
# if support by local tools is detected. Detection currently supports these curl backends:
|
||||
# GnuTLS and OpenSSL (possibly also LibreSSL and BoringSSL). Return value can be empty.
|
||||
get_ciphersuites_for_curl() {
|
||||
if [ -n "${RUSTUP_TLS_CIPHERSUITES-}" ]; then
|
||||
# user specified custom cipher suites, assume they know what they're doing
|
||||
RETVAL="$RUSTUP_TLS_CIPHERSUITES"
|
||||
return
|
||||
fi
|
||||
|
||||
local _openssl_syntax="no"
|
||||
local _gnutls_syntax="no"
|
||||
local _backend_supported="yes"
|
||||
if curl -V | grep -q ' OpenSSL/'; then
|
||||
_openssl_syntax="yes"
|
||||
elif curl -V | grep -iq ' LibreSSL/'; then
|
||||
_openssl_syntax="yes"
|
||||
elif curl -V | grep -iq ' BoringSSL/'; then
|
||||
_openssl_syntax="yes"
|
||||
elif curl -V | grep -iq ' GnuTLS/'; then
|
||||
_gnutls_syntax="yes"
|
||||
else
|
||||
_backend_supported="no"
|
||||
fi
|
||||
|
||||
local _args_supported="no"
|
||||
if [ "$_backend_supported" = "yes" ]; then
|
||||
# "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc.
|
||||
if check_help_for "notspecified" "curl" "--tlsv1.2" "--ciphers" "--proto"; then
|
||||
_args_supported="yes"
|
||||
fi
|
||||
fi
|
||||
|
||||
local _cs=""
|
||||
if [ "$_args_supported" = "yes" ]; then
|
||||
if [ "$_openssl_syntax" = "yes" ]; then
|
||||
_cs=$(get_strong_ciphersuites_for "openssl")
|
||||
elif [ "$_gnutls_syntax" = "yes" ]; then
|
||||
_cs=$(get_strong_ciphersuites_for "gnutls")
|
||||
fi
|
||||
fi
|
||||
|
||||
RETVAL="$_cs"
|
||||
}
|
||||
|
||||
# Return cipher suite string specified by user, otherwise return strong TLS 1.2-1.3 cipher suites
|
||||
# if support by local tools is detected. Detection currently supports these wget backends:
|
||||
# GnuTLS and OpenSSL (possibly also LibreSSL and BoringSSL). Return value can be empty.
|
||||
get_ciphersuites_for_wget() {
|
||||
if [ -n "${RUSTUP_TLS_CIPHERSUITES-}" ]; then
|
||||
# user specified custom cipher suites, assume they know what they're doing
|
||||
RETVAL="$RUSTUP_TLS_CIPHERSUITES"
|
||||
return
|
||||
fi
|
||||
|
||||
local _cs=""
|
||||
if wget -V | grep -q '\-DHAVE_LIBSSL'; then
|
||||
# "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc.
|
||||
if check_help_for "notspecified" "wget" "TLSv1_2" "--ciphers" "--https-only" "--secure-protocol"; then
|
||||
_cs=$(get_strong_ciphersuites_for "openssl")
|
||||
fi
|
||||
elif wget -V | grep -q '\-DHAVE_LIBGNUTLS'; then
|
||||
# "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc.
|
||||
if check_help_for "notspecified" "wget" "TLSv1_2" "--ciphers" "--https-only" "--secure-protocol"; then
|
||||
_cs=$(get_strong_ciphersuites_for "gnutls")
|
||||
fi
|
||||
fi
|
||||
|
||||
RETVAL="$_cs"
|
||||
}
|
||||
|
||||
# Return strong TLS 1.2-1.3 cipher suites in OpenSSL or GnuTLS syntax. TLS 1.2
|
||||
# excludes non-ECDHE and non-AEAD cipher suites. DHE is excluded due to bad
|
||||
# DH params often found on servers (see RFC 7919). Sequence matches or is
|
||||
# similar to Firefox 68 ESR with weak cipher suites disabled via about:config.
|
||||
# $1 must be openssl or gnutls.
|
||||
get_strong_ciphersuites_for() {
|
||||
if [ "$1" = "openssl" ]; then
|
||||
# OpenSSL is forgiving of unknown values, no problems with TLS 1.3 values on versions that don't support it yet.
|
||||
echo "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384"
|
||||
elif [ "$1" = "gnutls" ]; then
|
||||
# GnuTLS isn't forgiving of unknown values, so this may require a GnuTLS version that supports TLS 1.3 even if wget doesn't.
|
||||
# Begin with SECURE128 (and higher) then remove/add to build cipher suites. Produces same 9 cipher suites as OpenSSL but in slightly different order.
|
||||
echo "SECURE128:-VERS-SSL3.0:-VERS-TLS1.0:-VERS-TLS1.1:-VERS-DTLS-ALL:-CIPHER-ALL:-MAC-ALL:-KX-ALL:+AEAD:+ECDHE-ECDSA:+ECDHE-RSA:+AES-128-GCM:+CHACHA20-POLY1305:+AES-256-GCM"
|
||||
fi
|
||||
}
|
||||
|
||||
main "$@" || exit 1
|
|
@ -157,7 +157,7 @@ if(LIBEVDEV_FOUND AND LIBUDEV_FOUND)
|
|||
)
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
if(UNIX OR WIN32)
|
||||
target_sources(inputcommon PRIVATE
|
||||
ControllerInterface/Pipes/Pipes.cpp
|
||||
ControllerInterface/Pipes/Pipes.h
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include <sstream>
|
||||
#include <string>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/FileUtil.h"
|
||||
|
@ -41,6 +40,31 @@ static double StringToDouble(const std::string& text)
|
|||
|
||||
void PopulateDevices()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
PIPE_FD pipes[4];
|
||||
// Windows has named pipes, but they're different. They don't exist on the
|
||||
// local filesystem and are transient. So rather than searching the /Pipes
|
||||
// directory for pipes, we just always assume there's 4 and then make them
|
||||
for (uint32_t i = 0; i < 4; i++)
|
||||
{
|
||||
std::string pipename = "\\\\.\\pipe\\slippibot" + std::to_string(i + 1);
|
||||
pipes[i] = CreateNamedPipeA(
|
||||
pipename.data(), // pipe name
|
||||
PIPE_ACCESS_INBOUND, // read access, inward only
|
||||
PIPE_TYPE_BYTE | PIPE_NOWAIT, // byte mode, nonblocking
|
||||
1, // number of clients
|
||||
256, // output buffer size
|
||||
256, // input buffer size
|
||||
0, // timeout value
|
||||
NULL // security attributes
|
||||
);
|
||||
|
||||
// We're in nonblocking mode, so this won't wait for clients
|
||||
ConnectNamedPipe(pipes[i], NULL);
|
||||
std::string ui_pipe_name = "slippibot" + std::to_string(i + 1);
|
||||
g_controller_interface.AddDevice(std::make_shared<PipeDevice>(pipes[i], ui_pipe_name));
|
||||
}
|
||||
#else
|
||||
// Search the Pipes directory for files that we can open in read-only,
|
||||
// non-blocking mode. The device name is the virtual name of the file.
|
||||
File::FSTEntry fst;
|
||||
|
@ -55,14 +79,15 @@ void PopulateDevices()
|
|||
const File::FSTEntry& child = fst.children[i];
|
||||
if (child.isDirectory)
|
||||
continue;
|
||||
int fd = open(child.physicalName.c_str(), O_RDONLY | O_NONBLOCK);
|
||||
PIPE_FD fd = open(child.physicalName.c_str(), O_RDONLY | O_NONBLOCK);
|
||||
if (fd < 0)
|
||||
continue;
|
||||
g_controller_interface.AddDevice(std::make_shared<PipeDevice>(fd, child.virtualName));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
PipeDevice::PipeDevice(int fd, const std::string& name) : m_fd(fd), m_name(name)
|
||||
PipeDevice::PipeDevice(PIPE_FD fd, const std::string& name) : m_fd(fd), m_name(name)
|
||||
{
|
||||
for (const auto& tok : s_button_tokens)
|
||||
{
|
||||
|
@ -83,7 +108,52 @@ PipeDevice::PipeDevice(int fd, const std::string& name) : m_fd(fd), m_name(name)
|
|||
|
||||
PipeDevice::~PipeDevice()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
CloseHandle(m_fd);
|
||||
#else
|
||||
close(m_fd);
|
||||
#endif
|
||||
}
|
||||
|
||||
s32 PipeDevice::readFromPipe(PIPE_FD file_descriptor, char* in_buffer, size_t size)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
|
||||
u32 bytes_available = 0;
|
||||
DWORD bytesread = 0;
|
||||
bool peek_success = PeekNamedPipe(
|
||||
file_descriptor,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
(LPDWORD)&bytes_available,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (!peek_success && (GetLastError() == ERROR_BROKEN_PIPE))
|
||||
{
|
||||
DisconnectNamedPipe(file_descriptor);
|
||||
ConnectNamedPipe(file_descriptor, NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (peek_success && (bytes_available > 0))
|
||||
{
|
||||
bool success = ReadFile(
|
||||
file_descriptor, // pipe handle
|
||||
in_buffer, // buffer to receive reply
|
||||
(DWORD)std::min(bytes_available, (u32)size), // size of buffer
|
||||
&bytesread, // number of bytes read
|
||||
NULL); // not overlapped
|
||||
if (!success)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return (s32)bytesread;
|
||||
#else
|
||||
return read(file_descriptor, in_buffer, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
void PipeDevice::UpdateInput()
|
||||
|
@ -91,11 +161,11 @@ void PipeDevice::UpdateInput()
|
|||
// Read any pending characters off the pipe. If we hit a newline,
|
||||
// then dequeue a command off the front of m_buf and parse it.
|
||||
char buf[32];
|
||||
ssize_t bytes_read = read(m_fd, buf, sizeof buf);
|
||||
s32 bytes_read = readFromPipe(m_fd, buf, sizeof buf);
|
||||
while (bytes_read > 0)
|
||||
{
|
||||
m_buf.append(buf, bytes_read);
|
||||
bytes_read = read(m_fd, buf, sizeof buf);
|
||||
bytes_read = readFromPipe(m_fd, buf, sizeof buf);
|
||||
}
|
||||
std::size_t newline = m_buf.find("\n");
|
||||
while (newline != std::string::npos)
|
||||
|
|
|
@ -7,9 +7,19 @@
|
|||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
namespace ciface::Pipes
|
||||
{
|
||||
#ifdef _WIN32
|
||||
typedef HANDLE PIPE_FD;
|
||||
#else
|
||||
typedef int PIPE_FD;
|
||||
#endif
|
||||
// To create a piped controller input, create a named pipe in the
|
||||
// Pipes directory and write commands out to it. Commands are separated
|
||||
// by a newline character, with spaces separating command tokens.
|
||||
|
@ -25,7 +35,7 @@ void PopulateDevices();
|
|||
class PipeDevice : public Core::Device
|
||||
{
|
||||
public:
|
||||
PipeDevice(int fd, const std::string& name);
|
||||
PipeDevice(PIPE_FD fd, const std::string& name);
|
||||
~PipeDevice();
|
||||
|
||||
void UpdateInput() override;
|
||||
|
@ -49,8 +59,9 @@ private:
|
|||
void AddAxis(const std::string& name, double value);
|
||||
void ParseCommand(const std::string& command);
|
||||
void SetAxis(const std::string& entry, double value);
|
||||
s32 readFromPipe(PIPE_FD file_descriptor, char* in_buffer, size_t size);
|
||||
|
||||
const int m_fd;
|
||||
const PIPE_FD m_fd;
|
||||
const std::string m_name;
|
||||
std::string m_buf;
|
||||
std::map<std::string, PipeInput*> m_buttons;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue