Generalize SharedStore

This commit is contained in:
X9VoiD 2022-01-13 01:58:20 +08:00
parent 8c96ec7537
commit 3dd078ea2d
14 changed files with 101 additions and 72 deletions

View file

@ -4,6 +4,7 @@ using OpenTabletDriver.Plugin.Platform.Pointer;
using OpenTabletDriver.Plugin.Tablet;
using VoiDPlugins.Library.VMulti;
using VoiDPlugins.Library.VMulti.Device;
using VoiDPlugins.Library.VoiD;
namespace VoiDPlugins.OutputMode
{
@ -15,7 +16,7 @@ namespace VoiDPlugins.OutputMode
public VMultiAbsolutePointer(TabletReference tabletReference, IVirtualScreen virtualScreen)
{
_instance = VMultiInstanceManager.RetrieveVMultiInstance("VMultiAbs", tabletReference, () => new AbsoluteInputReport());
_instance = GlobalStore<VMultiInstance>.GetOrInitialize(tabletReference, () => new VMultiInstance<AbsoluteInputReport>("VMultiAbs", new AbsoluteInputReport()));
_rawPointer = _instance.Pointer;
_conversionFactor = new Vector2(32767, 32767) / new Vector2(virtualScreen.Width, virtualScreen.Height);
}

View file

@ -3,6 +3,7 @@ using OpenTabletDriver.Plugin.Platform.Pointer;
using OpenTabletDriver.Plugin.Tablet;
using VoiDPlugins.Library.VMulti;
using VoiDPlugins.Library.VMulti.Device;
using VoiDPlugins.Library.VoiD;
namespace VoiDPlugins.OutputMode
{
@ -14,7 +15,7 @@ namespace VoiDPlugins.OutputMode
public VMultiRelativePointer(TabletReference tabletReference)
{
_instance = VMultiInstanceManager.RetrieveVMultiInstance("VMultiRel", tabletReference, () => new RelativeInputReport());
_instance = GlobalStore<VMultiInstance>.GetOrInitialize(tabletReference, () => new VMultiInstance<RelativeInputReport>("VMultiAbs", new RelativeInputReport()));
_rawPointer = _instance.Pointer;
}

View file

@ -4,6 +4,7 @@ using OpenTabletDriver.Plugin;
using OpenTabletDriver.Plugin.Attributes;
using OpenTabletDriver.Plugin.Tablet;
using VoiDPlugins.Library.VMulti;
using VoiDPlugins.Library.VoiD;
namespace VoiDPlugins.OutputMode
{
@ -29,7 +30,7 @@ namespace VoiDPlugins.OutputMode
private void Initialize(TabletReference tabletReference)
{
_instance = VMultiInstanceManager.RetrieveVMultiInstance(tabletReference);
_instance = GlobalStore<VMultiInstance>.Get(tabletReference);
}
public void Press(TabletReference tablet, IDeviceReport report)

View file

@ -1,5 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<VMultiLibrary>true</VMultiLibrary>
<VoiDLibrary>true</VoiDLibrary>
</PropertyGroup>
</Project>

View file

@ -9,7 +9,7 @@ namespace VoiDPlugins.OutputMode
{
private readonly Vector2 _conversionFactor;
public WinInkAbsolutePointer(TabletReference tabletReference, IVirtualScreen screen) : base(tabletReference)
public WinInkAbsolutePointer(TabletReference tabletReference, IVirtualScreen screen) : base("Windows Ink", tabletReference)
{
_conversionFactor = new Vector2(32767, 32767) / new Vector2(screen.Width, screen.Height);
}

View file

@ -4,6 +4,7 @@ using OpenTabletDriver.Plugin.Tablet;
using VoiDPlugins.Library;
using VoiDPlugins.Library.VMulti;
using VoiDPlugins.Library.VMulti.Device;
using VoiDPlugins.Library.VoiD;
using static VoiDPlugins.OutputMode.WindowsInkConstants;
namespace VoiDPlugins.OutputMode
@ -12,21 +13,24 @@ namespace VoiDPlugins.OutputMode
{
protected DigitizerInputReport* RawPointer { get; }
protected VMultiInstance<DigitizerInputReport>? Instance { get; }
protected SharedStore? SharedStore { get; }
public WinInkBasePointer(TabletReference tabletReference)
public WinInkBasePointer(string name, TabletReference tabletReference)
{
Instance = VMultiInstanceManager.RetrieveVMultiInstance("WindowsInk", tabletReference, () => new DigitizerInputReport());
Instance.InitializeData(POINTER, this);
Instance.InitializeData(ERASER_STATE, new Boxed<bool>(false));
Instance.InitializeData(MANUAL_ERASER, new Boxed<bool>(false));
Instance = new VMultiInstance<DigitizerInputReport>(name, new DigitizerInputReport());
SharedStore = GlobalStore<SharedStore>.GetOrInitialize(tabletReference, () => new SharedStore());
SharedStore.InitializeData(INSTANCE, Instance);
SharedStore.InitializeData(POINTER, this);
SharedStore.InitializeData(ERASER_STATE, new Boxed<bool>(false));
SharedStore.InitializeData(MANUAL_ERASER, new Boxed<bool>(false));
RawPointer = Instance.Pointer;
}
public void SetEraser(bool isEraser)
{
if (!Instance!.GetData<Boxed<bool>>(MANUAL_ERASER).Value)
if (!SharedStore!.GetData<Boxed<bool>>(MANUAL_ERASER).Value)
{
WindowsInkButtonHandler.EraserStateTransition(Instance, ref GetEraser(), isEraser);
WindowsInkButtonHandler.EraserStateTransition(Instance!, ref GetEraser(), isEraser);
}
}
@ -43,7 +47,6 @@ namespace VoiDPlugins.OutputMode
public void Reset()
{
Instance!.DisableButtonBit((int)WindowsInkButtonFlags.InRange);
}
public void Flush()
@ -53,7 +56,7 @@ namespace VoiDPlugins.OutputMode
private ref Boxed<bool> GetEraser()
{
return ref Instance!.GetData<Boxed<bool>>(ERASER_STATE);
return ref SharedStore!.GetData<Boxed<bool>>(ERASER_STATE);
}
}
}

View file

@ -11,7 +11,7 @@ namespace VoiDPlugins.OutputMode
private Vector2 _currentPoint;
private Vector2 _error;
public WinInkRelativePointer(TabletReference tabletReference, IVirtualScreen screen) : base(tabletReference)
public WinInkRelativePointer(TabletReference tabletReference, IVirtualScreen screen) : base("Windows Ink", tabletReference)
{
_maxPoint = new Vector2(screen.Width, screen.Height);
_currentPoint = _maxPoint / 2;

View file

@ -4,6 +4,7 @@ using OpenTabletDriver.Plugin.Tablet;
using VoiDPlugins.Library;
using VoiDPlugins.Library.VMulti;
using VoiDPlugins.Library.VMulti.Device;
using VoiDPlugins.Library.VoiD;
using static VoiDPlugins.OutputMode.WindowsInkConstants;
namespace VoiDPlugins.OutputMode
@ -12,6 +13,7 @@ namespace VoiDPlugins.OutputMode
public unsafe partial class WindowsInkButtonHandler : IStateBinding
{
private VMultiInstance? _instance;
private SharedStore? _sharedStore;
public static string[] ValidButtons { get; } = new string[]
{
@ -24,14 +26,13 @@ namespace VoiDPlugins.OutputMode
[Property("Button"), PropertyValidated(nameof(ValidButtons))]
public string? Button { get; set; }
public bool IsManuallySet { get; set; }
[TabletReference]
public TabletReference Reference { set => Initialize(value); }
private void Initialize(TabletReference tabletReference)
{
_instance = VMultiInstanceManager.RetrieveVMultiInstance(tabletReference);
_sharedStore = GlobalStore<SharedStore>.Get(tabletReference);
_instance = _sharedStore.GetData<VMultiInstance>(INSTANCE);
}
public void Press(TabletReference tablet, IDeviceReport report)
@ -48,12 +49,12 @@ namespace VoiDPlugins.OutputMode
break;
case "Eraser (Toggle)":
IsManuallySet = true;
_sharedStore!.GetData<Boxed<bool>>(MANUAL_ERASER).Value = !eraserState.Value;
EraserStateTransition(_instance!, ref eraserState, !eraserState.Value);
break;
case "Eraser (Hold)":
IsManuallySet = true;
_sharedStore!.GetData<Boxed<bool>>(MANUAL_ERASER).Value = true;
EraserStateTransition(_instance!, ref eraserState, true);
break;
}
@ -72,6 +73,7 @@ namespace VoiDPlugins.OutputMode
break;
case "Eraser (Hold)":
_sharedStore!.GetData<Boxed<bool>>(MANUAL_ERASER).Value = false;
EraserStateTransition(_instance!, ref GetEraser(), false);
break;
}
@ -111,7 +113,7 @@ namespace VoiDPlugins.OutputMode
private ref Boxed<bool> GetEraser()
{
return ref _instance!.GetData<Boxed<bool>>(ERASER_STATE);
return ref _sharedStore!.GetData<Boxed<bool>>(ERASER_STATE);
}
}
}

View file

@ -2,8 +2,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;
public const int INSTANCE = 0;
public const int POINTER = 1;
public const int ERASER_STATE = 2;
public const int MANUAL_ERASER = 3;
}
}

