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))