diff --git a/Data/Sys/Config/Profiles/GCPad/slippibot.ini b/Data/Sys/Config/Profiles/GCPad/slippibot.ini new file mode 100644 index 0000000000..5e1aaefbb8 --- /dev/null +++ b/Data/Sys/Config/Profiles/GCPad/slippibot.ini @@ -0,0 +1,29 @@ +[Profile] +device = Pipe/0/slippibot1 +buttons/a = Button A +buttons/b = Button B +buttons/x = Button X +buttons/y = Button Y +buttons/z = Button Z +buttons/l = Button L +buttons/r = Button R +main stick/up = Axis MAIN Y + +main stick/down = Axis MAIN Y - +main stick/left = Axis MAIN X - +main stick/right = Axis MAIN X + +triggers/l = Button L +triggers/r = Button R +main stick/modifier = Shift_L +main stick/modifier/range = 50.000000000000000 +d-pad/up = Button D_UP +d-pad/down = Button D_DOWN +d-pad/left = Button D_LEFT +d-pad/right = Button D_RIGHT +buttons/start = Button START +c-stick/up = Axis C Y + +c-stick/down = Axis C Y - +c-stick/left = Axis C X - +c-stick/right = Axis C X + +triggers/l-analog = Axis L -+ +triggers/r-analog = Axis R -+ +triggers/threshold = 95.000000000000000 diff --git a/Source/Core/InputCommon/ControllerInterface/Pipes/Pipes.cpp b/Source/Core/InputCommon/ControllerInterface/Pipes/Pipes.cpp index 6f09214f5b..16992f335c 100644 --- a/Source/Core/InputCommon/ControllerInterface/Pipes/Pipes.cpp +++ b/Source/Core/InputCommon/ControllerInterface/Pipes/Pipes.cpp @@ -11,7 +11,6 @@ #include #include #include -#include #include #include "Common/FileUtil.h" @@ -43,6 +42,32 @@ 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(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; @@ -57,14 +82,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(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) { @@ -85,7 +111,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() @@ -93,11 +164,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) diff --git a/Source/Core/InputCommon/ControllerInterface/Pipes/Pipes.h b/Source/Core/InputCommon/ControllerInterface/Pipes/Pipes.h index 3cb79fee39..5907026fe9 100644 --- a/Source/Core/InputCommon/ControllerInterface/Pipes/Pipes.h +++ b/Source/Core/InputCommon/ControllerInterface/Pipes/Pipes.h @@ -7,11 +7,22 @@ #include #include #include +#ifdef _WIN32 +#include +#else +#include +#endif namespace ciface { namespace 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. @@ -27,7 +38,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 +60,9 @@ class PipeDevice : public Core::Device 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 m_buttons; diff --git a/Source/Core/InputCommon/InputCommon.vcxproj b/Source/Core/InputCommon/InputCommon.vcxproj index 7423bdd6be..f9c8e8e0da 100644 --- a/Source/Core/InputCommon/InputCommon.vcxproj +++ b/Source/Core/InputCommon/InputCommon.vcxproj @@ -64,6 +64,7 @@ +