diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
deleted file mode 100644
index a29c1ef..0000000
--- a/.github/workflows/build.yml
+++ /dev/null
@@ -1,41 +0,0 @@
-name: .NET Build
-
-on:
- workflow_dispatch:
-
-jobs:
- build:
- name: Build on ${{ matrix.os }}
- runs-on: ${{ matrix.os }}
- strategy:
- matrix:
- 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
- uses: actions/checkout@v4
-
- - name: Set up .NET
- uses: actions/setup-dotnet@v4
- with:
- dotnet-version: '8.x'
-
- - name: Restore dependencies
- run: dotnet restore
-
- - name: Build self-contained application
- 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@v4
- with:
- name: build-${{ matrix.runtime }}
- path: |
- **/bin/Release/net8.0/${{ matrix.runtime }}/publish/
diff --git a/.idea/.idea.SwitchSlidePresenter/.idea/workspace.xml b/.idea/.idea.SwitchSlidePresenter/.idea/workspace.xml
deleted file mode 100644
index 41f33f2..0000000
--- a/.idea/.idea.SwitchSlidePresenter/.idea/workspace.xml
+++ /dev/null
@@ -1,144 +0,0 @@
-
-
-
- SwitchSlidePresenter.csproj
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {
- "lastFilter": {
- "state": "OPEN",
- "assignee": "GerardGascon"
- }
-}
- {
- "selectedUrlAndAccountId": {
- "url": "https://github.com/GerardGascon/Switch-Slide-Presenter.git",
- "accountId": "0af66c52-cbb7-4844-ad24-01b5c5b9bee8"
- }
-}
-
-
-
-
-
-
-
-
-
- {
- "associatedIndex": 6
-}
-
-
-
-
-
-
-
-
-
- {
- "keyToString": {
- ".NET Project.SwitchSlidePresenter.executor": "Run",
- "Publish to folder.Publish ControllerSlidePresenter to folder.executor": "Run",
- "RunOnceActivity.ShowReadmeOnStart": "true",
- "git-widget-placeholder": "master",
- "node.js.detected.package.eslint": "true",
- "node.js.detected.package.tslint": "true",
- "node.js.selected.package.eslint": "(autodetect)",
- "node.js.selected.package.tslint": "(autodetect)",
- "nodejs_package_manager_path": "npm",
- "vue.rearranger.settings.migration": "true"
- },
- "keyToStringList": {
- "rider.external.source.directories": [
- "C:\\Users\\ggasc\\AppData\\Roaming\\JetBrains\\Rider2024.1\\resharper-host\\DecompilerCache",
- "C:\\Users\\ggasc\\AppData\\Roaming\\JetBrains\\Rider2024.1\\resharper-host\\SourcesCache",
- "C:\\Users\\ggasc\\AppData\\Local\\Symbols\\src"
- ]
- }
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1718404015037
-
-
- 1718404015037
-
-
-
-
- 1718408820801
-
-
-
- 1718408820801
-
-
-
- 1718408956240
-
-
-
- 1718408956240
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.run/Publish Linux-x64.run.xml b/.run/Publish Linux-x64.run.xml
deleted file mode 100644
index 24fa928..0000000
--- a/.run/Publish Linux-x64.run.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.run/Publish Windows-x64.run.xml b/.run/Publish Windows-x64.run.xml
deleted file mode 100644
index 78279af..0000000
--- a/.run/Publish Windows-x64.run.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/README.md b/README.md
deleted file mode 100644
index e3599a9..0000000
--- a/README.md
+++ /dev/null
@@ -1,41 +0,0 @@
-# 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))
diff --git a/SlidePresenter/ControllerSelector.cs b/SlidePresenter/ControllerSelector.cs
index 31e5dd8..8efff0f 100644
--- a/SlidePresenter/ControllerSelector.cs
+++ b/SlidePresenter/ControllerSelector.cs
@@ -1,33 +1,11 @@
-using ControllerSlidePresenter.GamepadReader;
-
-namespace ControllerSlidePresenter;
+namespace SwitchSlidePresenter;
public static class ControllerSelector {
- 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}");
+ Console.WriteLine("[1] - JoyCon");
+ Console.WriteLine("[2] - Wiimote");
- 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.");
@@ -37,11 +15,13 @@ public static class ControllerSelector {
Console.WriteLine("Invalid number.");
return null;
}
- if (id <= 0 || id >= Readers.Count) {
- Console.WriteLine("Invalid number");
- return null;
- }
- return id - 1;
+ return GetReader(id);
}
+
+ 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 2324e47..66a3144 100644
--- a/SlidePresenter/ControllerSlidePresenter.csproj
+++ b/SlidePresenter/ControllerSlidePresenter.csproj
@@ -5,31 +5,16 @@
net8.0
enable
enable
- win-x64;linux-x64
+ SwitchSlidePresenter
-
- $(DefineConstants);OS_WINDOWS
-
-
- $(DefineConstants);OS_LINUX
-
-
- $(DefineConstants);OS_MAC
-
-
-
- $(DefineConstants);JoyCon
- $(DefineConstants);Wiimote
-
-
-
-
+
+
-
+
diff --git a/SlidePresenter/GamepadReader/WiimoteRead.cs b/SlidePresenter/GamepadReader/WiimoteRead.cs
deleted file mode 100644
index 5918a2e..0000000
--- a/SlidePresenter/GamepadReader/WiimoteRead.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-#if Wiimote
-using WiimoteLib.NetCore;
-
-namespace ControllerSlidePresenter.GamepadReader;
-
-public class WiimoteRead : IGamepadReader {
- public event Action? NextSlide;
- public event Action? PrevSlide;
-
- public async Task Read() {
- Wiimote wiimote = new();
- wiimote.Connect();
-
- if (string.IsNullOrEmpty(wiimote.HIDDevicePath)) {
- Console.WriteLine("No controller. Please connect Wiimote via Bluetooth.");
- Console.WriteLine("Press any key to exit program.");
- Console.ReadKey();
- return;
- }
-
- wiimote.WiimoteChanged += WiimoteChanged;
-
- Console.WriteLine("Wiimote ready for presenting.");
- Console.WriteLine("Press Enter to exit program.");
- while (Console.ReadKey().Key != ConsoleKey.Enter) {
- await Task.Yield();
- }
- wiimote.Disconnect();
-
- Console.WriteLine();
- Console.WriteLine("Stopped.");
- await Task.CompletedTask;
- }
-
- private void WiimoteChanged(object? sender, WiimoteChangedEventArgs e) {
- if (PreviousPressed(e.WiimoteState.ButtonState)) {
- PrevSlide?.Invoke();
- }
- if (NextPressed(e.WiimoteState.ButtonState)) {
- NextSlide?.Invoke();
- }
- }
-
- private static bool PreviousPressed(ButtonState input) {
- return input.B || input.Left;
- }
- private static bool NextPressed(ButtonState input) {
- return input.A || input.Right;
- }
-}
-#endif
diff --git a/SlidePresenter/GamepadReader/IGamepadReader.cs b/SlidePresenter/IGamepadReader.cs
similarity index 69%
rename from SlidePresenter/GamepadReader/IGamepadReader.cs
rename to SlidePresenter/IGamepadReader.cs
index f3f0be5..2fbf258 100644
--- a/SlidePresenter/GamepadReader/IGamepadReader.cs
+++ b/SlidePresenter/IGamepadReader.cs
@@ -1,4 +1,4 @@
-namespace ControllerSlidePresenter.GamepadReader;
+namespace SwitchSlidePresenter;
public interface IGamepadReader {
public event Action NextSlide;
diff --git a/SlidePresenter/InputSender/IInputSender.cs b/SlidePresenter/InputSender/IInputSender.cs
deleted file mode 100644
index 461f08d..0000000
--- a/SlidePresenter/InputSender/IInputSender.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace ControllerSlidePresenter.InputSender;
-
-public interface IInputSender {
- void NextSlide();
- void PreviousSlide();
-}
\ No newline at end of file
diff --git a/SlidePresenter/InputSender/LinuxInputSender.cs b/SlidePresenter/InputSender/LinuxInputSender.cs
deleted file mode 100644
index 011061c..0000000
--- a/SlidePresenter/InputSender/LinuxInputSender.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-#if OS_LINUX
-using System.Diagnostics;
-
-namespace ControllerSlidePresenter.InputSender;
-
-public class LinuxInputSender : IInputSender {
- 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/InputSender/MacInputSender.cs b/SlidePresenter/InputSender/MacInputSender.cs
deleted file mode 100644
index 270704a..0000000
--- a/SlidePresenter/InputSender/MacInputSender.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-#if OS_MAC
-namespace ControllerSlidePresenter.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
deleted file mode 100644
index 3ecb477..0000000
--- a/SlidePresenter/InputSender/WindowsInputSender.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-#if OS_WINDOWS
-using System.Runtime.InteropServices;
-using Win32Api;
-
-namespace ControllerSlidePresenter.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)));
- }
-}
-#endif
\ No newline at end of file
diff --git a/SlidePresenter/GamepadReader/JoyConRead.cs b/SlidePresenter/JoyConRead.cs
similarity index 58%
rename from SlidePresenter/GamepadReader/JoyConRead.cs
rename to SlidePresenter/JoyConRead.cs
index 9459431..3eb2a94 100644
--- a/SlidePresenter/GamepadReader/JoyConRead.cs
+++ b/SlidePresenter/JoyConRead.cs
@@ -1,24 +1,22 @@
-#if JoyCon
-using System.Text;
+using System.Text;
using HidSharp;
-using HidSharp.Reports;
using wtf.cluster.JoyCon;
using wtf.cluster.JoyCon.ExtraData;
using wtf.cluster.JoyCon.InputData;
using wtf.cluster.JoyCon.InputReports;
-namespace ControllerSlidePresenter.GamepadReader;
+namespace SwitchSlidePresenter;
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;
HidDevice? device = GetHidDevice();
if (device == null) {
- Console.WriteLine("No controller. Please connect Joy-Con via Bluetooth.");
+ Console.WriteLine("No controller. Please connect Joy-Con or Pro controller via Bluetooth.");
Console.WriteLine("Press any key to exit program.");
Console.ReadKey();
return;
@@ -41,14 +39,11 @@ public class JoyConRead : IGamepadReader {
Console.WriteLine("JoyCon ready for presenting.");
Console.WriteLine("Press Enter to exit program.");
- while (Console.ReadKey().Key != ConsoleKey.Enter) {
- await Task.Yield();
- }
+ while (Console.ReadKey().Key != ConsoleKey.Enter) { }
joycon.Stop();
Console.WriteLine();
Console.WriteLine("Stopped.");
- await Task.CompletedTask;
}
private static async Task LogDeviceInfo(JoyCon joycon) {
@@ -64,42 +59,36 @@ 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;
- }
-
- 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;
+ if (OperatingSystem.IsWindows()) {
+ var nintendos = list.GetHidDevices(0x057e);
+ device = nintendos.FirstOrDefault();
+ } else {
+ var hidDevices = list.GetHidDevices();
+ foreach (var d in hidDevices) {
+ var rd = d.GetReportDescriptor();
+ if (rd != null) {
+ 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
+ ) {
+ device = d;
+ break;
+ }
+ }
+ }
}
return device;
}
@@ -125,5 +114,4 @@ public class JoyConRead : IGamepadReader {
private static bool NextPressed(ButtonsSimple input) {
return input.ZLorZR || input.Down;
}
-}
-#endif
+}
\ No newline at end of file
diff --git a/SlidePresenter/Linux.cs b/SlidePresenter/Linux.cs
deleted file mode 100644
index b13c885..0000000
--- a/SlidePresenter/Linux.cs
+++ /dev/null
@@ -1,55 +0,0 @@
-#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 53df152..9a8e12c 100644
--- a/SlidePresenter/Program.cs
+++ b/SlidePresenter/Program.cs
@@ -1,13 +1,6 @@
-using ControllerSlidePresenter.GamepadReader;
-
-namespace ControllerSlidePresenter {
+namespace SwitchSlidePresenter {
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.");
diff --git a/SlidePresenter/SlideSwitcher.cs b/SlidePresenter/SlideSwitcher.cs
index 3cd7c5d..d81adae 100644
--- a/SlidePresenter/SlideSwitcher.cs
+++ b/SlidePresenter/SlideSwitcher.cs
@@ -1,33 +1,65 @@
-using ControllerSlidePresenter.GamepadReader;
-using ControllerSlidePresenter.InputSender;
+using System.Runtime.InteropServices;
+using Win32Api;
-namespace ControllerSlidePresenter;
+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
+ 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 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;
}
- private void NextSlide() => _inputSender.NextSlide();
- private void PreviousSlide() => _inputSender.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)));
+ }
}
\ No newline at end of file
diff --git a/SlidePresenter/WiimoteRead.cs b/SlidePresenter/WiimoteRead.cs
new file mode 100644
index 0000000..7ab8dca
--- /dev/null
+++ b/SlidePresenter/WiimoteRead.cs
@@ -0,0 +1,58 @@
+using WiimoteLib.NetCore;
+
+namespace SwitchSlidePresenter;
+
+public class WiimoteRead : IGamepadReader {
+ public event Action NextSlide;
+ public event Action PrevSlide;
+
+ private const int RetryDelay = 1000;
+
+ public async Task Read() {
+ Wiimote wiimote = new();
+ while (string.IsNullOrEmpty(wiimote.HIDDevicePath)) {
+ wiimote.Connect();
+ if (string.IsNullOrEmpty(wiimote.HIDDevicePath)) {
+ Console.WriteLine("Wiimote connection failed, trying again...");
+ await Task.Delay(RetryDelay);
+ } else {
+ Console.WriteLine("Wiimote ready for presenting!");
+ }
+ }
+
+ ButtonState previousState = wiimote.WiimoteState.ButtonState;
+ while (true) {
+ if (PreviousPressed(wiimote.WiimoteState.ButtonState, previousState)) {
+ PrevSlide?.Invoke();
+ }
+ if (NextPressed(wiimote.WiimoteState.ButtonState, previousState)) {
+ NextSlide?.Invoke();
+ }
+ previousState = wiimote.WiimoteState.ButtonState;
+
+ await Task.Yield();
+
+ if (!Console.KeyAvailable || Console.ReadKey().Key != ConsoleKey.Enter)
+ continue;
+ wiimote.Disconnect();
+
+ Console.WriteLine();
+ Console.WriteLine("Stopped.");
+ break;
+ }
+ }
+
+ private static bool PreviousPressed(ButtonState input) {
+ return input.B || input.Left;
+ }
+ private static bool NextPressed(ButtonState input) {
+ return input.A || input.Right;
+ }
+
+ private static bool PreviousPressed(ButtonState input, ButtonState previousState) {
+ return PreviousPressed(input) && !PreviousPressed(previousState);
+ }
+ private static bool NextPressed(ButtonState input, ButtonState previousState) {
+ return NextPressed(input) && !NextPressed(previousState);
+ }
+}
\ No newline at end of file