diff --git a/.modules/Directory.Build.props b/.modules/Directory.Build.props new file mode 100644 index 0000000..c1df222 --- /dev/null +++ b/.modules/Directory.Build.props @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/.modules/Directory.Build.targets b/.modules/Directory.Build.targets new file mode 100644 index 0000000..c1df222 --- /dev/null +++ b/.modules/Directory.Build.targets @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/.modules/OpenTabletDriver b/.modules/OpenTabletDriver index 267a322..78e9d03 160000 --- a/.modules/OpenTabletDriver +++ b/.modules/OpenTabletDriver @@ -1 +1 @@ -Subproject commit 267a32282ad5462a5be254e74f60edeba809831f +Subproject commit 78e9d03766e61f986d3b510dfd3b23c74917d895 diff --git a/Binding/ScriptRunner/ScriptRunner.cs b/Binding/ScriptRunner/ScriptRunner.cs index 13eda4d..412b956 100644 --- a/Binding/ScriptRunner/ScriptRunner.cs +++ b/Binding/ScriptRunner/ScriptRunner.cs @@ -1,6 +1,5 @@ -using System.Collections.Generic; +using System; using System.Diagnostics; -using System.Linq; using OpenTabletDriver.Plugin; using OpenTabletDriver.Plugin.Attributes; using OpenTabletDriver.Plugin.Tablet; @@ -10,82 +9,8 @@ namespace VoiDPlugins.Binding.ScriptRunner [PluginName("Script Runner")] public class ScriptRunner : IStateBinding { - public static string[] ValidIndexes = Enumerable.Range(0, 10).Select(i => i.ToString()).ToArray(); - - private List ScriptPathList = new List(10); - - [Property("Script Index"), PropertyValidated(nameof(ValidIndexes))] - public string ScriptIndex { set; get; } - - [Property("Script Path 0")] - public string ScriptPath0 - { - get => ScriptPathList[0]; - set => ScriptPathList[0] = value; - } - - [Property("Script Path 1")] - public string ScriptPath1 - { - get => ScriptPathList[1]; - set => ScriptPathList[1] = value; - } - - [Property("Script Path 2")] - public string ScriptPath2 - { - get => ScriptPathList[2]; - set => ScriptPathList[2] = value; - } - - [Property("Script Path 3")] - public string ScriptPath3 - { - get => ScriptPathList[3]; - set => ScriptPathList[3] = value; - } - - [Property("Script Path 4")] - public string ScriptPath4 - { - get => ScriptPathList[4]; - set => ScriptPathList[4] = value; - } - - [Property("Script Path 5")] - public string ScriptPath5 - { - get => ScriptPathList[5]; - set => ScriptPathList[5] = value; - } - - [Property("Script Path 6")] - public string ScriptPath6 - { - get => ScriptPathList[6]; - set => ScriptPathList[6] = value; - } - - [Property("Script Path 7")] - public string ScriptPath7 - { - get => ScriptPathList[7]; - set => ScriptPathList[7] = value; - } - - [Property("Script Path 8")] - public string ScriptPath8 - { - get => ScriptPathList[8]; - set => ScriptPathList[8] = value; - } - - [Property("Script Path 9")] - public string ScriptPath9 - { - get => ScriptPathList[9]; - set => ScriptPathList[9] = value; - } + [Property("Run")] + public string? Script { get; set; } public void Press(TabletReference tablet, IDeviceReport report) { @@ -93,14 +18,17 @@ namespace VoiDPlugins.Binding.ScriptRunner { var process = new Process { - StartInfo = new ProcessStartInfo(ScriptPathList[int.Parse(ScriptIndex)]) + StartInfo = new ProcessStartInfo(Script!) { UseShellExecute = true } }; process.Start(); } - catch { } + catch (Exception e) + { + Log.Exception(e); + } } public void Release(TabletReference tablet, IDeviceReport report) diff --git a/Binding/ScriptRunner/ScriptRunner.csproj b/Binding/ScriptRunner/ScriptRunner.csproj index ef87223..bef0383 100644 --- a/Binding/ScriptRunner/ScriptRunner.csproj +++ b/Binding/ScriptRunner/ScriptRunner.csproj @@ -1,17 +1,2 @@  - - - net5 - - - - none - false - false - - - - - - diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 0000000..5bd4b75 --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,12 @@ + + + net6.0 + true + enable + 0.3.0 + + + + embedded + + \ No newline at end of file diff --git a/Directory.Build.targets b/Directory.Build.targets new file mode 100644 index 0000000..d6eb2cf --- /dev/null +++ b/Directory.Build.targets @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/Filter/MeL/Core/MLCore.cs b/Filter/MeL/Core/MLCore.cs index 2877ff4..cba45c1 100644 --- a/Filter/MeL/Core/MLCore.cs +++ b/Filter/MeL/Core/MLCore.cs @@ -1,3 +1,4 @@ +using System.Diagnostics; using System.Linq; using System.Numerics; using MathNet.Numerics; @@ -8,6 +9,28 @@ namespace VoiDPlugins.Filter.MeL.Core { internal partial class MLCore { + private double[]? weights; + private Polynomial? xCoeff, yCoeff; + private RingBuffer? timeSeriesPoints; + private readonly Stopwatch watch = new(); + + public bool IsReady { private set; get; } + + private int samples; + public int Samples + { + set + { + this.timeSeriesPoints = new RingBuffer(value); + this.samples = value; + } + get => this.samples; + } + + public int Complexity { set; get; } = 2; + public float Weight { set => this.weights = CalcWeight(value).ToArray(); } + public double TimeNow { get => watch.Elapsed.TotalMilliseconds; } + public MLCore() { Weight = 1.4f; @@ -49,29 +72,61 @@ namespace VoiDPlugins.Filter.MeL.Core { var predicted = new Vector2(); double predictAhead; - predictAhead = TimeNow - this.timeSeriesPoints[0].Elapsed + offset; + predictAhead = TimeNow - this.timeSeriesPoints![0].Elapsed + offset; - predicted.X = (float)this.xCoeff.Evaluate(predictAhead); - predicted.Y = (float)this.yCoeff.Evaluate(predictAhead); + predicted.X = (float)this.xCoeff!.Evaluate(predictAhead); + predicted.Y = (float)this.yCoeff!.Evaluate(predictAhead); return predicted; } - public bool IsReady { private set; get; } - - private int samples; - public int Samples + private bool AddTimeSeriesPoint(Vector2 point, double elapsed) { - set - { - this.timeSeriesPoints = new RingBuffer(value); - this.samples = value; - } - get => this.samples; + this.timeSeriesPoints!.Insert(new TimeSeriesPoint(point, elapsed)); + return this.timeSeriesPoints.IsFilled; } - public int Complexity { set; get; } = 2; - public float Weight { set => this.weights = CalcWeight(value).ToArray(); } - public double TimeNow { get => watch.Elapsed.TotalMilliseconds; } + private double[] ConstructTimeDesignMatrix() + { + var baseTime = this.timeSeriesPoints![0].Elapsed; + var data = new double[Samples]; + var index = 0; + foreach (var timePoint in this.timeSeriesPoints) + data[index++] = timePoint.Elapsed - baseTime; + + return data; + } + + private double[] ConstructTargetMatrix(Axis axis) + { + var points = new double[Samples]; + var index = 0; + + switch (axis) + { + case Axis.X: + foreach (var timePoint in timeSeriesPoints!) + points[index++] = timePoint.Point.X; + break; + case Axis.Y: + foreach (var timePoint in timeSeriesPoints!) + points[index++] = timePoint.Point.Y; + break; + } + + return points; + } + + private double[] CalcWeight(double ratio) + { + var weights = new double[Samples]; + var weightsNormalized = new double[Samples]; + double weight = 1; + for (int i = 0; i < Samples; i++) + weights[i] = weight *= ratio; + for (int i = 0; i < Samples; i++) + weightsNormalized[i] = weights[i] / weights[^1]; + return weightsNormalized; + } } } \ No newline at end of file diff --git a/Filter/MeL/Core/MLCorePriv.cs b/Filter/MeL/Core/MLCorePriv.cs deleted file mode 100644 index d76ba1f..0000000 --- a/Filter/MeL/Core/MLCorePriv.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System.Diagnostics; -using System.Numerics; -using MathNet.Numerics; -using VoiDPlugins.Library; - -namespace VoiDPlugins.Filter.MeL.Core -{ - internal partial class MLCore - { - private double[] weights; - private Polynomial xCoeff, yCoeff; - private RingBuffer timeSeriesPoints; - private readonly Stopwatch watch = new(); - - private bool AddTimeSeriesPoint(Vector2 point, double elapsed) - { - this.timeSeriesPoints.Insert(new TimeSeriesPoint(point, elapsed)); - return this.timeSeriesPoints.IsFilled; - } - - private double[] ConstructTimeDesignMatrix() - { - var baseTime = this.timeSeriesPoints[0].Elapsed; - var data = new double[Samples]; - var index = 0; - foreach (var timePoint in this.timeSeriesPoints) - data[index++] = timePoint.Elapsed - baseTime; - - return data; - } - - private double[] ConstructTargetMatrix(Axis axis) - { - var points = new double[Samples]; - var index = 0; - - switch (axis) - { - case Axis.X: - foreach (var timePoint in timeSeriesPoints) - points[index++] = timePoint.Point.X; - break; - case Axis.Y: - foreach (var timePoint in timeSeriesPoints) - points[index++] = timePoint.Point.Y; - break; - } - - return points; - } - - private double[] CalcWeight(double ratio) - { - var weights = new double[Samples]; - var weightsNormalized = new double[Samples]; - double weight = 1; - for (int i = 0; i < Samples; i++) - weights[i] = weight *= ratio; - for (int i = 0; i < Samples; i++) - weightsNormalized[i] = weights[i] / weights[^1]; - return weightsNormalized; - } - } -} \ No newline at end of file diff --git a/Filter/MeL/Filter/MeLFilter.cs b/Filter/MeL/Filter/MeLFilter.cs index fd9bc94..53c015e 100644 --- a/Filter/MeL/Filter/MeLFilter.cs +++ b/Filter/MeL/Filter/MeLFilter.cs @@ -10,10 +10,10 @@ namespace VoiDPlugins.Filter.MeL [PluginName("MeL Filter")] public class MeLFilter : IPositionedPipelineElement { - private readonly MLCore Core = new MLCore(); + private readonly MLCore Core = new(); private bool rateLimit; - public event Action Emit; + public event Action? Emit; public PipelinePosition Position => PipelinePosition.PostTransform; diff --git a/Filter/MeL/MeL.csproj b/Filter/MeL/MeL.csproj index a743c8f..bc942a5 100644 --- a/Filter/MeL/MeL.csproj +++ b/Filter/MeL/MeL.csproj @@ -1,19 +1,9 @@  - - net5 - - - - none - false - false + true - - - diff --git a/Filter/PrecisionControl/PrecisionControl.cs b/Filter/PrecisionControl/PrecisionControl.cs index 64189ae..de80474 100644 --- a/Filter/PrecisionControl/PrecisionControl.cs +++ b/Filter/PrecisionControl/PrecisionControl.cs @@ -17,7 +17,7 @@ namespace VoiDPlugins.Filter public static string[] ValidModes => new[] { "Toggle", "Hold" }; [Property("Mode"), PropertyValidated(nameof(ValidModes))] - public string Mode { set; get; } + public string? Mode { set; get; } public void Press(TabletReference tablet, IDeviceReport report) { @@ -39,7 +39,7 @@ namespace VoiDPlugins.Filter [PluginName("Precision Control")] public class PrecisionControl : IPositionedPipelineElement { - public event Action Emit; + public event Action? Emit; [SliderProperty("Precision Multiplier", 0.0f, 10f, 0.3f), DefaultPropertyValue(0.3f)] public float Scale { get; set; } diff --git a/Filter/PrecisionControl/PrecisionControl.csproj b/Filter/PrecisionControl/PrecisionControl.csproj index 36deb4c..bef0383 100644 --- a/Filter/PrecisionControl/PrecisionControl.csproj +++ b/Filter/PrecisionControl/PrecisionControl.csproj @@ -1,18 +1,2 @@  - - - net5 - true - - - - none - false - false - - - - - - diff --git a/Filter/Reconstructor/Reconstructor.cs b/Filter/Reconstructor/Reconstructor.cs index ad18aa5..c1e132b 100644 --- a/Filter/Reconstructor/Reconstructor.cs +++ b/Filter/Reconstructor/Reconstructor.cs @@ -25,7 +25,7 @@ namespace VoiDPlugins.Filter get => weight; } - public event Action Emit; + public event Action? Emit; public PipelinePosition Position => PipelinePosition.PreTransform; diff --git a/Filter/Reconstructor/Reconstructor.csproj b/Filter/Reconstructor/Reconstructor.csproj index 9019b32..25bef7b 100644 --- a/Filter/Reconstructor/Reconstructor.csproj +++ b/Filter/Reconstructor/Reconstructor.csproj @@ -1,18 +1,5 @@ - - net5 + true - - - none - false - false - - - - - - - diff --git a/OutputMode/TouchEmu/NativeMethods.cs b/OutputMode/TouchEmu/NativeMethods.cs index 6043a86..ac112c3 100644 --- a/OutputMode/TouchEmu/NativeMethods.cs +++ b/OutputMode/TouchEmu/NativeMethods.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; namespace VoiDPlugins.OutputMode @@ -165,7 +166,7 @@ namespace VoiDPlugins.OutputMode [DllImport("user32.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)] [return: MarshalAs(UnmanagedType.Bool)] - public static unsafe extern bool GetPointerDevices(out uint deviceCount, [In, Out, MarshalAs(UnmanagedType.LPArray)] POINTER_DEVICE_INFO[] pointerDevices); + public static unsafe extern bool GetPointerDevices(out uint deviceCount, [In, Out, MarshalAs(UnmanagedType.LPArray), AllowNull] POINTER_DEVICE_INFO[] pointerDevices); [DllImport("user32.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)] public static extern IntPtr GetForegroundWindow(); diff --git a/OutputMode/TouchEmu/Touch.cs b/OutputMode/TouchEmu/Touch.cs index 5609586..33edeee 100644 --- a/OutputMode/TouchEmu/Touch.cs +++ b/OutputMode/TouchEmu/Touch.cs @@ -6,7 +6,7 @@ namespace VoiDPlugins.OutputMode public static class Touch { private static IntPtr _penHandle; - private static POINTER_TYPE_INFO[] pointer; + private static POINTER_TYPE_INFO[]? pointer; private static uint _pointerId; private static IntPtr _sourceDevice; @@ -79,7 +79,7 @@ namespace VoiDPlugins.OutputMode public static void Inject() { - if (!NativeMethods.InjectSyntheticPointerInput(_penHandle, pointer, 1)) + if (!NativeMethods.InjectSyntheticPointerInput(_penHandle, pointer!, 1)) { throw new Exception($"Input injection failed. Reason: {Marshal.GetLastWin32Error()}"); } @@ -87,38 +87,38 @@ namespace VoiDPlugins.OutputMode public static void SetTarget() { - pointer[0].penInfo.pointerInfo.hwndTarget = NativeMethods.GetForegroundWindow(); + pointer![0].penInfo.pointerInfo.hwndTarget = NativeMethods.GetForegroundWindow(); } public static void SetPosition(POINT point) { - pointer[0].penInfo.pointerInfo.ptPixelLocation = point; + pointer![0].penInfo.pointerInfo.ptPixelLocation = point; pointer[0].penInfo.pointerInfo.ptPixelLocationRaw = point; } public static void SetPressure(uint pressure) { - pointer[0].penInfo.pressure = pressure; + pointer![0].penInfo.pressure = pressure; } public static void SetPointerFlags(POINTER_FLAGS flags) { - pointer[0].penInfo.pointerInfo.pointerFlags |= flags; + pointer![0].penInfo.pointerInfo.pointerFlags |= flags; } public static void UnsetPointerFlags(POINTER_FLAGS flags) { - pointer[0].penInfo.pointerInfo.pointerFlags &= ~flags; + pointer![0].penInfo.pointerInfo.pointerFlags &= ~flags; } public static void ClearPointerFlags() { - pointer[0].penInfo.pointerInfo.pointerFlags = 0; + pointer![0].penInfo.pointerInfo.pointerFlags = 0; } public static void ClearPointerFlags(POINTER_FLAGS flags) { - pointer[0].penInfo.pointerInfo.pointerFlags = flags; + pointer![0].penInfo.pointerInfo.pointerFlags = flags; } } } diff --git a/OutputMode/TouchEmu/TouchEmu.csproj b/OutputMode/TouchEmu/TouchEmu.csproj index 36deb4c..05d1625 100644 --- a/OutputMode/TouchEmu/TouchEmu.csproj +++ b/OutputMode/TouchEmu/TouchEmu.csproj @@ -1,18 +1,5 @@  - - net5 - true + true - - - none - false - false - - - - - - diff --git a/OutputMode/TouchEmu/TouchPointerHandler.cs b/OutputMode/TouchEmu/TouchPointerHandler.cs index ef97d0a..f6d17d1 100644 --- a/OutputMode/TouchEmu/TouchPointerHandler.cs +++ b/OutputMode/TouchEmu/TouchPointerHandler.cs @@ -3,7 +3,7 @@ using OpenTabletDriver.Plugin.Platform.Pointer; namespace VoiDPlugins.OutputMode { - public class TouchPointerHandler : IAbsolutePointer, IVirtualTablet + public class TouchPointerHandler : IAbsolutePointer, IPressureHandler { private bool _inContact; private bool _lastContact; @@ -15,16 +15,6 @@ namespace VoiDPlugins.OutputMode _lastContact = false; } - public void SetButtonState(uint button, bool active) - { - return; - } - - public void SetEraser(bool isEraser) - { - return; - } - public void SetPosition(Vector2 pos) { Touch.SetPosition(new POINT((int)pos.X, (int)pos.Y)); @@ -67,15 +57,5 @@ namespace VoiDPlugins.OutputMode _inContact = false; } } - - public void SetProximity(bool proximity, uint distance) - { - return; - } - - public void SetTilt(Vector2 tilt) - { - return; - } } } \ No newline at end of file diff --git a/OutputMode/VMultiMode/Output/VMultiAbsoluteMode.cs b/OutputMode/VMultiMode/Output/VMultiAbsoluteMode.cs index 8ccc6d1..04d1008 100644 --- a/OutputMode/VMultiMode/Output/VMultiAbsoluteMode.cs +++ b/OutputMode/VMultiMode/Output/VMultiAbsoluteMode.cs @@ -10,12 +10,24 @@ namespace VoiDPlugins.OutputMode [PluginName("VMulti Absolute Mode")] public class VMultiAbsoluteMode : AbsoluteOutputMode { + private VMultiAbsolutePointer? _pointer; + [Resolved] public IServiceProvider ServiceProvider { - set => Pointer = new VMultiAbsolutePointer((IVirtualScreen)value.GetService(typeof(IVirtualScreen))); + set => _pointer = new VMultiAbsolutePointer((IVirtualScreen)value.GetService(typeof(IVirtualScreen))!); } - public override IAbsolutePointer Pointer { get; set; } + [OnDependencyLoad] + public void Initialize() + { + _pointer!.Initialize(TabletReference); + } + + public override IAbsolutePointer Pointer + { + get => _pointer!; + set { } + } } } \ No newline at end of file diff --git a/OutputMode/VMultiMode/Output/VMultiRelativeMode.cs b/OutputMode/VMultiMode/Output/VMultiRelativeMode.cs index c230fab..9853fb0 100644 --- a/OutputMode/VMultiMode/Output/VMultiRelativeMode.cs +++ b/OutputMode/VMultiMode/Output/VMultiRelativeMode.cs @@ -1,8 +1,6 @@ -using System; using OpenTabletDriver.Plugin.Attributes; using OpenTabletDriver.Plugin.DependencyInjection; using OpenTabletDriver.Plugin.Output; -using OpenTabletDriver.Plugin.Platform.Display; using OpenTabletDriver.Plugin.Platform.Pointer; namespace VoiDPlugins.OutputMode @@ -10,12 +8,19 @@ namespace VoiDPlugins.OutputMode [PluginName("VMulti Relative Mode")] public class VMultiRelativeMode : RelativeOutputMode { - [Resolved] - public IServiceProvider ServiceProvider + private VMultiRelativePointer? _pointer; + + [OnDependencyLoad] + public void Initialize() { - set => Pointer = new VMultiRelativePointer((IVirtualScreen)value.GetService(typeof(IVirtualScreen))); + _pointer = new VMultiRelativePointer(); + _pointer!.Initialize(TabletReference); } - public override IRelativePointer Pointer { get; set; } + public override IRelativePointer Pointer + { + get => _pointer!; + set { } + } } } \ No newline at end of file diff --git a/OutputMode/VMultiMode/Pointer/VMultiAbsolutePointer.cs b/OutputMode/VMultiMode/Pointer/VMultiAbsolutePointer.cs index 8c1371f..b7f6196 100644 --- a/OutputMode/VMultiMode/Pointer/VMultiAbsolutePointer.cs +++ b/OutputMode/VMultiMode/Pointer/VMultiAbsolutePointer.cs @@ -1,27 +1,43 @@ using System.Numerics; using OpenTabletDriver.Plugin.Platform.Display; using OpenTabletDriver.Plugin.Platform.Pointer; +using OpenTabletDriver.Plugin.Tablet; using VoiDPlugins.Library.VMulti; using VoiDPlugins.Library.VMulti.Device; namespace VoiDPlugins.OutputMode { - public unsafe class VMultiAbsolutePointer : BasePointer, IAbsolutePointer + public unsafe class VMultiAbsolutePointer : IAbsolutePointer, ISynchronousPointer { - public VMultiAbsolutePointer(IVirtualScreen screen) : base(screen, "VMultiAbs") + private AbsoluteInputReport* _rawPointer; + private VMultiInstance? _instance; + private Vector2 _conversionFactor; + + public VMultiAbsolutePointer(IVirtualScreen virtualScreen) { - ButtonHandler.SetReport((VMultiReportHeader*)ReportPointer, ReportBuffer); + _conversionFactor = new Vector2(virtualScreen.Width, virtualScreen.Height) / (1 / 32767); } - protected override AbsoluteInputReport CreateReport() + public void Initialize(TabletReference tabletReference) { - return new AbsoluteInputReport(0x09); + _instance = VMultiInstanceManager.RetrieveVMultiInstance("VMultiAbs", tabletReference, () => new AbsoluteInputReport()); + _rawPointer = _instance.Pointer; } - protected override void SetCoordinates(Vector2 pos) + public void SetPosition(Vector2 pos) { - ReportPointer->X = (ushort)pos.X; - ReportPointer->Y = (ushort)pos.Y; + pos *= _conversionFactor; + _rawPointer->X = (ushort)pos.X; + _rawPointer->Y = (ushort)pos.Y; + } + + public void Reset() + { + } + + public void Flush() + { + _instance!.Write(); } } } \ No newline at end of file diff --git a/OutputMode/VMultiMode/Pointer/VMultiRelativePointer.cs b/OutputMode/VMultiMode/Pointer/VMultiRelativePointer.cs index b742438..686a03b 100644 --- a/OutputMode/VMultiMode/Pointer/VMultiRelativePointer.cs +++ b/OutputMode/VMultiMode/Pointer/VMultiRelativePointer.cs @@ -1,33 +1,38 @@ using System.Numerics; -using OpenTabletDriver.Plugin.Platform.Display; using OpenTabletDriver.Plugin.Platform.Pointer; +using OpenTabletDriver.Plugin.Tablet; using VoiDPlugins.Library.VMulti; using VoiDPlugins.Library.VMulti.Device; namespace VoiDPlugins.OutputMode { - public unsafe class VMultiRelativePointer : BasePointer, IRelativePointer + public unsafe class VMultiRelativePointer : IRelativePointer, ISynchronousPointer { - public VMultiRelativePointer(IVirtualScreen screen) : base(screen, "VMultiRel") + private RelativeInputReport* _rawPointer; + private VMultiInstance? _instance; + private Vector2 _error; + + public void Initialize(TabletReference tabletReference) { - ButtonHandler.SetReport((VMultiReportHeader*)ReportPointer, ReportBuffer); + _instance = VMultiInstanceManager.RetrieveVMultiInstance("VMultiRel", tabletReference, () => new RelativeInputReport()); + _rawPointer = _instance.Pointer; } - protected override RelativeInputReport CreateReport() + public void SetPosition(Vector2 delta) { - return new RelativeInputReport(0x04); + delta += _error; + _error = new Vector2(delta.X % 1, delta.Y % 1); + _rawPointer->X = (byte)delta.X; + _rawPointer->Y = (byte)delta.Y; } - public override void SetPosition(Vector2 pos) + public void Reset() { - SetCoordinates(pos); - Device.Write(ReportBuffer); } - protected override void SetCoordinates(Vector2 pos) + public void Flush() { - ReportPointer->X = (byte)pos.X; - ReportPointer->Y = (byte)pos.Y; + _instance!.Write(); } } } \ No newline at end of file diff --git a/OutputMode/VMultiMode/VMultiButtonHandler.cs b/OutputMode/VMultiMode/VMultiButtonHandler.cs index 7ce89cc..c48d8ab 100644 --- a/OutputMode/VMultiMode/VMultiButtonHandler.cs +++ b/OutputMode/VMultiMode/VMultiButtonHandler.cs @@ -8,8 +8,10 @@ using VoiDPlugins.Library.VMulti; namespace VoiDPlugins.OutputMode { [PluginName("VMulti Mode")] - public class VMultiButtonHandler : ButtonHandler, IStateBinding + public class VMultiButtonHandler : IStateBinding { + private VMultiInstance? _instance; + public static Dictionary Bindings { get; } = new() { { "Left", 1 }, @@ -20,16 +22,24 @@ namespace VoiDPlugins.OutputMode public static string[] ValidButtons { get; } = Bindings.Keys.ToArray(); [Property("Button"), PropertyValidated(nameof(ValidButtons))] - public string Button { get; set; } + public string? Button { get; set; } + + [TabletReference] + public TabletReference Reference { set => Initialize(value); } + + private void Initialize(TabletReference tabletReference) + { + _instance = VMultiInstanceManager.RetrieveVMultiInstance(tabletReference); + } public void Press(TabletReference tablet, IDeviceReport report) { - EnableBit(Bindings[Button]); + _instance!.EnableButtonBit(Bindings[Button!]); } public void Release(TabletReference tablet, IDeviceReport report) { - DisableBit(Bindings[Button]); + _instance!.DisableButtonBit(Bindings[Button!]); } } } \ No newline at end of file diff --git a/OutputMode/VMultiMode/VMultiMode.csproj b/OutputMode/VMultiMode/VMultiMode.csproj index bd9d098..05d1625 100644 --- a/OutputMode/VMultiMode/VMultiMode.csproj +++ b/OutputMode/VMultiMode/VMultiMode.csproj @@ -1,19 +1,5 @@  - - net5 - true + true - - - none - false - false - - - - - - - diff --git a/OutputMode/WindowsInk/Output/WinInkAbsoluteMode.cs b/OutputMode/WindowsInk/Output/WinInkAbsoluteMode.cs index f860304..67514ce 100644 --- a/OutputMode/WindowsInk/Output/WinInkAbsoluteMode.cs +++ b/OutputMode/WindowsInk/Output/WinInkAbsoluteMode.cs @@ -10,12 +10,24 @@ namespace VoiDPlugins.OutputMode [PluginName("Windows Ink Absolute Mode")] public class WinInkAbsoluteMode : AbsoluteOutputMode { + private WinInkAbsolutePointer? _pointer; + [Resolved] public IServiceProvider ServiceProvider { - set => Pointer = new WinInkAbsolutePointer((IVirtualScreen)value.GetService(typeof(IVirtualScreen))); + set => _pointer = new WinInkAbsolutePointer((IVirtualScreen)value.GetService(typeof(IVirtualScreen))!); } - public override IAbsolutePointer Pointer { get; set; } + [OnDependencyLoad] + public void Initialize() + { + _pointer!.Initialize(TabletReference); + } + + public override IAbsolutePointer Pointer + { + get => _pointer!; + set { } + } } } \ No newline at end of file diff --git a/OutputMode/WindowsInk/Output/WinInkRelativeMode.cs b/OutputMode/WindowsInk/Output/WinInkRelativeMode.cs index 9c89338..b7e3b54 100644 --- a/OutputMode/WindowsInk/Output/WinInkRelativeMode.cs +++ b/OutputMode/WindowsInk/Output/WinInkRelativeMode.cs @@ -10,12 +10,24 @@ namespace VoiDPlugins.OutputMode [PluginName("Windows Ink Relative Mode")] public class WinInkRelativeMode : RelativeOutputMode { + private WinInkRelativePointer? _pointer; + [Resolved] public IServiceProvider ServiceProvider { - set => Pointer = new WinInkRelativePointer((IVirtualScreen)value.GetService(typeof(IVirtualScreen))); + set => _pointer = new WinInkRelativePointer((IVirtualScreen)value.GetService(typeof(IVirtualScreen))!); } - public override IRelativePointer Pointer { get; set; } + [OnDependencyLoad] + public void Initialize() + { + _pointer!.Initialize(TabletReference); + } + + public override IRelativePointer Pointer + { + get => _pointer!; + set { } + } } } \ No newline at end of file diff --git a/OutputMode/WindowsInk/Pointer/WinInkAbsolutePointer.cs b/OutputMode/WindowsInk/Pointer/WinInkAbsolutePointer.cs index f9444b0..550a3e1 100644 --- a/OutputMode/WindowsInk/Pointer/WinInkAbsolutePointer.cs +++ b/OutputMode/WindowsInk/Pointer/WinInkAbsolutePointer.cs @@ -1,57 +1,23 @@ using System.Numerics; using OpenTabletDriver.Plugin.Platform.Display; using OpenTabletDriver.Plugin.Platform.Pointer; -using VoiDPlugins.Library.VMulti; -using VoiDPlugins.Library.VMulti.Device; namespace VoiDPlugins.OutputMode { - public unsafe class WinInkAbsolutePointer : BasePointer, IVirtualTablet + public unsafe class WinInkAbsolutePointer : WinInkBasePointer, IAbsolutePointer { - public WinInkAbsolutePointer(IVirtualScreen screen) : base(screen, "WindowsInk") + private readonly Vector2 _conversionFactor; + + public WinInkAbsolutePointer(IVirtualScreen screen) { - WinInkButtonHandler.SetReport(ReportPointer, ReportBuffer); - WinInkButtonHandler.SetDevice(Device); + _conversionFactor = new Vector2(screen.Width, screen.Height) / (1 / 32767); } - public void SetButtonState(uint button, bool active) + public void SetPosition(Vector2 pos) { - throw new System.NotImplementedException(); - } - - public void SetEraser(bool isEraser) - { - if (!WinInkButtonHandler.IsManuallySet) - { - WinInkButtonHandler.EraserStateTransition(isEraser); - } - } - - public void SetPressure(float percentage) - { - ReportPointer->Pressure = (ushort)(percentage * 8191); - } - - public void SetProximity(bool proximity, uint distance) - { - return; - } - - public void SetTilt(Vector2 tilt) - { - ReportPointer->XTilt = (byte)tilt.X; - ReportPointer->YTilt = (byte)tilt.Y; - } - - protected override DigitizerInputReport CreateReport() - { - return new DigitizerInputReport(0x05); - } - - protected override void SetCoordinates(Vector2 pos) - { - ReportPointer->X = (ushort)pos.X; - ReportPointer->Y = (ushort)pos.Y; + pos *= _conversionFactor; + RawPointer->X = (ushort)pos.X; + RawPointer->Y = (ushort)pos.Y; } } } \ No newline at end of file diff --git a/OutputMode/WindowsInk/Pointer/WinInkBasePointer.cs b/OutputMode/WindowsInk/Pointer/WinInkBasePointer.cs new file mode 100644 index 0000000..0be8a6b --- /dev/null +++ b/OutputMode/WindowsInk/Pointer/WinInkBasePointer.cs @@ -0,0 +1,57 @@ +using System.Numerics; +using OpenTabletDriver.Plugin.Platform.Pointer; +using OpenTabletDriver.Plugin.Tablet; +using VoiDPlugins.Library.VMulti; +using VoiDPlugins.Library.VMulti.Device; +using static VoiDPlugins.OutputMode.WindowsInkConstants; + +namespace VoiDPlugins.OutputMode +{ + public unsafe abstract class WinInkBasePointer : IPressureHandler, ITiltHandler, IEraserHandler, ISynchronousPointer + { + protected DigitizerInputReport* RawPointer { get; private set; } + protected VMultiInstance? Instance { get; private set; } + + public void Initialize(TabletReference tabletReference) + { + Instance = VMultiInstanceManager.RetrieveVMultiInstance("WindowsInk", tabletReference, () => new DigitizerInputReport()); + Instance.InitializeData(POINTER, this); + Instance.InitializeData(ERASER_STATE, false); + Instance.InitializeData(MANUAL_ERASER, false); + RawPointer = Instance.Pointer; + } + + public void SetEraser(bool isEraser) + { + if (!Instance!.GetData(MANUAL_ERASER)) + { + WinInkButtonHandler.EraserStateTransition(Instance, ref GetEraser(), isEraser); + } + } + + public void SetPressure(float percentage) + { + RawPointer->Pressure = (ushort)(percentage * 8191); + } + + public void SetTilt(Vector2 tilt) + { + RawPointer->XTilt = (byte)tilt.X; + RawPointer->YTilt = (byte)tilt.Y; + } + + public void Reset() + { + } + + public void Flush() + { + Instance!.Write(); + } + + private ref bool GetEraser() + { + return ref Instance!.GetData(ERASER_STATE); + } + } +} \ No newline at end of file diff --git a/OutputMode/WindowsInk/Pointer/WinInkRelativePointer.cs b/OutputMode/WindowsInk/Pointer/WinInkRelativePointer.cs index 04e34fe..c45a1d1 100644 --- a/OutputMode/WindowsInk/Pointer/WinInkRelativePointer.cs +++ b/OutputMode/WindowsInk/Pointer/WinInkRelativePointer.cs @@ -1,68 +1,29 @@ using System.Numerics; using OpenTabletDriver.Plugin.Platform.Display; using OpenTabletDriver.Plugin.Platform.Pointer; -using VoiDPlugins.Library.VMulti; -using VoiDPlugins.Library.VMulti.Device; namespace VoiDPlugins.OutputMode { - public unsafe class WinInkRelativePointer : BasePointer, IVirtualTablet + public unsafe class WinInkRelativePointer : WinInkBasePointer, IRelativePointer { - private Vector2 maxPoint; - private Vector2 currentPoint; + private Vector2 _maxPoint; + private Vector2 _currentPoint; + private Vector2 _error; - public WinInkRelativePointer(IVirtualScreen screen) : base(screen, "WindowsInk") + public WinInkRelativePointer(IVirtualScreen screen) { - WinInkButtonHandler.SetReport(ReportPointer, ReportBuffer); - WinInkButtonHandler.SetDevice(Device); - maxPoint = new Vector2(VirtualScreen.Width, VirtualScreen.Height); - currentPoint = maxPoint / 2; + _maxPoint = new Vector2(screen.Width, screen.Height); + _currentPoint = _maxPoint / 2; } - public void SetButtonState(uint button, bool active) + public void SetPosition(Vector2 delta) { - return; - } + delta += _error; + _error = new Vector2(delta.X % 1, delta.Y % 1); - public void SetEraser(bool isEraser) - { - if (!WinInkButtonHandler.IsManuallySet) - { - WinInkButtonHandler.EraserStateTransition(isEraser); - } - } - - public void SetPressure(float percentage) - { - ReportPointer->Pressure = (ushort)(percentage * 8191); - } - - public void SetProximity(bool proximity, uint distance) - { - return; - } - - public void SetTilt(Vector2 tilt) - { - ReportPointer->XTilt = (byte)tilt.X; - ReportPointer->YTilt = (byte)tilt.Y; - } - - public override void Translate(Vector2 delta) - { - currentPoint = Vector2.Clamp(currentPoint + delta, Vector2.Zero, maxPoint); - base.SetPosition(currentPoint); - } - - protected override DigitizerInputReport CreateReport() - { - return new DigitizerInputReport(0x05); - } - - protected override void SetCoordinates(Vector2 pos) - { - ReportPointer->X = (ushort)pos.X; - ReportPointer->Y = (ushort)pos.Y; + _currentPoint = Vector2.Clamp(_currentPoint + delta, Vector2.Zero, _maxPoint); + RawPointer->X = (ushort)_currentPoint.X; + RawPointer->Y = (ushort)_currentPoint.Y; } } } \ No newline at end of file diff --git a/OutputMode/WindowsInk/WinInkButtonHandler.cs b/OutputMode/WindowsInk/WinInkButtonHandler.cs index b57fde3..c4f2601 100644 --- a/OutputMode/WindowsInk/WinInkButtonHandler.cs +++ b/OutputMode/WindowsInk/WinInkButtonHandler.cs @@ -1,16 +1,18 @@ using System; -using HidSharp; using OpenTabletDriver.Plugin; using OpenTabletDriver.Plugin.Attributes; using OpenTabletDriver.Plugin.Tablet; using VoiDPlugins.Library.VMulti; using VoiDPlugins.Library.VMulti.Device; +using static VoiDPlugins.OutputMode.WindowsInkConstants; namespace VoiDPlugins.OutputMode { [PluginName("Windows Ink")] - public unsafe class WinInkButtonHandler : ButtonHandler, IStateBinding + public unsafe class WinInkButtonHandler : IStateBinding { + private VMultiInstance? _instance; + public static string[] ValidButtons { get; } = new string[] { "Pen Tip", @@ -20,7 +22,7 @@ namespace VoiDPlugins.OutputMode }; [Property("Button"), PropertyValidated(nameof(ValidButtons))] - public string Button { get; set; } + public string? Button { get; set; } [Flags] private enum ButtonBits : byte @@ -32,30 +34,37 @@ namespace VoiDPlugins.OutputMode InRange = 16 } - public static bool IsManuallySet { get; set; } - private static bool EraserState; - private static HidStream Device; + public bool IsManuallySet { get; set; } + + [TabletReference] + public TabletReference Reference { set => Initialize(value); } + + private void Initialize(TabletReference tabletReference) + { + _instance = VMultiInstanceManager.RetrieveVMultiInstance(tabletReference); + } public void Press(TabletReference tablet, IDeviceReport report) { + ref var eraserState = ref GetEraser(); switch (Button) { case "Pen Tip": - EnableBit((int)(EraserState ? ButtonBits.Eraser : ButtonBits.Press)); + _instance!.EnableButtonBit((int)(eraserState ? ButtonBits.Eraser : ButtonBits.Press)); break; case "Pen Button": - EnableBit((int)ButtonBits.Barrel); + _instance!.EnableButtonBit((int)ButtonBits.Barrel); break; case "Eraser (Toggle)": IsManuallySet = true; - EraserStateTransition(!EraserState); + EraserStateTransition(_instance!, ref eraserState, !eraserState); break; case "Eraser (Hold)": IsManuallySet = true; - EraserStateTransition(true); + EraserStateTransition(_instance!, ref eraserState, true); break; } } @@ -65,60 +74,54 @@ namespace VoiDPlugins.OutputMode switch (Button) { case "Pen Tip": - DisableBit((int)(ButtonBits.Press | ButtonBits.Eraser)); + _instance!.DisableButtonBit((int)(ButtonBits.Press | ButtonBits.Eraser)); break; case "Pen Button": - DisableBit((int)ButtonBits.Barrel); + _instance!.DisableButtonBit((int)ButtonBits.Barrel); break; case "Eraser (Hold)": - EraserStateTransition(false); + EraserStateTransition(_instance!, ref GetEraser(), false); break; } } - public static void EraserStateTransition(bool isEraser) + public static void EraserStateTransition(VMultiInstance instance, ref bool eraserState, bool isEraser) { - if (EraserState != isEraser) + if (eraserState != isEraser) { - EraserState = isEraser; - var report = (DigitizerInputReport*)ReportPointer; + eraserState = isEraser; + var report = (DigitizerInputReport*)instance.Header; var buttons = report->Header.Buttons; var pressure = report->Pressure; // Send In-Range but no tips - DisableBit((int)(ButtonBits.Press | ButtonBits.Eraser)); + instance.DisableButtonBit((int)(ButtonBits.Press | ButtonBits.Eraser)); report->Pressure = 0; - Device.Write(ReportBuffer); + instance.Write(); // Send Out-Of-Range report->Header.Buttons = 0; - Device.Write(ReportBuffer); + instance.Write(); // Send In-Range but no tips - EnableBit((int)ButtonBits.InRange); - if (EraserState) - EnableBit((int)ButtonBits.Invert); + instance.EnableButtonBit((int)ButtonBits.InRange); + if (eraserState) + instance.EnableButtonBit((int)ButtonBits.Invert); - Device.Write(ReportBuffer); + instance.Write(); // Set Proper Report - if (HasBit(buttons, (int)(ButtonBits.Press | ButtonBits.Eraser))) - EnableBit((int)(EraserState ? ButtonBits.Eraser : ButtonBits.Press)); + if (VMultiInstance.HasBit(buttons, (int)(ButtonBits.Press | ButtonBits.Eraser))) + instance.EnableButtonBit((int)(eraserState ? ButtonBits.Eraser : ButtonBits.Press)); report->Pressure = pressure; } } - public static void SetReport(DigitizerInputReport* report, byte[] reportBuffer) + private ref bool GetEraser() { - SetReport((VMultiReportHeader*)report, reportBuffer); - EnableBit((int)ButtonBits.InRange); - } - - public static void SetDevice(HidStream device) - { - Device = device; + return ref _instance!.GetData(ERASER_STATE); } } } \ No newline at end of file diff --git a/OutputMode/WindowsInk/WindowsInk.csproj b/OutputMode/WindowsInk/WindowsInk.csproj index bd9d098..05d1625 100644 --- a/OutputMode/WindowsInk/WindowsInk.csproj +++ b/OutputMode/WindowsInk/WindowsInk.csproj @@ -1,19 +1,5 @@  - - net5 - true + true - - - none - false - false - - - - - - - diff --git a/OutputMode/WindowsInk/WindowsInkConstants.cs b/OutputMode/WindowsInk/WindowsInkConstants.cs new file mode 100644 index 0000000..1b0380f --- /dev/null +++ b/OutputMode/WindowsInk/WindowsInkConstants.cs @@ -0,0 +1,9 @@ +namespace VoiDPlugins.OutputMode +{ + public static class WindowsInkConstants + { + public const int POINTER = 0; + public const int ERASER_STATE = 1; + public const int MANUAL_ERASER = 2; + } +} \ No newline at end of file diff --git a/VoiDPlugins.Library/VMulti/BasePointer.cs b/VoiDPlugins.Library/VMulti/BasePointer.cs deleted file mode 100644 index 7b66ff7..0000000 --- a/VoiDPlugins.Library/VMulti/BasePointer.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.Numerics; -using System.Runtime.CompilerServices; -using HidSharp; -using OpenTabletDriver.Plugin.Attributes; -using OpenTabletDriver.Plugin.Platform.Display; -using OpenTabletDriver.Plugin.Platform.Pointer; - -namespace VoiDPlugins.Library.VMulti -{ - [PluginIgnore] - public abstract unsafe class BasePointer : IAbsolutePointer, IRelativePointer where T : unmanaged - { - protected readonly byte[] ReportBuffer; - protected readonly T* ReportPointer; - protected readonly HidStream Device; - protected IVirtualScreen VirtualScreen; - - private Vector2 ScreenToVMulti; - private Vector2 error; - - public BasePointer(IVirtualScreen screen, string Name) - { - ReportBuffer = GC.AllocateArray(Unsafe.SizeOf(), pinned: true); - ReportPointer = (T*)Unsafe.AsPointer(ref ReportBuffer[0]); - - T report = CreateReport(); - *ReportPointer = report; - - VirtualScreen = screen; - Device = VMultiDevice.Retrieve(Name); - - ScreenToVMulti = new Vector2(VirtualScreen.Width, VirtualScreen.Height) / 32767; - } - - protected Vector2 Convert(Vector2 pos) - { - return pos / ScreenToVMulti; - } - - protected abstract T CreateReport(); - protected abstract void SetCoordinates(Vector2 pos); - - public virtual void SetPosition(Vector2 pos) - { - SetCoordinates(Convert(pos)); - Device.Write(ReportBuffer); - } - - public virtual void Translate(Vector2 delta) - { - delta += error; - error = new Vector2(delta.X % 1, delta.Y % 1); - - SetCoordinates(delta); - Device.Write(ReportBuffer); - } - } -} \ No newline at end of file diff --git a/VoiDPlugins.Library/VMulti/ButtonHandler.cs b/VoiDPlugins.Library/VMulti/ButtonHandler.cs deleted file mode 100644 index 748e309..0000000 --- a/VoiDPlugins.Library/VMulti/ButtonHandler.cs +++ /dev/null @@ -1,38 +0,0 @@ -using OpenTabletDriver.Plugin.Attributes; -using VoiDPlugins.Library.VMulti.Device; - -namespace VoiDPlugins.Library.VMulti -{ - [PluginIgnore] - public unsafe class ButtonHandler - { - protected static byte[] ReportBuffer; - protected static VMultiReportHeader* ReportPointer; - - public static void SetReport(VMultiReportHeader* report, byte[] reportBuffer) - { - ReportBuffer = reportBuffer; - ReportPointer = report; - } - - public static void EnableBit(int bit) - { - ReportPointer->Buttons = (byte)(ReportPointer->Buttons | bit); - } - - public static void DisableBit(int bit) - { - ReportPointer->Buttons = (byte)(ReportPointer->Buttons & ~bit); - } - - public static bool HasBit(int bit) - { - return (ReportPointer->Buttons & bit) != 0; - } - - public static bool HasBit(byte buttons, int bit) - { - return (buttons & bit) != 0; - } - } -} \ No newline at end of file diff --git a/VoiDPlugins.Library/VMulti/Device/AbsoluteInputReport.cs b/VoiDPlugins.Library/VMulti/Device/AbsoluteInputReport.cs index 016eefb..9ffc686 100644 --- a/VoiDPlugins.Library/VMulti/Device/AbsoluteInputReport.cs +++ b/VoiDPlugins.Library/VMulti/Device/AbsoluteInputReport.cs @@ -6,9 +6,9 @@ namespace VoiDPlugins.Library.VMulti.Device [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct AbsoluteInputReport { - public AbsoluteInputReport(byte reportID) + public AbsoluteInputReport() { - Header = new VMultiReportHeader(Unsafe.SizeOf(), reportID); + Header = new VMultiReportHeader(Unsafe.SizeOf(), 0x09); X = 0; Y = 0; Pressure = 0; diff --git a/VoiDPlugins.Library/VMulti/VMulti.csproj b/VoiDPlugins.Library/VMulti/VMulti.csproj index 14f047c..8b2354d 100644 --- a/VoiDPlugins.Library/VMulti/VMulti.csproj +++ b/VoiDPlugins.Library/VMulti/VMulti.csproj @@ -1,19 +1,5 @@ - - - net5 - true - - - - none - false - false - - - - \ No newline at end of file diff --git a/VoiDPlugins.Library/VMulti/VMultiDevice.cs b/VoiDPlugins.Library/VMulti/VMultiDevice.cs deleted file mode 100644 index 2e83b57..0000000 --- a/VoiDPlugins.Library/VMulti/VMultiDevice.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using HidSharp; -using OpenTabletDriver.Plugin; - -namespace VoiDPlugins.Library.VMulti -{ - public static class VMultiDevice - { - public static HidStream Retrieve(string Name) - { - HidStream VMultiDev = null; - foreach (var device in DeviceList.Local.GetHidDevices(productID: 47820)) - { - if (device.GetMaxOutputReportLength() == 65 && device.GetMaxInputReportLength() == 65) - { - if (device.TryOpen(out VMultiDev)) - break; - } - } - - if (VMultiDev == null) - { - Log.Write(Name, "Cannot find VirtualHID", LogLevel.Error); - Log.Write(Name, "Install VMulti driver here: https://github.com/X9VoiD/vmulti-bin/releases/latest", LogLevel.Error); - throw new Exception(); - } - - return VMultiDev; - } - } -} \ No newline at end of file diff --git a/VoiDPlugins.Library/VMulti/VMultiInstance.cs b/VoiDPlugins.Library/VMulti/VMultiInstance.cs new file mode 100644 index 0000000..a13042c --- /dev/null +++ b/VoiDPlugins.Library/VMulti/VMultiInstance.cs @@ -0,0 +1,101 @@ +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using HidSharp; +using OpenTabletDriver.Plugin; +using VoiDPlugins.Library.VMulti.Device; + +namespace VoiDPlugins.Library.VMulti +{ + public class VMultiInstance + { + private readonly object[] _data; + private readonly HidStream _device; + protected readonly byte[] Buffer; + public unsafe VMultiReportHeader* Header { get; } + + internal unsafe VMultiInstance(string name, int size) + { + Buffer = GC.AllocateArray(size, true); + Header = (VMultiReportHeader*)Unsafe.AsPointer(ref Buffer[0]); + _device = Retrieve(name); + _data = GC.AllocateArray(32, true); + } + + public void Write() + { + _device.Write(Buffer); + } + + public void InitializeData(int i, T data) + { + Check(); + _data[i] = data!; + } + + public unsafe ref T GetData(int i) + { + return ref Unsafe.AsRef(Unsafe.AsPointer(ref _data[i])); + } + + public unsafe void EnableButtonBit(int bit) + { + Header->Buttons = (byte)(Header->Buttons | bit); + } + + public unsafe void DisableButtonBit(int bit) + { + Header->Buttons = (byte)(Header->Buttons & ~bit); + } + + public unsafe bool HasButtonBit(int bit) + { + return HasBit(Header->Buttons, bit); + } + + public static bool HasBit(byte buttons, int bit) + { + return (buttons & bit) != 0; + } + + private static HidStream Retrieve(string Name) + { + HidStream? VMultiDev = null; + foreach (var device in DeviceList.Local.GetHidDevices(productID: 47820)) + { + if (device.GetMaxOutputReportLength() == 65 && device.GetMaxInputReportLength() == 65) + { + if (device.TryOpen(out VMultiDev)) + break; + } + } + + if (VMultiDev == null) + { + Log.Write(Name, "Cannot find VirtualHID", LogLevel.Error); + Log.Write(Name, "Install VMulti driver here: https://github.com/X9VoiD/vmulti-bin/releases/latest", LogLevel.Error); + throw new Exception(); + } + + return VMultiDev; + } + + [Conditional("DEBUG")] + private void Check() + { + if (Unsafe.SizeOf() > IntPtr.Size) + throw new InvalidOperationException(); + } + } + + public class VMultiInstance : VMultiInstance where T : unmanaged + { + public unsafe T* Pointer { get; } + + internal unsafe VMultiInstance(string name, Func initialValue) : base(name, Unsafe.SizeOf()) + { + Pointer = (T*)Unsafe.AsPointer(ref Buffer[0]); + *Pointer = initialValue(); + } + } +} \ No newline at end of file diff --git a/VoiDPlugins.Library/VMulti/VMultiInstanceManager.cs b/VoiDPlugins.Library/VMulti/VMultiInstanceManager.cs new file mode 100644 index 0000000..d3a97d0 --- /dev/null +++ b/VoiDPlugins.Library/VMulti/VMultiInstanceManager.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using OpenTabletDriver.Plugin.Tablet; + +namespace VoiDPlugins.Library.VMulti +{ + public static class VMultiInstanceManager + { + private static readonly object _syncLock = new(); + private static readonly Dictionary _map = new(); + + public static VMultiInstance RetrieveVMultiInstance(string name, TabletReference tabletReference, Func initialValue) + where T : unmanaged + { + lock (_syncLock) + { + ref var instance = ref CollectionsMarshal.GetValueRefOrAddDefault(_map, tabletReference.Properties.Name, out var exists); + if (!exists) + instance = new VMultiInstance(name, initialValue); + return (VMultiInstance)instance!; + } + } + + public static VMultiInstance RetrieveVMultiInstance(TabletReference tabletReference) + { + return _map[tabletReference.Properties.Name]; + } + } +} \ No newline at end of file diff --git a/VoiDPlugins.Library/VoiD/VoiD.csproj b/VoiDPlugins.Library/VoiD/VoiD.csproj index 15b3585..cfdae44 100644 --- a/VoiDPlugins.Library/VoiD/VoiD.csproj +++ b/VoiDPlugins.Library/VoiD/VoiD.csproj @@ -1,13 +1,5 @@ - - net5 + true - - - none - false - false - - \ No newline at end of file diff --git a/VoiDPlugins.sln b/VoiDPlugins.sln index 11d4b22..08a655d 100644 --- a/VoiDPlugins.sln +++ b/VoiDPlugins.sln @@ -23,10 +23,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VMultiMode", "OutputMode\VM EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsInk", "OutputMode\WindowsInk\WindowsInk.csproj", "{D8DBD60E-BE5C-43DE-AEB6-D6ADBAC3BE8C}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tool", "Tool", "{C3E1E369-CD2C-4030-88BE-3D4E7493F8C7}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OemKill", "Tool\OemKill\OemKill.csproj", "{DE2D6E1E-F04E-4E0C-BE95-7B8E8AFBCD4C}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "VoiDPlugins.Library", "VoiDPlugins.Library", "{9B841994-6F85-4834-8C8C-04D196FE388A}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VMulti", "VoiDPlugins.Library\VMulti\VMulti.csproj", "{E6A1BA35-D3D4-4F28-9B59-FA946B3039C7}" @@ -128,18 +124,6 @@ Global {D8DBD60E-BE5C-43DE-AEB6-D6ADBAC3BE8C}.Release|x64.Build.0 = Release|Any CPU {D8DBD60E-BE5C-43DE-AEB6-D6ADBAC3BE8C}.Release|x86.ActiveCfg = Release|Any CPU {D8DBD60E-BE5C-43DE-AEB6-D6ADBAC3BE8C}.Release|x86.Build.0 = Release|Any CPU - {DE2D6E1E-F04E-4E0C-BE95-7B8E8AFBCD4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DE2D6E1E-F04E-4E0C-BE95-7B8E8AFBCD4C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DE2D6E1E-F04E-4E0C-BE95-7B8E8AFBCD4C}.Debug|x64.ActiveCfg = Debug|Any CPU - {DE2D6E1E-F04E-4E0C-BE95-7B8E8AFBCD4C}.Debug|x64.Build.0 = Debug|Any CPU - {DE2D6E1E-F04E-4E0C-BE95-7B8E8AFBCD4C}.Debug|x86.ActiveCfg = Debug|Any CPU - {DE2D6E1E-F04E-4E0C-BE95-7B8E8AFBCD4C}.Debug|x86.Build.0 = Debug|Any CPU - {DE2D6E1E-F04E-4E0C-BE95-7B8E8AFBCD4C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DE2D6E1E-F04E-4E0C-BE95-7B8E8AFBCD4C}.Release|Any CPU.Build.0 = Release|Any CPU - {DE2D6E1E-F04E-4E0C-BE95-7B8E8AFBCD4C}.Release|x64.ActiveCfg = Release|Any CPU - {DE2D6E1E-F04E-4E0C-BE95-7B8E8AFBCD4C}.Release|x64.Build.0 = Release|Any CPU - {DE2D6E1E-F04E-4E0C-BE95-7B8E8AFBCD4C}.Release|x86.ActiveCfg = Release|Any CPU - {DE2D6E1E-F04E-4E0C-BE95-7B8E8AFBCD4C}.Release|x86.Build.0 = Release|Any CPU {E6A1BA35-D3D4-4F28-9B59-FA946B3039C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E6A1BA35-D3D4-4F28-9B59-FA946B3039C7}.Debug|Any CPU.Build.0 = Debug|Any CPU {E6A1BA35-D3D4-4F28-9B59-FA946B3039C7}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -161,7 +145,6 @@ Global {40F46E98-3485-4805-A70A-EAC5C6E0BACC} = {44DF0884-9B34-45CA-92B7-2D57DCA3A1A8} {A0101CA9-B8C8-4715-81E6-0A1EB34CA739} = {44DF0884-9B34-45CA-92B7-2D57DCA3A1A8} {D8DBD60E-BE5C-43DE-AEB6-D6ADBAC3BE8C} = {44DF0884-9B34-45CA-92B7-2D57DCA3A1A8} - {DE2D6E1E-F04E-4E0C-BE95-7B8E8AFBCD4C} = {C3E1E369-CD2C-4030-88BE-3D4E7493F8C7} {E6A1BA35-D3D4-4F28-9B59-FA946B3039C7} = {9B841994-6F85-4834-8C8C-04D196FE388A} EndGlobalSection EndGlobal