Compare commits
17 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
9513da302c | ||
![]() |
ec459f846f | ||
![]() |
0ea469cb2b | ||
![]() |
86eb2137a3 | ||
![]() |
9e50cfbde7 | ||
![]() |
61124fefd7 | ||
![]() |
c329754f32 | ||
![]() |
1df15a8ba3 | ||
![]() |
168ec1ab6a | ||
![]() |
0c34d1839c | ||
![]() |
e876fef15f | ||
d91916d785 | |||
d996ca0efb | |||
![]() |
04ebe3f606 | ||
![]() |
72750c3388 | ||
![]() |
65d562ee74 | ||
![]() |
1e6f8c0b9f |
17 changed files with 378 additions and 76 deletions
41
.github/workflows/build.yml
vendored
Normal file
41
.github/workflows/build.yml
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
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/
|
|
@ -37,11 +37,15 @@
|
|||
<setting file="file://$PROJECT_DIR$/SlidePresenter/Program.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
</component>
|
||||
<component name="MetaFilesCheckinStateConfiguration" checkMetaFiles="true" />
|
||||
<component name="ProblemsViewState">
|
||||
<option name="selectedTabId" value="Toolset" />
|
||||
</component>
|
||||
<component name="ProjectColorInfo">{
|
||||
"associatedIndex": 6
|
||||
}</component>
|
||||
<component name="ProjectId" id="2htCW7BWCLo4IJC4dn1HIEGkg1I" />
|
||||
<component name="ProjectLevelVcsManager" settingsEditedManually="true">
|
||||
<OptionsSetting value="false" id="Update" />
|
||||
<ConfirmationsSetting value="2" id="Add" />
|
||||
</component>
|
||||
<component name="ProjectViewState">
|
||||
|
|
6
.run/Publish Linux-x64.run.xml
Normal file
6
.run/Publish Linux-x64.run.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Publish Linux-x64" type="DotNetFolderPublish" factoryName="Publish to folder">
|
||||
<riderPublish configuration="Release" platform="Any CPU" runtime="linux-x64" self_contained="true" target_folder="$PROJECT_DIR$/SlidePresenter/bin/Release/net8.0/linux-x64/publish" target_framework="net8.0" uuid_high="-467478054054508763" uuid_low="-8110965388391740835" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
6
.run/Publish Windows-x64.run.xml
Normal file
6
.run/Publish Windows-x64.run.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Publish Windows-x64" type="DotNetFolderPublish" factoryName="Publish to folder">
|
||||
<riderPublish configuration="Release" include_native_libs_for_self_extract="true" platform="Any CPU" produce_single_file="true" runtime="win-x64" self_contained="true" target_folder="$PROJECT_DIR$/SlidePresenter/bin/Release/net8.0/win-x64/publish" target_framework="net8.0" uuid_high="-467478054054508763" uuid_low="-8110965388391740835" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
41
README.md
Normal file
41
README.md
Normal file
|
@ -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))
|
|
@ -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
|
||||
};
|
||||
}
|
|
@ -5,16 +5,31 @@
|
|||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>SwitchSlidePresenter</RootNamespace>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="$([MSBuild]::IsOSPlatform('Windows'))">
|
||||
<DefineConstants>$(DefineConstants);OS_WINDOWS</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="$([MSBuild]::IsOSPlatform('Linux'))">
|
||||
<DefineConstants>$(DefineConstants);OS_LINUX</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="$([MSBuild]::IsOSPlatform('OSX'))">
|
||||
<DefineConstants>$(DefineConstants);OS_MAC</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<DefineConstants>$(DefineConstants);JoyCon</DefineConstants>
|
||||
<DefineConstants>$(DefineConstants);Wiimote</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="JoyCon.NET" Version="1.0.1" />
|
||||
<PackageReference Include="WiimoteLib.NetCore" Version="1.0.0" />
|
||||
<PackageReference Include="JoyCon.NET" Version="1.0.1" Condition="$(DefineConstants.Contains(JoyCon))" />
|
||||
<PackageReference Include="WiimoteLib.NetCore" Version="1.0.0" Condition="$(DefineConstants.Contains(Wiimote))" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Win32Api\Win32Api.csproj" />
|
||||
<ProjectReference Include="..\Win32Api\Win32Api.csproj" Condition="$([MSBuild]::IsOSPlatform('Windows'))"/>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace SwitchSlidePresenter;
|
||||
namespace ControllerSlidePresenter.GamepadReader;
|
||||
|
||||
public interface IGamepadReader {
|
||||
public event Action NextSlide;
|
|
@ -1,15 +1,17 @@
|
|||
using System.Text;
|
||||
#if JoyCon
|
||||
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 SwitchSlidePresenter;
|
||||
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;
|
||||
|
@ -62,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<HidDevice>? 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<HidDevice>? 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) {
|
||||
|
@ -90,3 +126,4 @@ public class JoyConRead : IGamepadReader {
|
|||
return input.ZLorZR || input.Down;
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -1,10 +1,11 @@
|
|||
using WiimoteLib.NetCore;
|
||||
#if Wiimote
|
||||
using WiimoteLib.NetCore;
|
||||
|
||||
namespace SwitchSlidePresenter;
|
||||
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();
|
||||
|
@ -47,3 +48,4 @@ public class WiimoteRead : IGamepadReader {
|
|||
return input.A || input.Right;
|
||||
}
|
||||
}
|
||||
#endif
|
6
SlidePresenter/InputSender/IInputSender.cs
Normal file
6
SlidePresenter/InputSender/IInputSender.cs
Normal file
|
@ -0,0 +1,6 @@
|
|||
namespace ControllerSlidePresenter.InputSender;
|
||||
|
||||
public interface IInputSender {
|
||||
void NextSlide();
|
||||
void PreviousSlide();
|
||||
}
|
32
SlidePresenter/InputSender/LinuxInputSender.cs
Normal file
32
SlidePresenter/InputSender/LinuxInputSender.cs
Normal file
|
@ -0,0 +1,32 @@
|
|||
#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
|
13
SlidePresenter/InputSender/MacInputSender.cs
Normal file
13
SlidePresenter/InputSender/MacInputSender.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
#if OS_MAC
|
||||
namespace ControllerSlidePresenter.InputSender;
|
||||
|
||||
public class MacInputSender : IInputSender {
|
||||
public void NextSlide() {
|
||||
|
||||
}
|
||||
|
||||
public void PreviousSlide() {
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
49
SlidePresenter/InputSender/WindowsInputSender.cs
Normal file
49
SlidePresenter/InputSender/WindowsInputSender.cs
Normal file
|
@ -0,0 +1,49 @@
|
|||
#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
|
55
SlidePresenter/Linux.cs
Normal file
55
SlidePresenter/Linux.cs
Normal file
|
@ -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
|
|
@ -1,6 +1,13 @@
|
|||
namespace SwitchSlidePresenter {
|
||||
using ControllerSlidePresenter.GamepadReader;
|
||||
|
||||
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.");
|
||||
|
|
|
@ -1,65 +1,33 @@
|
|||
using System.Runtime.InteropServices;
|
||||
using Win32Api;
|
||||
using ControllerSlidePresenter.GamepadReader;
|
||||
using ControllerSlidePresenter.InputSender;
|
||||
|
||||
namespace SwitchSlidePresenter;
|
||||
namespace ControllerSlidePresenter;
|
||||
|
||||
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;
|
||||
#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;
|
||||
if (_reader == null) return;
|
||||
|
||||
_reader.NextSlide += NextSlide;
|
||||
_reader.PrevSlide += PreviousSlide;
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
if (_reader == null) return;
|
||||
_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)));
|
||||
}
|
||||
private void NextSlide() => _inputSender.NextSlide();
|
||||
private void PreviousSlide() => _inputSender.PreviousSlide();
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue