diff --git a/src/OutputMode/VMultiMode/Pointer/VMultiAbsolutePointer.cs b/src/OutputMode/VMultiMode/Pointer/VMultiAbsolutePointer.cs index 7ab3e4e..9fb0f8c 100644 --- a/src/OutputMode/VMultiMode/Pointer/VMultiAbsolutePointer.cs +++ b/src/OutputMode/VMultiMode/Pointer/VMultiAbsolutePointer.cs @@ -21,15 +21,23 @@ namespace VoiDPlugins.OutputMode public VMultiAbsolutePointer(TabletReference tabletReference, IVirtualScreen virtualScreen) { _instance = new VMultiInstance("VMultiAbs", new AbsoluteInputReport()); - SharedStore.GetStore(tabletReference, STORE_KEY).Add(INSTANCE, _instance); - _rawPointer = _instance.Pointer; - _conversionFactor = new Vector2(32767, 32767) / new Vector2(virtualScreen.Width, virtualScreen.Height); + if (SharedStore.GetStore(tabletReference, STORE_KEY).TryAdd(INSTANCE, _instance)) + { + _rawPointer = _instance.Pointer; + _conversionFactor = new Vector2(32767, 32767) / new Vector2(virtualScreen.Width, virtualScreen.Height); + } + else + { + _instance = null; + } } public void SetPosition(Vector2 pos) { if (pos == _prev) return; + if (_rawPointer is null) + return; pos *= _conversionFactor; _rawPointer->X = (ushort)pos.X; @@ -44,10 +52,10 @@ namespace VoiDPlugins.OutputMode public void Flush() { - if (_dirty) + if (_dirty && _instance is not null) { _dirty = false; - _instance!.Write(); + _instance.Write(); } } } diff --git a/src/OutputMode/VMultiMode/Pointer/VMultiRelativePointer.cs b/src/OutputMode/VMultiMode/Pointer/VMultiRelativePointer.cs index 5c87df6..5b4af18 100644 --- a/src/OutputMode/VMultiMode/Pointer/VMultiRelativePointer.cs +++ b/src/OutputMode/VMultiMode/Pointer/VMultiRelativePointer.cs @@ -19,14 +19,22 @@ namespace VoiDPlugins.OutputMode public VMultiRelativePointer(TabletReference tabletReference) { _instance = new VMultiInstance("VMultiRel", new RelativeInputReport()); - SharedStore.GetStore(tabletReference, STORE_KEY).Add(INSTANCE, _instance); - _rawPointer = _instance.Pointer; + if (SharedStore.GetStore(tabletReference, STORE_KEY).TryAdd(INSTANCE, _instance)) + { + _rawPointer = _instance.Pointer; + } + else + { + _instance = null; + } } public void SetPosition(Vector2 delta) { if (delta == Vector2.Zero && _prev == Vector2.Zero) return; + if (_rawPointer is null) + return; delta += _error; _error = new Vector2(delta.X % 1, delta.Y % 1); @@ -42,10 +50,10 @@ namespace VoiDPlugins.OutputMode public void Flush() { - if (_dirty) + if (_dirty && _instance is not null) { _dirty = false; - _instance!.Write(); + _instance.Write(); } } } diff --git a/src/OutputMode/WindowsInk/Pointer/ThinVMultiAbsPointer.cs b/src/OutputMode/WindowsInk/Pointer/ThinVMultiAbsPointer.cs new file mode 100644 index 0000000..c330671 --- /dev/null +++ b/src/OutputMode/WindowsInk/Pointer/ThinVMultiAbsPointer.cs @@ -0,0 +1,29 @@ +using System.Numerics; +using OpenTabletDriver.Plugin.Platform.Display; +using VoiDPlugins.Library.VMulti; +using VoiDPlugins.Library.VMulti.Device; + +namespace VoiDPlugins.OutputMode +{ + internal unsafe class ThinVMultiAbsPointer + { + private readonly AbsoluteInputReport* _rawPointer; + private readonly VMultiInstance? _instance; + private Vector2 _conversionFactor; + + public ThinVMultiAbsPointer(IVirtualScreen virtualScreen) + { + _instance = new VMultiInstance("VMultiAbs", new AbsoluteInputReport()); + _rawPointer = _instance.Pointer; + _conversionFactor = new Vector2(32767, 32767) / new Vector2(virtualScreen.Width, virtualScreen.Height); + } + + public void SetPosition(Vector2 pos) + { + pos *= _conversionFactor; + _rawPointer->X = (ushort)pos.X; + _rawPointer->Y = (ushort)pos.Y; + _instance!.Write(); + } + } +} \ No newline at end of file diff --git a/src/OutputMode/WindowsInk/Pointer/WinInkAbsolutePointer.cs b/src/OutputMode/WindowsInk/Pointer/WinInkAbsolutePointer.cs index 673b672..3e45398 100644 --- a/src/OutputMode/WindowsInk/Pointer/WinInkAbsolutePointer.cs +++ b/src/OutputMode/WindowsInk/Pointer/WinInkAbsolutePointer.cs @@ -10,7 +10,8 @@ namespace VoiDPlugins.OutputMode private readonly Vector2 _conversionFactor; private Vector2 _prev; - public WinInkAbsolutePointer(TabletReference tabletReference, IVirtualScreen screen) : base("Windows Ink", tabletReference) + public WinInkAbsolutePointer(TabletReference tabletReference, IVirtualScreen screen) + : base("Windows Ink", tabletReference, screen) { _conversionFactor = new Vector2(32767, 32767) / new Vector2(screen.Width, screen.Height); } @@ -19,6 +20,8 @@ namespace VoiDPlugins.OutputMode { if (pos == _prev) return; + if (Instance is null) + return; Instance!.EnableButtonBit((int)WindowsInkButtonFlags.InRange); pos *= _conversionFactor; diff --git a/src/OutputMode/WindowsInk/Pointer/WinInkBasePointer.cs b/src/OutputMode/WindowsInk/Pointer/WinInkBasePointer.cs index 4caebb7..adc75fd 100644 --- a/src/OutputMode/WindowsInk/Pointer/WinInkBasePointer.cs +++ b/src/OutputMode/WindowsInk/Pointer/WinInkBasePointer.cs @@ -1,4 +1,6 @@ using System.Numerics; +using OpenTabletDriver.Plugin.Attributes; +using OpenTabletDriver.Plugin.Platform.Display; using OpenTabletDriver.Plugin.Platform.Pointer; using OpenTabletDriver.Plugin.Tablet; using VoiDPlugins.Library.VMulti; @@ -10,50 +12,86 @@ namespace VoiDPlugins.OutputMode { public unsafe abstract class WinInkBasePointer : IPressureHandler, ITiltHandler, IEraserHandler, ISynchronousPointer { + private readonly IVirtualScreen _screen; + private ThinVMultiAbsPointer? _osPointer; protected DigitizerInputReport* RawPointer { get; } - protected VMultiInstance Instance { get; } - protected SharedStore SharedStore { get; } + protected VMultiInstance? Instance { get; } + protected SharedStore? SharedStore { get; } protected bool Dirty { get; set; } - public WinInkBasePointer(string name, TabletReference tabletReference) + [Property("Sync")] + [ToolTip("Synchronize OS cursor with Windows Ink's current position when pen goes out of range.")] + [DefaultPropertyValue(true)] + public bool Sync { + set => _osPointer = value ? new ThinVMultiAbsPointer(_screen) : null; + } + + [Property("Forced Sync")] + [ToolTip("If this and \"Sync\" is enabled, the OS cursor will always be resynced with Windows Ink's current position.")] + [DefaultPropertyValue(false)] + public bool ForcedSync { get; set; } + + public WinInkBasePointer(string name, TabletReference tabletReference, IVirtualScreen screen) + { + _screen = screen; Instance = new VMultiInstance(name, new DigitizerInputReport()); SharedStore = SharedStore.GetStore(tabletReference, STORE_KEY); - SharedStore.Add(INSTANCE, Instance); - SharedStore.Add(POINTER, this); - SharedStore.Add(ERASER_STATE, false); - SharedStore.Add(MANUAL_ERASER, false); - RawPointer = Instance.Pointer; + if (SharedStore.TryAdd(INSTANCE, Instance)) + { + SharedStore.TryAdd(POINTER, this); + SharedStore.TryAdd(ERASER_STATE, false); + SharedStore.TryAdd(MANUAL_ERASER, false); + RawPointer = Instance.Pointer; + } + else + { + Instance = null; + SharedStore = null; + RawPointer = null; + } } public void SetEraser(bool isEraser) { - if (!SharedStore.Get(MANUAL_ERASER)) + if (!SharedStore?.Get(MANUAL_ERASER) ?? false) { - WindowsInkButtonHandler.EraserStateTransition(SharedStore, Instance, isEraser); + WindowsInkButtonHandler.EraserStateTransition(SharedStore!, Instance!, isEraser); } } public void SetPressure(float percentage) { - RawPointer->Pressure = (ushort)(percentage * 8191); + if (RawPointer != null) + RawPointer->Pressure = (ushort)(percentage * 8191); } public void SetTilt(Vector2 tilt) { - RawPointer->XTilt = (byte)tilt.X; - RawPointer->YTilt = (byte)tilt.Y; + if (RawPointer != null) + { + RawPointer->XTilt = (byte)tilt.X; + RawPointer->YTilt = (byte)tilt.Y; + } } public void Reset() { + if (RawPointer is not null && _osPointer is not null && !ForcedSync) + { + _osPointer.SetPosition(new Vector2(RawPointer->X, RawPointer->Y)); + } } public void Flush() { - if (Dirty) + if (RawPointer is not null && Dirty) { Dirty = false; + + if (ForcedSync) + _osPointer?.SetPosition(new Vector2(RawPointer->X, RawPointer->Y)); + Instance!.Write(); } } diff --git a/src/OutputMode/WindowsInk/Pointer/WinInkRelativePointer.cs b/src/OutputMode/WindowsInk/Pointer/WinInkRelativePointer.cs index 9af5e1e..996c620 100644 --- a/src/OutputMode/WindowsInk/Pointer/WinInkRelativePointer.cs +++ b/src/OutputMode/WindowsInk/Pointer/WinInkRelativePointer.cs @@ -12,7 +12,8 @@ namespace VoiDPlugins.OutputMode private Vector2 _error; private Vector2 _prev; - public WinInkRelativePointer(TabletReference tabletReference, IVirtualScreen screen) : base("Windows Ink", tabletReference) + public WinInkRelativePointer(TabletReference tabletReference, IVirtualScreen screen) + : base("Windows Ink", tabletReference, screen) { _maxPoint = new Vector2(screen.Width, screen.Height); _currentPoint = _maxPoint / 2; @@ -22,8 +23,10 @@ namespace VoiDPlugins.OutputMode { if (_prev == Vector2.Zero && delta == Vector2.Zero) return; + if (Instance is null) + return; - Instance!.EnableButtonBit((int)WindowsInkButtonFlags.InRange); + Instance.EnableButtonBit((int)WindowsInkButtonFlags.InRange); delta += _error; _error = new Vector2(delta.X % 1, delta.Y % 1); _currentPoint = Vector2.Clamp(_currentPoint + delta, Vector2.Zero, _maxPoint); diff --git a/src/VoiDPlugins.Library/VoiD/SharedStore.cs b/src/VoiDPlugins.Library/VoiD/SharedStore.cs index a4680d7..c77eb57 100644 --- a/src/VoiDPlugins.Library/VoiD/SharedStore.cs +++ b/src/VoiDPlugins.Library/VoiD/SharedStore.cs @@ -49,6 +49,11 @@ namespace VoiDPlugins.Library.VoiD ((IDictionary)_sharedStore).Add(key, value); } + public bool TryAdd(int key, object value) + { + return _sharedStore.TryAdd(key, value); + } + public void Add(KeyValuePair item) { ((ICollection>)_sharedStore).Add(item);