View file

@ -1,5 +1,4 @@
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using HidSharp;
using OpenTabletDriver.Plugin;
@ -9,17 +8,15 @@ 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)
public unsafe VMultiInstance(string name, int size)
{
Buffer = GC.AllocateArray<byte>(size, true);
Header = (VMultiReportHeader*)Unsafe.AsPointer(ref Buffer[0]);
_device = Retrieve(name);
_data = new object[32];
}
public void Write()
@ -27,16 +24,6 @@ namespace VoiDPlugins.Library.VMulti
_device.Write(Buffer);
}
public void InitializeData<T>(int i, T data)
{
_data[i] = data!;
}
public unsafe ref T GetData<T>(int i) where T : class
{
return ref Unsafe.AsRef<T>(Unsafe.AsPointer(ref _data[i]));
}
public unsafe void EnableButtonBit(int bit)
{
Header->Buttons = (byte)(Header->Buttons | bit);
@ -84,10 +71,10 @@ namespace VoiDPlugins.Library.VMulti
{
public unsafe T* Pointer { get; }
internal unsafe VMultiInstance(string name, Func<T> initialValue) : base(name, Unsafe.SizeOf<T>())
public unsafe VMultiInstance(string name, T initialValue) : base(name, Unsafe.SizeOf<T>())
{
Pointer = (T*)Unsafe.AsPointer(ref Buffer[0]);
*Pointer = initialValue();
*Pointer = initialValue;
}
}
}

