From baf15cdb0f6a8c357fb573d7db6aea51b2b9f271 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Gerard=20Gasc=C3=B3n?=
<52170489+GerardGascon@users.noreply.github.com>
Date: Sat, 15 Jun 2024 01:47:00 +0200
Subject: [PATCH] feat: Added wiimote support and cleaned up the project
---
.../.idea/.gitignore | 0
.../.idea/.name | 1 +
.../.idea/encodings.xml | 0
.../.idea/git_toolbox_prj.xml | 0
.../.idea/indexLayout.xml | 0
.../.idea/vcs.xml | 0
ControllerSlidePresenter.sln | 22 +++++++
Program.cs | 10 ---
SlidePresenter/ControllerSelector.cs | 27 ++++++++
.../IGamepadReader.cs | 0
JoyConRead.cs => SlidePresenter/JoyConRead.cs | 3 -
SlidePresenter/Program.cs | 14 ++++
SlidePresenter/SlideSwitcher.cs | 65 +++++++++++++++++++
.../SwitchSlidePresenter.csproj | 5 ++
SlidePresenter/WiimoteRead.cs | 58 +++++++++++++++++
SlideSwitcher.cs | 26 --------
SwitchSlidePresenter.sln | 16 -----
Win32Api.cs | 14 ----
Win32Api/HardwareInput.cs | 10 +++
Win32Api/Input.cs | 9 +++
Win32Api/InputUnion.cs | 10 +++
Win32Api/KeyboardInput.cs | 12 ++++
Win32Api/MouseInput.cs | 13 ++++
Win32Api/Win32Api.cs | 8 +++
Win32Api/Win32Api.csproj | 9 +++
25 files changed, 263 insertions(+), 69 deletions(-)
rename .idea/{.idea.SwitchSlidePresenter => .idea.ControllerSlidePresenter}/.idea/.gitignore (100%)
create mode 100644 .idea/.idea.ControllerSlidePresenter/.idea/.name
rename .idea/{.idea.SwitchSlidePresenter => .idea.ControllerSlidePresenter}/.idea/encodings.xml (100%)
rename .idea/{.idea.SwitchSlidePresenter => .idea.ControllerSlidePresenter}/.idea/git_toolbox_prj.xml (100%)
rename .idea/{.idea.SwitchSlidePresenter => .idea.ControllerSlidePresenter}/.idea/indexLayout.xml (100%)
rename .idea/{.idea.SwitchSlidePresenter => .idea.ControllerSlidePresenter}/.idea/vcs.xml (100%)
create mode 100644 ControllerSlidePresenter.sln
delete mode 100644 Program.cs
create mode 100644 SlidePresenter/ControllerSelector.cs
rename GamepadReader.cs => SlidePresenter/IGamepadReader.cs (100%)
rename JoyConRead.cs => SlidePresenter/JoyConRead.cs (97%)
create mode 100644 SlidePresenter/Program.cs
create mode 100644 SlidePresenter/SlideSwitcher.cs
rename SwitchSlidePresenter.csproj => SlidePresenter/SwitchSlidePresenter.csproj (67%)
create mode 100644 SlidePresenter/WiimoteRead.cs
delete mode 100644 SlideSwitcher.cs
delete mode 100644 SwitchSlidePresenter.sln
delete mode 100644 Win32Api.cs
create mode 100644 Win32Api/HardwareInput.cs
create mode 100644 Win32Api/Input.cs
create mode 100644 Win32Api/InputUnion.cs
create mode 100644 Win32Api/KeyboardInput.cs
create mode 100644 Win32Api/MouseInput.cs
create mode 100644 Win32Api/Win32Api.cs
create mode 100644 Win32Api/Win32Api.csproj
diff --git a/.idea/.idea.SwitchSlidePresenter/.idea/.gitignore b/.idea/.idea.ControllerSlidePresenter/.idea/.gitignore
similarity index 100%
rename from .idea/.idea.SwitchSlidePresenter/.idea/.gitignore
rename to .idea/.idea.ControllerSlidePresenter/.idea/.gitignore
diff --git a/.idea/.idea.ControllerSlidePresenter/.idea/.name b/.idea/.idea.ControllerSlidePresenter/.idea/.name
new file mode 100644
index 0000000..ef9baeb
--- /dev/null
+++ b/.idea/.idea.ControllerSlidePresenter/.idea/.name
@@ -0,0 +1 @@
+ControllerSlidePresenter
\ No newline at end of file
diff --git a/.idea/.idea.SwitchSlidePresenter/.idea/encodings.xml b/.idea/.idea.ControllerSlidePresenter/.idea/encodings.xml
similarity index 100%
rename from .idea/.idea.SwitchSlidePresenter/.idea/encodings.xml
rename to .idea/.idea.ControllerSlidePresenter/.idea/encodings.xml
diff --git a/.idea/.idea.SwitchSlidePresenter/.idea/git_toolbox_prj.xml b/.idea/.idea.ControllerSlidePresenter/.idea/git_toolbox_prj.xml
similarity index 100%
rename from .idea/.idea.SwitchSlidePresenter/.idea/git_toolbox_prj.xml
rename to .idea/.idea.ControllerSlidePresenter/.idea/git_toolbox_prj.xml
diff --git a/.idea/.idea.SwitchSlidePresenter/.idea/indexLayout.xml b/.idea/.idea.ControllerSlidePresenter/.idea/indexLayout.xml
similarity index 100%
rename from .idea/.idea.SwitchSlidePresenter/.idea/indexLayout.xml
rename to .idea/.idea.ControllerSlidePresenter/.idea/indexLayout.xml
diff --git a/.idea/.idea.SwitchSlidePresenter/.idea/vcs.xml b/.idea/.idea.ControllerSlidePresenter/.idea/vcs.xml
similarity index 100%
rename from .idea/.idea.SwitchSlidePresenter/.idea/vcs.xml
rename to .idea/.idea.ControllerSlidePresenter/.idea/vcs.xml
diff --git a/ControllerSlidePresenter.sln b/ControllerSlidePresenter.sln
new file mode 100644
index 0000000..eb48f5c
--- /dev/null
+++ b/ControllerSlidePresenter.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SwitchSlidePresenter", "SlidePresenter\SwitchSlidePresenter.csproj", "{F9832F2F-C7CA-4725-8F70-0FF3F76C0A5D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Win32Api", "Win32Api\Win32Api.csproj", "{16DC83C8-381A-4CA7-9E45-2A9CBC7BF48A}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {F9832F2F-C7CA-4725-8F70-0FF3F76C0A5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F9832F2F-C7CA-4725-8F70-0FF3F76C0A5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F9832F2F-C7CA-4725-8F70-0FF3F76C0A5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F9832F2F-C7CA-4725-8F70-0FF3F76C0A5D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {16DC83C8-381A-4CA7-9E45-2A9CBC7BF48A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {16DC83C8-381A-4CA7-9E45-2A9CBC7BF48A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {16DC83C8-381A-4CA7-9E45-2A9CBC7BF48A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {16DC83C8-381A-4CA7-9E45-2A9CBC7BF48A}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/Program.cs b/Program.cs
deleted file mode 100644
index 99e227d..0000000
--- a/Program.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-namespace SwitchSlidePresenter {
- class Program {
- private static async Task Main() {
- IGamepadReader reader = new JoyConRead();
- SlideSwitcher switcher = new(reader);
- await reader.Read();
- switcher.Dispose();
- }
- }
-}
\ No newline at end of file
diff --git a/SlidePresenter/ControllerSelector.cs b/SlidePresenter/ControllerSelector.cs
new file mode 100644
index 0000000..8efff0f
--- /dev/null
+++ b/SlidePresenter/ControllerSelector.cs
@@ -0,0 +1,27 @@
+namespace SwitchSlidePresenter;
+
+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");
+
+ string? line = Console.ReadLine();
+ if (line == null) {
+ Console.WriteLine("Invalid input.");
+ return null;
+ }
+ if (!int.TryParse(line, out int id)) {
+ Console.WriteLine("Invalid number.");
+ return null;
+ }
+
+ 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/GamepadReader.cs b/SlidePresenter/IGamepadReader.cs
similarity index 100%
rename from GamepadReader.cs
rename to SlidePresenter/IGamepadReader.cs
diff --git a/JoyConRead.cs b/SlidePresenter/JoyConRead.cs
similarity index 97%
rename from JoyConRead.cs
rename to SlidePresenter/JoyConRead.cs
index 5496085..3eb2a94 100644
--- a/JoyConRead.cs
+++ b/SlidePresenter/JoyConRead.cs
@@ -1,12 +1,9 @@
using System.Text;
using HidSharp;
using wtf.cluster.JoyCon;
-using wtf.cluster.JoyCon.Calibration;
using wtf.cluster.JoyCon.ExtraData;
-using wtf.cluster.JoyCon.HomeLed;
using wtf.cluster.JoyCon.InputData;
using wtf.cluster.JoyCon.InputReports;
-using wtf.cluster.JoyCon.Rumble;
namespace SwitchSlidePresenter;
diff --git a/SlidePresenter/Program.cs b/SlidePresenter/Program.cs
new file mode 100644
index 0000000..9a8e12c
--- /dev/null
+++ b/SlidePresenter/Program.cs
@@ -0,0 +1,14 @@
+namespace SwitchSlidePresenter {
+ internal abstract class Program {
+ private static async Task Main() {
+ IGamepadReader? reader = ControllerSelector.GetReader();
+ if (reader == null) {
+ Console.WriteLine("Invalid Controller Selected.");
+ return;
+ }
+ SlideSwitcher switcher = new(reader);
+ await reader.Read();
+ switcher.Dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/SlidePresenter/SlideSwitcher.cs b/SlidePresenter/SlideSwitcher.cs
new file mode 100644
index 0000000..d81adae
--- /dev/null
+++ b/SlidePresenter/SlideSwitcher.cs
@@ -0,0 +1,65 @@
+using System.Runtime.InteropServices;
+using Win32Api;
+
+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;
+
+ public SlideSwitcher(IGamepadReader? reader) {
+ _reader = reader;
+ _reader.NextSlide += NextSlide;
+ _reader.PrevSlide += PreviousSlide;
+ }
+
+ public void Dispose() {
+ _reader.NextSlide -= NextSlide;
+ _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)));
+ }
+}
\ No newline at end of file
diff --git a/SwitchSlidePresenter.csproj b/SlidePresenter/SwitchSlidePresenter.csproj
similarity index 67%
rename from SwitchSlidePresenter.csproj
rename to SlidePresenter/SwitchSlidePresenter.csproj
index 21b392a..3e00c50 100644
--- a/SwitchSlidePresenter.csproj
+++ b/SlidePresenter/SwitchSlidePresenter.csproj
@@ -9,6 +9,11 @@
+
+
+
+
+
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
diff --git a/SlideSwitcher.cs b/SlideSwitcher.cs
deleted file mode 100644
index 645d039..0000000
--- a/SlideSwitcher.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-namespace SwitchSlidePresenter;
-
-public class SlideSwitcher : IDisposable {
- private readonly IGamepadReader _reader;
-
- public SlideSwitcher(IGamepadReader reader) {
- _reader = reader;
- _reader.NextSlide += NextSlide;
- _reader.PrevSlide += PreviousSlide;
- }
-
- public void Dispose() {
- _reader.NextSlide -= NextSlide;
- _reader.PrevSlide -= PreviousSlide;
- }
-
- private void NextSlide() {
- IntPtr handle = Win32Api.GetForegroundWindow();
- Win32Api.PostMessage(handle, Win32Api.WM_KEYDOWN, Win32Api.VK_NEXT, 0);
- }
-
- private void PreviousSlide() {
- IntPtr handle = Win32Api.GetForegroundWindow();
- Win32Api.PostMessage(handle, Win32Api.WM_KEYDOWN, Win32Api.VK_PRIOR, 0);
- }
-}
\ No newline at end of file
diff --git a/SwitchSlidePresenter.sln b/SwitchSlidePresenter.sln
deleted file mode 100644
index d5f8c1e..0000000
--- a/SwitchSlidePresenter.sln
+++ /dev/null
@@ -1,16 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SwitchSlidePresenter", "SwitchSlidePresenter.csproj", "{50CECFA5-3AC2-4F08-82F2-ED8C82993360}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {50CECFA5-3AC2-4F08-82F2-ED8C82993360}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {50CECFA5-3AC2-4F08-82F2-ED8C82993360}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {50CECFA5-3AC2-4F08-82F2-ED8C82993360}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {50CECFA5-3AC2-4F08-82F2-ED8C82993360}.Release|Any CPU.Build.0 = Release|Any CPU
- EndGlobalSection
-EndGlobal
diff --git a/Win32Api.cs b/Win32Api.cs
deleted file mode 100644
index e5f503c..0000000
--- a/Win32Api.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System.Runtime.InteropServices;
-
-namespace SwitchSlidePresenter;
-
-public static class Win32Api {
- public const UInt32 WM_KEYDOWN = 0x0100;
- public const int VK_NEXT = 0x22;
- public const int VK_PRIOR = 0x21;
-
- [DllImport("user32.dll")]
- public static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);
- [DllImport("user32.dll")]
- public static extern IntPtr GetForegroundWindow();
-}
\ No newline at end of file
diff --git a/Win32Api/HardwareInput.cs b/Win32Api/HardwareInput.cs
new file mode 100644
index 0000000..6df4733
--- /dev/null
+++ b/Win32Api/HardwareInput.cs
@@ -0,0 +1,10 @@
+using System.Runtime.InteropServices;
+
+namespace Win32Api;
+
+[StructLayout(LayoutKind.Sequential)]
+public struct HardwareInput {
+ public uint uMsg;
+ public ushort wParamL;
+ public ushort wParamH;
+}
\ No newline at end of file
diff --git a/Win32Api/Input.cs b/Win32Api/Input.cs
new file mode 100644
index 0000000..991c3da
--- /dev/null
+++ b/Win32Api/Input.cs
@@ -0,0 +1,9 @@
+using System.Runtime.InteropServices;
+
+namespace Win32Api;
+
+[StructLayout(LayoutKind.Sequential)]
+public struct Input {
+ public uint type;
+ public InputUnion u;
+}
\ No newline at end of file
diff --git a/Win32Api/InputUnion.cs b/Win32Api/InputUnion.cs
new file mode 100644
index 0000000..93bf663
--- /dev/null
+++ b/Win32Api/InputUnion.cs
@@ -0,0 +1,10 @@
+using System.Runtime.InteropServices;
+
+namespace Win32Api;
+
+[StructLayout(LayoutKind.Explicit)]
+public struct InputUnion {
+ [FieldOffset(0)] public MouseInput mi;
+ [FieldOffset(0)] public KeyboardInput ki;
+ [FieldOffset(0)] public HardwareInput hi;
+}
\ No newline at end of file
diff --git a/Win32Api/KeyboardInput.cs b/Win32Api/KeyboardInput.cs
new file mode 100644
index 0000000..0a28b48
--- /dev/null
+++ b/Win32Api/KeyboardInput.cs
@@ -0,0 +1,12 @@
+using System.Runtime.InteropServices;
+
+namespace Win32Api;
+
+[StructLayout(LayoutKind.Sequential)]
+public struct KeyboardInput {
+ public ushort wVk;
+ public ushort wScan;
+ public uint dwFlags;
+ public uint time;
+ public IntPtr dwExtraInfo;
+}
\ No newline at end of file
diff --git a/Win32Api/MouseInput.cs b/Win32Api/MouseInput.cs
new file mode 100644
index 0000000..47eaa35
--- /dev/null
+++ b/Win32Api/MouseInput.cs
@@ -0,0 +1,13 @@
+using System.Runtime.InteropServices;
+
+namespace Win32Api;
+
+[StructLayout(LayoutKind.Sequential)]
+public struct MouseInput {
+ public int dx;
+ public int dy;
+ public uint mouseData;
+ public uint dwFlags;
+ public uint time;
+ public IntPtr dwExtraInfo;
+}
\ No newline at end of file
diff --git a/Win32Api/Win32Api.cs b/Win32Api/Win32Api.cs
new file mode 100644
index 0000000..62e51fd
--- /dev/null
+++ b/Win32Api/Win32Api.cs
@@ -0,0 +1,8 @@
+using System.Runtime.InteropServices;
+
+namespace Win32Api;
+
+public static class Win32Api {
+ [DllImport("user32.dll", SetLastError = true)]
+ public static extern uint SendInput(uint nInputs, Input[] pInputs, int cbSize);
+}
\ No newline at end of file
diff --git a/Win32Api/Win32Api.csproj b/Win32Api/Win32Api.csproj
new file mode 100644
index 0000000..3a63532
--- /dev/null
+++ b/Win32Api/Win32Api.csproj
@@ -0,0 +1,9 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+
+