feat: Added wiimote support and cleaned up the project
This commit is contained in:
parent
36574bdf46
commit
baf15cdb0f
25 changed files with 263 additions and 69 deletions
1
.idea/.idea.ControllerSlidePresenter/.idea/.name
generated
Normal file
1
.idea/.idea.ControllerSlidePresenter/.idea/.name
generated
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ControllerSlidePresenter
|
22
ControllerSlidePresenter.sln
Normal file
22
ControllerSlidePresenter.sln
Normal file
|
@ -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
|
10
Program.cs
10
Program.cs
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
27
SlidePresenter/ControllerSelector.cs
Normal file
27
SlidePresenter/ControllerSelector.cs
Normal file
|
@ -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
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,12 +1,9 @@
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using HidSharp;
|
using HidSharp;
|
||||||
using wtf.cluster.JoyCon;
|
using wtf.cluster.JoyCon;
|
||||||
using wtf.cluster.JoyCon.Calibration;
|
|
||||||
using wtf.cluster.JoyCon.ExtraData;
|
using wtf.cluster.JoyCon.ExtraData;
|
||||||
using wtf.cluster.JoyCon.HomeLed;
|
|
||||||
using wtf.cluster.JoyCon.InputData;
|
using wtf.cluster.JoyCon.InputData;
|
||||||
using wtf.cluster.JoyCon.InputReports;
|
using wtf.cluster.JoyCon.InputReports;
|
||||||
using wtf.cluster.JoyCon.Rumble;
|
|
||||||
|
|
||||||
namespace SwitchSlidePresenter;
|
namespace SwitchSlidePresenter;
|
||||||
|
|
14
SlidePresenter/Program.cs
Normal file
14
SlidePresenter/Program.cs
Normal file
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
65
SlidePresenter/SlideSwitcher.cs
Normal file
65
SlidePresenter/SlideSwitcher.cs
Normal file
|
@ -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)));
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,11 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="JoyCon.NET" Version="1.0.1" />
|
<PackageReference Include="JoyCon.NET" Version="1.0.1" />
|
||||||
|
<PackageReference Include="WiimoteLib.NetCore" Version="1.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Win32Api\Win32Api.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
58
SlidePresenter/WiimoteRead.cs
Normal file
58
SlidePresenter/WiimoteRead.cs
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
14
Win32Api.cs
14
Win32Api.cs
|
@ -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();
|
|
||||||
}
|
|
10
Win32Api/HardwareInput.cs
Normal file
10
Win32Api/HardwareInput.cs
Normal file
|
@ -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;
|
||||||
|
}
|
9
Win32Api/Input.cs
Normal file
9
Win32Api/Input.cs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Win32Api;
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct Input {
|
||||||
|
public uint type;
|
||||||
|
public InputUnion u;
|
||||||
|
}
|
10
Win32Api/InputUnion.cs
Normal file
10
Win32Api/InputUnion.cs
Normal file
|
@ -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;
|
||||||
|
}
|
12
Win32Api/KeyboardInput.cs
Normal file
12
Win32Api/KeyboardInput.cs
Normal file
|
@ -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;
|
||||||
|
}
|
13
Win32Api/MouseInput.cs
Normal file
13
Win32Api/MouseInput.cs
Normal file
|
@ -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;
|
||||||
|
}
|
8
Win32Api/Win32Api.cs
Normal file
8
Win32Api/Win32Api.cs
Normal file
|
@ -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);
|
||||||
|
}
|
9
Win32Api/Win32Api.csproj
Normal file
9
Win32Api/Win32Api.csproj
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
Loading…
Add table
Add a link
Reference in a new issue