View file

@ -1,30 +0,0 @@
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<string, VMultiInstance> _map = new();
public static VMultiInstance<T> RetrieveVMultiInstance<T>(string name, TabletReference tabletReference, Func<T> initialValue)
where T : unmanaged
{
lock (_syncLock)
{
ref var instance = ref CollectionsMarshal.GetValueRefOrAddDefault(_map, tabletReference.Properties.Name, out var exists);
if (!exists)
instance = new VMultiInstance<T>(name, initialValue);
return (VMultiInstance<T>)instance!;
}
}
public static VMultiInstance RetrieveVMultiInstance(TabletReference tabletReference)
{
return _map[tabletReference.Properties.Name];
}
}
}

View file

@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using OpenTabletDriver.Plugin.Tablet;
namespace VoiDPlugins.Library.VoiD
{
/// <summary>
/// Stores one instance of <typeparamref name="T"/> per <see cref="TabletReference"/>.
/// </summary>
/// <typeparam name="T">A class.</typeparam>
public static class GlobalStore<T> where T : class
{
private static readonly object _syncLock = new();
private static readonly Dictionary<string, T> _map = new();
public static U GetOrInitialize<U>(TabletReference tabletReference, Func<U> initialValue) where U : T
{
lock (_syncLock)
{
ref var instance = ref CollectionsMarshal.GetValueRefOrAddDefault(_map, tabletReference.Properties.Name, out var exists);
if (!exists)
instance = initialValue();
return (U)instance!;
}
}
public static U Get<U>(TabletReference tabletReference) where U : T
{
return (U)_map[tabletReference.Properties.Name];
}
public static T Get(TabletReference tabletReference)
{
return _map[tabletReference.Properties.Name];
}
}
}

View file

@ -0,0 +1,27 @@
using System.Runtime.CompilerServices;
namespace VoiDPlugins.Library.VoiD
{
/// <summary>
/// Fast shared store with support for generic ref returning <see cref="GetData"/>.
/// </summary>
public class SharedStore
{
private readonly object[] _data;
public SharedStore()
{
_data = new object[32];
}
public void InitializeData<T>(int i, T data)
{
_data[i] = data!;
}
public unsafe ref T GetData<T>(int i)
{
return ref Unsafe.AsRef<T>(Unsafe.AsPointer(ref _data[i]));
}
}
}

View file

@ -1,5 +1,2 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<NotPluginProject>true</NotPluginProject>
</PropertyGroup>
</Project>