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