From 1e6f8c0b9f6ab6e46e712b6851faf17092d5b118 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerard=20Gasc=C3=B3n?= <52170489+GerardGascon@users.noreply.github.com> Date: Fri, 28 Jun 2024 14:23:17 +0200 Subject: [PATCH 01/16] refactor: extract input sender to an interface for multiple platform support --- .../.idea/workspace.xml | 4 ++ SlidePresenter/InputSender/IInputSender.cs | 6 +++ .../InputSender/WindowsInputSender.cs | 47 +++++++++++++++++ SlidePresenter/SlideSwitcher.cs | 51 ++----------------- 4 files changed, 61 insertions(+), 47 deletions(-) create mode 100644 SlidePresenter/InputSender/IInputSender.cs create mode 100644 SlidePresenter/InputSender/WindowsInputSender.cs diff --git a/.idea/.idea.SwitchSlidePresenter/.idea/workspace.xml b/.idea/.idea.SwitchSlidePresenter/.idea/workspace.xml index 6d4b518..41f33f2 100644 --- a/.idea/.idea.SwitchSlidePresenter/.idea/workspace.xml +++ b/.idea/.idea.SwitchSlidePresenter/.idea/workspace.xml @@ -37,11 +37,15 @@ + + { "associatedIndex": 6 } + diff --git a/SlidePresenter/InputSender/IInputSender.cs b/SlidePresenter/InputSender/IInputSender.cs new file mode 100644 index 0000000..e0bce4e --- /dev/null +++ b/SlidePresenter/InputSender/IInputSender.cs @@ -0,0 +1,6 @@ +namespace SwitchSlidePresenter.InputSender; + +public interface IInputSender { + void NextSlide(); + void PreviousSlide(); +} \ No newline at end of file diff --git a/SlidePresenter/InputSender/WindowsInputSender.cs b/SlidePresenter/InputSender/WindowsInputSender.cs new file mode 100644 index 0000000..bcde5ed --- /dev/null +++ b/SlidePresenter/InputSender/WindowsInputSender.cs @@ -0,0 +1,47 @@ +using System.Runtime.InteropServices; +using Win32Api; + +namespace SwitchSlidePresenter.InputSender; + +public class WindowsInputSender : IInputSender { + private const uint INPUT_KEYBOARD = 1; + private const ushort VK_NEXT = 0x22; + private const ushort VK_PRIOR = 0x21; + private const uint KEYEVENTF_KEYDOWN = 0x0000; + private const uint KEYEVENTF_KEYUP = 0x0002; + + public void NextSlide() => SimulateKeyPress(VK_NEXT); + public void PreviousSlide() => SimulateKeyPress(VK_PRIOR); + + private static void SimulateKeyPress(ushort keyCode) { + Input[] inputs = new Input[2]; + + inputs[0] = new Input { + type = INPUT_KEYBOARD, + u = new InputUnion { + ki = new KeyboardInput { + wVk = keyCode, + wScan = 0, + dwFlags = KEYEVENTF_KEYDOWN, + time = 0, + dwExtraInfo = IntPtr.Zero + } + } + }; + + inputs[1] = new Input { + type = INPUT_KEYBOARD, + u = new InputUnion { + ki = new KeyboardInput { + wVk = keyCode, + wScan = 0, + dwFlags = KEYEVENTF_KEYUP, + time = 0, + dwExtraInfo = IntPtr.Zero + } + } + }; + + Win32Api.Win32Api.SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(typeof(Input))); + } +} \ No newline at end of file diff --git a/SlidePresenter/SlideSwitcher.cs b/SlidePresenter/SlideSwitcher.cs index d81adae..004c51a 100644 --- a/SlidePresenter/SlideSwitcher.cs +++ b/SlidePresenter/SlideSwitcher.cs @@ -1,16 +1,10 @@ -using System.Runtime.InteropServices; -using Win32Api; +using SwitchSlidePresenter.InputSender; namespace SwitchSlidePresenter; public class SlideSwitcher : IDisposable { private readonly IGamepadReader? _reader; - - private const uint INPUT_KEYBOARD = 1; - private const ushort VK_NEXT = 0x22; - private const ushort VK_PRIOR = 0x21; - private const uint KEYEVENTF_KEYDOWN = 0x0000; - private const uint KEYEVENTF_KEYUP = 0x0002; + private readonly IInputSender _inputSender = new WindowsInputSender(); public SlideSwitcher(IGamepadReader? reader) { _reader = reader; @@ -23,43 +17,6 @@ public class SlideSwitcher : IDisposable { _reader.PrevSlide -= PreviousSlide; } - private static void NextSlide() { - SimulateKeyPress(VK_NEXT); - } - - private static void PreviousSlide() { - SimulateKeyPress(VK_PRIOR); - } - - private static void SimulateKeyPress(ushort keyCode) { - Input[] inputs = new Input[2]; - - inputs[0] = new Input { - type = INPUT_KEYBOARD, - u = new InputUnion { - ki = new KeyboardInput { - wVk = keyCode, - wScan = 0, - dwFlags = KEYEVENTF_KEYDOWN, - time = 0, - dwExtraInfo = IntPtr.Zero - } - } - }; - - inputs[1] = new Input { - type = INPUT_KEYBOARD, - u = new InputUnion { - ki = new KeyboardInput { - wVk = keyCode, - wScan = 0, - dwFlags = KEYEVENTF_KEYUP, - time = 0, - dwExtraInfo = IntPtr.Zero - } - } - }; - - Win32Api.Win32Api.SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(typeof(Input))); - } + private void NextSlide() => _inputSender.NextSlide(); + private void PreviousSlide() => _inputSender.PreviousSlide(); } \ No newline at end of file From 65d562ee74341605b2007fa38976d23c01ad721e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerard=20Gasc=C3=B3n?= <52170489+GerardGascon@users.noreply.github.com> Date: Fri, 28 Jun 2024 14:39:52 +0200 Subject: [PATCH 02/16] feat: added preprocessor directive for platform dependant compilation --- SlidePresenter/ControllerSlidePresenter.csproj | 12 +++++++++++- SlidePresenter/InputSender/LinuxInputSender.cs | 13 +++++++++++++ SlidePresenter/InputSender/MacInputSender.cs | 13 +++++++++++++ SlidePresenter/InputSender/WindowsInputSender.cs | 6 ++++-- SlidePresenter/SlideSwitcher.cs | 7 +++++++ 5 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 SlidePresenter/InputSender/LinuxInputSender.cs create mode 100644 SlidePresenter/InputSender/MacInputSender.cs diff --git a/SlidePresenter/ControllerSlidePresenter.csproj b/SlidePresenter/ControllerSlidePresenter.csproj index 66a3144..d6e90c1 100644 --- a/SlidePresenter/ControllerSlidePresenter.csproj +++ b/SlidePresenter/ControllerSlidePresenter.csproj @@ -8,13 +8,23 @@ SwitchSlidePresenter + + OS_WINDOWS + + + OS_LINUX + + + OS_MAC + + - + diff --git a/SlidePresenter/InputSender/LinuxInputSender.cs b/SlidePresenter/InputSender/LinuxInputSender.cs new file mode 100644 index 0000000..5f084eb --- /dev/null +++ b/SlidePresenter/InputSender/LinuxInputSender.cs @@ -0,0 +1,13 @@ +#if OS_LINUX +namespace SwitchSlidePresenter.InputSender; + +public class LinuxInputSender : IInputSender { + public void NextSlide() { + + } + + public void PreviousSlide() { + + } +} +#endif \ No newline at end of file diff --git a/SlidePresenter/InputSender/MacInputSender.cs b/SlidePresenter/InputSender/MacInputSender.cs new file mode 100644 index 0000000..32f8fb3 --- /dev/null +++ b/SlidePresenter/InputSender/MacInputSender.cs @@ -0,0 +1,13 @@ +#if OS_MAC +namespace SwitchSlidePresenter.InputSender; + +public class MacInputSender : IInputSender { + public void NextSlide() { + + } + + public void PreviousSlide() { + + } +} +#endif \ No newline at end of file diff --git a/SlidePresenter/InputSender/WindowsInputSender.cs b/SlidePresenter/InputSender/WindowsInputSender.cs index bcde5ed..233bd3c 100644 --- a/SlidePresenter/InputSender/WindowsInputSender.cs +++ b/SlidePresenter/InputSender/WindowsInputSender.cs @@ -1,4 +1,5 @@ -using System.Runtime.InteropServices; +#if OS_WINDOWS +using System.Runtime.InteropServices; using Win32Api; namespace SwitchSlidePresenter.InputSender; @@ -44,4 +45,5 @@ public class WindowsInputSender : IInputSender { Win32Api.Win32Api.SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(typeof(Input))); } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/SlidePresenter/SlideSwitcher.cs b/SlidePresenter/SlideSwitcher.cs index 004c51a..7c02e10 100644 --- a/SlidePresenter/SlideSwitcher.cs +++ b/SlidePresenter/SlideSwitcher.cs @@ -4,7 +4,14 @@ namespace SwitchSlidePresenter; public class SlideSwitcher : IDisposable { private readonly IGamepadReader? _reader; + +#if OS_WINDOWS private readonly IInputSender _inputSender = new WindowsInputSender(); +#elif OS_MAC + private readonly IInputSender _inputSender = new MacInputSender(); +#elif OS_LINUX + private readonly IInputSender _inputSender = new LinuxInputSender(); +#endif public SlideSwitcher(IGamepadReader? reader) { _reader = reader; From 72750c33881c61dc539e5c597b7a815c99e40d7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerard=20Gasc=C3=B3n?= <52170489+GerardGascon@users.noreply.github.com> Date: Fri, 28 Jun 2024 15:18:56 +0200 Subject: [PATCH 03/16] refactor: preprocessors for wiimote and joycon compilation --- SlidePresenter/ControllerSelector.cs | 44 ++++++++++++++----- .../ControllerSlidePresenter.csproj | 16 ++++--- .../{ => GamepadReader}/IGamepadReader.cs | 2 +- .../{ => GamepadReader}/JoyConRead.cs | 8 ++-- .../{ => GamepadReader}/WiimoteRead.cs | 8 ++-- SlidePresenter/InputSender/IInputSender.cs | 2 +- .../InputSender/LinuxInputSender.cs | 2 +- SlidePresenter/InputSender/MacInputSender.cs | 2 +- .../InputSender/WindowsInputSender.cs | 2 +- SlidePresenter/Program.cs | 4 +- SlidePresenter/SlideSwitcher.cs | 5 ++- 11 files changed, 63 insertions(+), 32 deletions(-) rename SlidePresenter/{ => GamepadReader}/IGamepadReader.cs (69%) rename SlidePresenter/{ => GamepadReader}/JoyConRead.cs (96%) rename SlidePresenter/{ => GamepadReader}/WiimoteRead.cs (92%) diff --git a/SlidePresenter/ControllerSelector.cs b/SlidePresenter/ControllerSelector.cs index 8efff0f..31e5dd8 100644 --- a/SlidePresenter/ControllerSelector.cs +++ b/SlidePresenter/ControllerSelector.cs @@ -1,11 +1,33 @@ -namespace SwitchSlidePresenter; +using ControllerSlidePresenter.GamepadReader; + +namespace ControllerSlidePresenter; public static class ControllerSelector { - public static IGamepadReader? GetReader() { - Console.WriteLine("Write a number to select controller type:"); - Console.WriteLine("[1] - JoyCon"); - Console.WriteLine("[2] - Wiimote"); + private static readonly List<(string name, IGamepadReader reader)> Readers = [ +#if JoyCon + ("JoyCon", new JoyConRead()), +#endif +#if Wiimote + ("Wiimote", new WiimoteRead()) +#endif + ]; + public static IGamepadReader? GetReader() { + if (Readers.Count == 1) + return Readers[0].reader; + + Console.WriteLine("Write a number to select controller type:"); + for (int i = 0; i < Readers.Count; i++) + Console.WriteLine($"[{i+1}] - {Readers[i].name}"); + + int? id = GetReaderIndex(); + if (id == null) + return null; + + return Readers[id.Value].reader; + } + + private static int? GetReaderIndex() { string? line = Console.ReadLine(); if (line == null) { Console.WriteLine("Invalid input."); @@ -15,13 +37,11 @@ public static class ControllerSelector { Console.WriteLine("Invalid number."); return null; } + if (id <= 0 || id >= Readers.Count) { + Console.WriteLine("Invalid number"); + return null; + } - return GetReader(id); + return id - 1; } - - private static IGamepadReader? GetReader(int id) => id switch { - 1 => new JoyConRead(), - 2 => new WiimoteRead(), - _ => null - }; } \ No newline at end of file diff --git a/SlidePresenter/ControllerSlidePresenter.csproj b/SlidePresenter/ControllerSlidePresenter.csproj index d6e90c1..1de9a6f 100644 --- a/SlidePresenter/ControllerSlidePresenter.csproj +++ b/SlidePresenter/ControllerSlidePresenter.csproj @@ -5,22 +5,26 @@ net8.0 enable enable - SwitchSlidePresenter - OS_WINDOWS + $(DefineConstants);OS_WINDOWS - OS_LINUX + $(DefineConstants);OS_LINUX - OS_MAC + $(DefineConstants);OS_MAC + + + + $(DefineConstants);JoyCon + $(DefineConstants);Wiimote - - + + diff --git a/SlidePresenter/IGamepadReader.cs b/SlidePresenter/GamepadReader/IGamepadReader.cs similarity index 69% rename from SlidePresenter/IGamepadReader.cs rename to SlidePresenter/GamepadReader/IGamepadReader.cs index 2fbf258..f3f0be5 100644 --- a/SlidePresenter/IGamepadReader.cs +++ b/SlidePresenter/GamepadReader/IGamepadReader.cs @@ -1,4 +1,4 @@ -namespace SwitchSlidePresenter; +namespace ControllerSlidePresenter.GamepadReader; public interface IGamepadReader { public event Action NextSlide; diff --git a/SlidePresenter/JoyConRead.cs b/SlidePresenter/GamepadReader/JoyConRead.cs similarity index 96% rename from SlidePresenter/JoyConRead.cs rename to SlidePresenter/GamepadReader/JoyConRead.cs index 09e750f..6b7b199 100644 --- a/SlidePresenter/JoyConRead.cs +++ b/SlidePresenter/GamepadReader/JoyConRead.cs @@ -1,11 +1,12 @@ -using System.Text; +#if JoyCon +using System.Text; using HidSharp; using wtf.cluster.JoyCon; using wtf.cluster.JoyCon.ExtraData; using wtf.cluster.JoyCon.InputData; using wtf.cluster.JoyCon.InputReports; -namespace SwitchSlidePresenter; +namespace ControllerSlidePresenter.GamepadReader; public class JoyConRead : IGamepadReader { public event Action NextSlide; @@ -89,4 +90,5 @@ public class JoyConRead : IGamepadReader { private static bool NextPressed(ButtonsSimple input) { return input.ZLorZR || input.Down; } -} \ No newline at end of file +} +#endif diff --git a/SlidePresenter/WiimoteRead.cs b/SlidePresenter/GamepadReader/WiimoteRead.cs similarity index 92% rename from SlidePresenter/WiimoteRead.cs rename to SlidePresenter/GamepadReader/WiimoteRead.cs index 1a25b90..8f45454 100644 --- a/SlidePresenter/WiimoteRead.cs +++ b/SlidePresenter/GamepadReader/WiimoteRead.cs @@ -1,6 +1,7 @@ -using WiimoteLib.NetCore; +#if Wiimote +using WiimoteLib.NetCore; -namespace SwitchSlidePresenter; +namespace ControllerSlidePresenter.GamepadReader; public class WiimoteRead : IGamepadReader { public event Action NextSlide; @@ -46,4 +47,5 @@ public class WiimoteRead : IGamepadReader { private static bool NextPressed(ButtonState input) { return input.A || input.Right; } -} \ No newline at end of file +} +#endif diff --git a/SlidePresenter/InputSender/IInputSender.cs b/SlidePresenter/InputSender/IInputSender.cs index e0bce4e..461f08d 100644 --- a/SlidePresenter/InputSender/IInputSender.cs +++ b/SlidePresenter/InputSender/IInputSender.cs @@ -1,4 +1,4 @@ -namespace SwitchSlidePresenter.InputSender; +namespace ControllerSlidePresenter.InputSender; public interface IInputSender { void NextSlide(); diff --git a/SlidePresenter/InputSender/LinuxInputSender.cs b/SlidePresenter/InputSender/LinuxInputSender.cs index 5f084eb..cda05c8 100644 --- a/SlidePresenter/InputSender/LinuxInputSender.cs +++ b/SlidePresenter/InputSender/LinuxInputSender.cs @@ -1,5 +1,5 @@ #if OS_LINUX -namespace SwitchSlidePresenter.InputSender; +namespace ControllerSlidePresenter.InputSender; public class LinuxInputSender : IInputSender { public void NextSlide() { diff --git a/SlidePresenter/InputSender/MacInputSender.cs b/SlidePresenter/InputSender/MacInputSender.cs index 32f8fb3..270704a 100644 --- a/SlidePresenter/InputSender/MacInputSender.cs +++ b/SlidePresenter/InputSender/MacInputSender.cs @@ -1,5 +1,5 @@ #if OS_MAC -namespace SwitchSlidePresenter.InputSender; +namespace ControllerSlidePresenter.InputSender; public class MacInputSender : IInputSender { public void NextSlide() { diff --git a/SlidePresenter/InputSender/WindowsInputSender.cs b/SlidePresenter/InputSender/WindowsInputSender.cs index 233bd3c..3ecb477 100644 --- a/SlidePresenter/InputSender/WindowsInputSender.cs +++ b/SlidePresenter/InputSender/WindowsInputSender.cs @@ -2,7 +2,7 @@ using System.Runtime.InteropServices; using Win32Api; -namespace SwitchSlidePresenter.InputSender; +namespace ControllerSlidePresenter.InputSender; public class WindowsInputSender : IInputSender { private const uint INPUT_KEYBOARD = 1; diff --git a/SlidePresenter/Program.cs b/SlidePresenter/Program.cs index 9a8e12c..a612818 100644 --- a/SlidePresenter/Program.cs +++ b/SlidePresenter/Program.cs @@ -1,4 +1,6 @@ -namespace SwitchSlidePresenter { +using ControllerSlidePresenter.GamepadReader; + +namespace ControllerSlidePresenter { internal abstract class Program { private static async Task Main() { IGamepadReader? reader = ControllerSelector.GetReader(); diff --git a/SlidePresenter/SlideSwitcher.cs b/SlidePresenter/SlideSwitcher.cs index 7c02e10..cd26bf0 100644 --- a/SlidePresenter/SlideSwitcher.cs +++ b/SlidePresenter/SlideSwitcher.cs @@ -1,6 +1,7 @@ -using SwitchSlidePresenter.InputSender; +using ControllerSlidePresenter.GamepadReader; +using ControllerSlidePresenter.InputSender; -namespace SwitchSlidePresenter; +namespace ControllerSlidePresenter; public class SlideSwitcher : IDisposable { private readonly IGamepadReader? _reader; From 04ebe3f60632da0df5c8525700214220b13a7935 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerard=20Gasc=C3=B3n?= <52170489+GerardGascon@users.noreply.github.com> Date: Fri, 28 Jun 2024 15:31:23 +0200 Subject: [PATCH 04/16] feat: added back non-windows joycon detection support --- SlidePresenter/GamepadReader/JoyConRead.cs | 37 +++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/SlidePresenter/GamepadReader/JoyConRead.cs b/SlidePresenter/GamepadReader/JoyConRead.cs index 6b7b199..f9b69fc 100644 --- a/SlidePresenter/GamepadReader/JoyConRead.cs +++ b/SlidePresenter/GamepadReader/JoyConRead.cs @@ -1,6 +1,7 @@ #if JoyCon using System.Text; using HidSharp; +using HidSharp.Reports; using wtf.cluster.JoyCon; using wtf.cluster.JoyCon.ExtraData; using wtf.cluster.JoyCon.InputData; @@ -63,10 +64,44 @@ public class JoyConRead : IGamepadReader { } private static HidDevice? GetHidDevice() { + return OperatingSystem.IsWindows() + ? GetWindowsHidDevice() + : GetNonWindowsHidDevice(); + } + + private static HidDevice? GetWindowsHidDevice() { DeviceList list = DeviceList.Local; IEnumerable? nintendos = list.GetHidDevices(0x057e); + HidDevice? device = nintendos.FirstOrDefault(); + return device; + } - return nintendos.FirstOrDefault(); + private static HidDevice? GetNonWindowsHidDevice() { + HidDevice? device = null; + DeviceList list = DeviceList.Local; + + IEnumerable? hidDevices = list.GetHidDevices(); + foreach (HidDevice d in hidDevices) + { + ReportDescriptor? rd = d.GetReportDescriptor(); + if (rd == null) continue; + if (rd.OutputReports.Count() != 4 + || rd.OutputReports.Count(r => r.ReportID == 0x01) != 1 + || rd.OutputReports.Count(r => r.ReportID == 0x10) != 1 + || rd.OutputReports.Count(r => r.ReportID == 0x11) != 1 + || rd.OutputReports.Count(r => r.ReportID == 0x12) != 1 + || rd.InputReports.Count() != 6 + || rd.InputReports.Count(r => r.ReportID == 0x21) != 1 + || rd.InputReports.Count(r => r.ReportID == 0x30) != 1 + || rd.InputReports.Count(r => r.ReportID == 0x31) != 1 + || rd.InputReports.Count(r => r.ReportID == 0x32) != 1 + || rd.InputReports.Count(r => r.ReportID == 0x33) != 1 + || rd.InputReports.Count(r => r.ReportID == 0x3F) != 1) continue; + + device = d; + break; + } + return device; } private Task OnJoyConOnReportReceived(JoyCon _, IJoyConReport input) { From d996ca0efb06a336107ae9fbc8c676e7c875fcfb Mon Sep 17 00:00:00 2001 From: geri Date: Sat, 29 Jun 2024 23:50:26 +0200 Subject: [PATCH 05/16] feat: linux support --- .../InputSender/LinuxInputSender.cs | 21 ++++++- SlidePresenter/Linux.cs | 55 +++++++++++++++++++ SlidePresenter/Program.cs | 5 ++ 3 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 SlidePresenter/Linux.cs diff --git a/SlidePresenter/InputSender/LinuxInputSender.cs b/SlidePresenter/InputSender/LinuxInputSender.cs index cda05c8..011061c 100644 --- a/SlidePresenter/InputSender/LinuxInputSender.cs +++ b/SlidePresenter/InputSender/LinuxInputSender.cs @@ -1,13 +1,32 @@ #if OS_LINUX +using System.Diagnostics; + namespace ControllerSlidePresenter.InputSender; public class LinuxInputSender : IInputSender { - public void NextSlide() { + private const string PageUp = "0xff55"; + private const string PageDown = "0xff56"; + public void NextSlide() { + SendKeys(PageDown); } public void PreviousSlide() { + SendKeys(PageUp); + } + private static void SendKeys(string keycode) { + Process proc = new() { + StartInfo = { + FileName = "xdotool", + Arguments = $"key {keycode}", + UseShellExecute = false, + RedirectStandardError = false, + RedirectStandardInput = false, + RedirectStandardOutput = false + } + }; + proc.Start(); } } #endif \ No newline at end of file diff --git a/SlidePresenter/Linux.cs b/SlidePresenter/Linux.cs new file mode 100644 index 0000000..b13c885 --- /dev/null +++ b/SlidePresenter/Linux.cs @@ -0,0 +1,55 @@ +#if OS_LINUX +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace ControllerSlidePresenter; + +public static class Linux { + public static bool CanRun() { + if (getuid() != 0) { + Console.WriteLine("On Linux you need tu run as 'sudo'"); + return false; + } + if (!IsXdoToolInstalled()) + return false; + + return true; + } + + private static bool IsXdoToolInstalled() { + string result = RunShellCommand("which xdotool"); + if (!string.IsNullOrEmpty(result)) + return true; + + Console.WriteLine("xdotool is not installed."); + return false; + } + + private static string RunShellCommand(string command) { + try { + ProcessStartInfo procStartInfo = new("bash", "-c \"" + command + "\"") { + RedirectStandardOutput = true, + UseShellExecute = false, + CreateNoWindow = true, + }; + + using Process process = new(); + process.StartInfo = procStartInfo; + process.Start(); + + string result = process.StandardOutput.ReadToEnd(); + process.WaitForExit(); + + return result.Trim(); + } + catch (Exception ex) { + Console.WriteLine("Error: " + ex.Message); + return string.Empty; + } + } + + + [DllImport("libc")] + private static extern uint getuid(); +} +#endif diff --git a/SlidePresenter/Program.cs b/SlidePresenter/Program.cs index a612818..53df152 100644 --- a/SlidePresenter/Program.cs +++ b/SlidePresenter/Program.cs @@ -3,6 +3,11 @@ namespace ControllerSlidePresenter { internal abstract class Program { private static async Task Main() { +#if OS_LINUX + if (!Linux.CanRun()) + return; +#endif + IGamepadReader? reader = ControllerSelector.GetReader(); if (reader == null) { Console.WriteLine("Invalid Controller Selected."); From d91916d785316236cc3ac3e81f7639e6acc5e2c8 Mon Sep 17 00:00:00 2001 From: geri Date: Sun, 30 Jun 2024 00:00:44 +0200 Subject: [PATCH 06/16] feat: rider publish templates added --- .run/Publish Linux-x64.run.xml | 6 ++++++ .run/Publish Windows-x64.run.xml | 6 ++++++ 2 files changed, 12 insertions(+) create mode 100644 .run/Publish Linux-x64.run.xml create mode 100644 .run/Publish Windows-x64.run.xml diff --git a/.run/Publish Linux-x64.run.xml b/.run/Publish Linux-x64.run.xml new file mode 100644 index 0000000..24fa928 --- /dev/null +++ b/.run/Publish Linux-x64.run.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.run/Publish Windows-x64.run.xml b/.run/Publish Windows-x64.run.xml new file mode 100644 index 0000000..35b8f45 --- /dev/null +++ b/.run/Publish Windows-x64.run.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file From e876fef15f4c004a313649f4c1ee2ed336607da5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerard=20Gasc=C3=B3n?= <52170489+GerardGascon@users.noreply.github.com> Date: Sun, 30 Jun 2024 00:13:21 +0200 Subject: [PATCH 07/16] Create build.yml --- .github/workflows/build.yml | 41 +++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..f7f6a04 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,41 @@ +name: .NET Build + +on: + workflow_dispatch: + +jobs: + build: + name: Build on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest] + include: + - os: ubuntu-latest + mono-version: 'latest' + runtime: 'linux-x64' + - os: windows-latest + vs-version: 'latest' + runtime: 'win-x64' + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up .NET + uses: actions/setup-dotnet@v3 + with: + dotnet-version: '8.x' + + - name: Restore dependencies + run: dotnet restore + + - name: Build self-contained application + run: dotnet publish --no-restore --configuration Release --self-contained -r ${{ matrix.runtime }} /p:PublishSingleFile=false + + - name: Upload build artifacts + uses: actions/upload-artifact@v3 + with: + name: self-contained-${{ matrix.runtime }} + path: | + **/bin/Release/net8.0/${{ matrix.runtime }}/publish/ From 0c34d1839c767f9083ff03eccea0bb6e25333df7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerard=20Gasc=C3=B3n?= <52170489+GerardGascon@users.noreply.github.com> Date: Sun, 30 Jun 2024 00:18:12 +0200 Subject: [PATCH 08/16] Update build.yml --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f7f6a04..9200d72 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -31,7 +31,7 @@ jobs: run: dotnet restore - name: Build self-contained application - run: dotnet publish --no-restore --configuration Release --self-contained -r ${{ matrix.runtime }} /p:PublishSingleFile=false + run: dotnet publish --no-restore --configuration Release --self-contained -r ${{ matrix.runtime }} - name: Upload build artifacts uses: actions/upload-artifact@v3 From 168ec1ab6a09d72539a37e6432adc01250f2e484 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerard=20Gasc=C3=B3n?= <52170489+GerardGascon@users.noreply.github.com> Date: Sun, 30 Jun 2024 00:19:40 +0200 Subject: [PATCH 09/16] Update build.yml --- .github/workflows/build.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9200d72..363b954 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,11 +9,8 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, windows-latest] + os: [windows-latest] include: - - os: ubuntu-latest - mono-version: 'latest' - runtime: 'linux-x64' - os: windows-latest vs-version: 'latest' runtime: 'win-x64' From 1df15a8ba34c62995adad27aad52abcbe8920b87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerard=20Gasc=C3=B3n?= <52170489+GerardGascon@users.noreply.github.com> Date: Sun, 30 Jun 2024 00:25:26 +0200 Subject: [PATCH 10/16] Update build.yml --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 363b954..f2cf013 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -28,11 +28,11 @@ jobs: run: dotnet restore - name: Build self-contained application - run: dotnet publish --no-restore --configuration Release --self-contained -r ${{ matrix.runtime }} + run: dotnet publish SlidePresenter/ControllerSlidePresenter.csproj --no-restore --configuration Release --self-contained -r ${{ matrix.runtime }} - name: Upload build artifacts uses: actions/upload-artifact@v3 with: - name: self-contained-${{ matrix.runtime }} + name: build-${{ matrix.runtime }} path: | **/bin/Release/net8.0/${{ matrix.runtime }}/publish/ From c329754f32d981d533195583459bb7e63960cb33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerard=20Gasc=C3=B3n?= <52170489+GerardGascon@users.noreply.github.com> Date: Sun, 30 Jun 2024 00:30:42 +0200 Subject: [PATCH 11/16] feat: added runtime identifiers to project --- SlidePresenter/ControllerSlidePresenter.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/SlidePresenter/ControllerSlidePresenter.csproj b/SlidePresenter/ControllerSlidePresenter.csproj index 1de9a6f..2324e47 100644 --- a/SlidePresenter/ControllerSlidePresenter.csproj +++ b/SlidePresenter/ControllerSlidePresenter.csproj @@ -5,6 +5,7 @@ net8.0 enable enable + win-x64;linux-x64 From 61124fefd7048a40681265c49e52881f28a15533 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerard=20Gasc=C3=B3n?= <52170489+GerardGascon@users.noreply.github.com> Date: Sun, 30 Jun 2024 00:37:35 +0200 Subject: [PATCH 12/16] feat: single file windows build config --- .run/Publish Windows-x64.run.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.run/Publish Windows-x64.run.xml b/.run/Publish Windows-x64.run.xml index 35b8f45..78279af 100644 --- a/.run/Publish Windows-x64.run.xml +++ b/.run/Publish Windows-x64.run.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file From 9e50cfbde762a58dea7c6eac50d8a45b615be128 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerard=20Gasc=C3=B3n?= <52170489+GerardGascon@users.noreply.github.com> Date: Sun, 30 Jun 2024 00:39:50 +0200 Subject: [PATCH 13/16] Update build.yml --- .github/workflows/build.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f2cf013..52d41ae 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,11 +9,14 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [windows-latest] + os: [windows-latest, ubuntu-latest] include: - os: windows-latest vs-version: 'latest' runtime: 'win-x64' + - os: ubuntu-latest + vs-version: 'latest' + runtime: 'linux-x64' steps: - name: Checkout code @@ -28,7 +31,7 @@ jobs: run: dotnet restore - name: Build self-contained application - run: dotnet publish SlidePresenter/ControllerSlidePresenter.csproj --no-restore --configuration Release --self-contained -r ${{ matrix.runtime }} + run: dotnet publish SlidePresenter/ControllerSlidePresenter.csproj --no-restore --configuration Release --self-contained -r ${{ matrix.runtime }} /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true - name: Upload build artifacts uses: actions/upload-artifact@v3 From 86eb2137a3e40c5fa8a26ea2c1720a31bd776261 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerard=20Gasc=C3=B3n?= <52170489+GerardGascon@users.noreply.github.com> Date: Sun, 30 Jun 2024 00:46:16 +0200 Subject: [PATCH 14/16] fix: build warnings --- SlidePresenter/GamepadReader/JoyConRead.cs | 4 ++-- SlidePresenter/GamepadReader/WiimoteRead.cs | 4 ++-- SlidePresenter/SlideSwitcher.cs | 3 +++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/SlidePresenter/GamepadReader/JoyConRead.cs b/SlidePresenter/GamepadReader/JoyConRead.cs index f9b69fc..9459431 100644 --- a/SlidePresenter/GamepadReader/JoyConRead.cs +++ b/SlidePresenter/GamepadReader/JoyConRead.cs @@ -10,8 +10,8 @@ using wtf.cluster.JoyCon.InputReports; namespace ControllerSlidePresenter.GamepadReader; public class JoyConRead : IGamepadReader { - public event Action NextSlide; - public event Action PrevSlide; + public event Action? NextSlide; + public event Action? PrevSlide; public async Task Read() { Console.OutputEncoding = Encoding.UTF8; diff --git a/SlidePresenter/GamepadReader/WiimoteRead.cs b/SlidePresenter/GamepadReader/WiimoteRead.cs index 8f45454..5918a2e 100644 --- a/SlidePresenter/GamepadReader/WiimoteRead.cs +++ b/SlidePresenter/GamepadReader/WiimoteRead.cs @@ -4,8 +4,8 @@ using WiimoteLib.NetCore; namespace ControllerSlidePresenter.GamepadReader; public class WiimoteRead : IGamepadReader { - public event Action NextSlide; - public event Action PrevSlide; + public event Action? NextSlide; + public event Action? PrevSlide; public async Task Read() { Wiimote wiimote = new(); diff --git a/SlidePresenter/SlideSwitcher.cs b/SlidePresenter/SlideSwitcher.cs index cd26bf0..3cd7c5d 100644 --- a/SlidePresenter/SlideSwitcher.cs +++ b/SlidePresenter/SlideSwitcher.cs @@ -16,11 +16,14 @@ public class SlideSwitcher : IDisposable { public SlideSwitcher(IGamepadReader? reader) { _reader = reader; + if (_reader == null) return; + _reader.NextSlide += NextSlide; _reader.PrevSlide += PreviousSlide; } public void Dispose() { + if (_reader == null) return; _reader.NextSlide -= NextSlide; _reader.PrevSlide -= PreviousSlide; } From ec459f846f5528928c790055e997108e2597a1e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerard=20Gasc=C3=B3n?= <52170489+GerardGascon@users.noreply.github.com> Date: Sun, 30 Jun 2024 00:52:40 +0200 Subject: [PATCH 15/16] update actions to v4 --- .github/workflows/build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 52d41ae..a29c1ef 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,10 +20,10 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: dotnet-version: '8.x' @@ -34,7 +34,7 @@ jobs: run: dotnet publish SlidePresenter/ControllerSlidePresenter.csproj --no-restore --configuration Release --self-contained -r ${{ matrix.runtime }} /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true - name: Upload build artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: build-${{ matrix.runtime }} path: | From 9513da302c807c8bd923f33d299bf0527b9ee556 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerard=20Gasc=C3=B3n?= <52170489+GerardGascon@users.noreply.github.com> Date: Tue, 9 Jul 2024 00:30:59 +0200 Subject: [PATCH 16/16] Create README.md --- README.md | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..e3599a9 --- /dev/null +++ b/README.md @@ -0,0 +1,41 @@ +# Controller Slide Presenter + +A small tool to emulate a Slide Presenter using a Wiimote or a Joy-Con. + +## Controls + +### Wiimote + +- A or Right - Next Slide +- B or Left - Previous Slide + +### Joy-Con + +- A or ZL/ZR - Next Slide +- B or L/R - Previous Slide + +## Platform Support + +### Windows + +For the Joy-Con you just need to connect it via Bluetooth and then run the program. + +For the Wiimote you may need to connect it using Dolphin Emulator and then just run the program. + +**WARNING:** It's possible that Steam tries reading the Joy-Con in the background and keeps it from working. + +### Linux + +**Prerequisite:** You need [xdotool](https://github.com/jordansissel/xdotool) installed in order to redirect the input. + +At the moment there's only Joy-Con support, so connect it via Bluetooth and run the program. + +### MacOS + +At the moment there's no MacOS support as I don't have a computer to test, but feel free to submit a Pull Request adding that feature, the Joy-Con reading should work just fine, only the input redirection is needed. + +## Packages used + +**JoyCon.NET** - ([GitHub](https://github.com/ClusterM/joycon)) ([NuGet](https://www.nuget.org/packages/JoyCon.NET)) + +**WiimoteLib.NetCore** - ([GitHub](https://github.com/BrianPeek/WiimoteLib)) ([NuGet](https://www.nuget.org/packages/WiimoteLib.NetCore))