Merge pull request #10 from X9VoiD/code-cleanup

Code Cleanup
This commit is contained in:
X9VoiD 2020-12-13 05:01:21 +08:00 committed by GitHub
commit d3c0c0d9f1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
59 changed files with 744 additions and 783 deletions

@ -1 +1 @@
Subproject commit 905c0376fd9423558aff23e7608d7a0aa0012144
Subproject commit 603db1945d0d14036ee3f050e7b537e4db902b7e

View file

@ -3,11 +3,9 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using OpenTabletDriver.Plugin;
using OpenTabletDriver.Plugin.Tablet;
using OpenTabletDriver.Plugin.Attributes;
using System.Collections;
namespace ScriptRunner
namespace VoiDPlugins.Binding.ScriptRunner
{
internal static class ScriptRunnerHelper
{
@ -32,7 +30,7 @@ namespace ScriptRunner
}
public string Property { set; get; }
public Action Press => (Action)(() => RunScript(ScriptPathList[Int32.Parse(Property)]));
private void RunScript(string path)
private static void RunScript(string path)
{
try
{

View file

@ -11,7 +11,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../.modules/OpenTabletDriver/OpenTabletDriver.Plugin/OpenTabletDriver.Plugin.csproj" />
<ProjectReference Include="../../.modules/OpenTabletDriver/OpenTabletDriver.Plugin/OpenTabletDriver.Plugin.csproj" />
</ItemGroup>
</Project>

View file

@ -1,4 +1,4 @@
namespace VoiDPlugins.MeL.Core
namespace VoiDPlugins.Filter.MeL.Core
{
internal enum Axis
{

View file

@ -4,7 +4,7 @@ using System.Numerics;
using MathNet.Numerics;
using OpenTabletDriver.Plugin;
namespace VoiDPlugins.MeL.Core
namespace VoiDPlugins.Filter.MeL.Core
{
internal partial class MLCore
{

View file

@ -2,7 +2,7 @@ using System;
using System.Numerics;
using MathNet.Numerics;
namespace VoiDPlugins.MeL.Core
namespace VoiDPlugins.Filter.MeL.Core
{
partial class MLCore
{

View file

@ -2,7 +2,7 @@ using System;
using System.Collections;
using System.Collections.Generic;
namespace VoiDPlugins.MeL.Core
namespace VoiDPlugins.Filter.MeL.Core
{
internal class RingBuffer<T> : IEnumerable<T>
{

View file

@ -1,7 +1,7 @@
using System;
using System.Numerics;
namespace VoiDPlugins.MeL.Core
namespace VoiDPlugins.Filter.MeL.Core
{
public class TimeSeriesPoint
{

View file

@ -3,9 +3,9 @@ using System.Numerics;
using OpenTabletDriver.Plugin;
using OpenTabletDriver.Plugin.Attributes;
using OpenTabletDriver.Plugin.Tablet;
using VoiDPlugins.MeL.Core;
using VoiDPlugins.Filter.MeL.Core;
namespace VoiDPlugins.MeL
namespace VoiDPlugins.Filter.MeL
{
[PluginName("MeL")]
public class MeLFilter : IFilter

View file

@ -3,9 +3,9 @@ using OpenTabletDriver.Plugin;
using OpenTabletDriver.Plugin.Attributes;
using OpenTabletDriver.Plugin.Tablet.Interpolator;
using OpenTabletDriver.Plugin.Timers;
using VoiDPlugins.MeL.Core;
using VoiDPlugins.Filter.MeL.Core;
namespace VoiDPlugins.MeL
namespace VoiDPlugins.Filter.MeL
{
[PluginName("MeL")]
public class MeLInterp : Interpolator

View file

@ -12,7 +12,7 @@
<ItemGroup>
<PackageReference Include="MathNet.Numerics" Version="4.11.0" />
<ProjectReference Include="../.modules/OpenTabletDriver/OpenTabletDriver.Plugin/OpenTabletDriver.Plugin.csproj" />
<ProjectReference Include="../../.modules/OpenTabletDriver/OpenTabletDriver.Plugin/OpenTabletDriver.Plugin.csproj" />
</ItemGroup>
</Project>

View file

@ -3,16 +3,15 @@ using OpenTabletDriver.Plugin.Tablet;
using OpenTabletDriver.Plugin.Attributes;
using System;
using System.Numerics;
using OpenTabletDriver.Plugin.Output;
namespace PrecisionControl
namespace VoiDPlugins.Filter
{
[PluginName("Precision Control")]
public class PrecisionControl: IBinding, IValidateBinding, IFilter
{
public static Vector2 StartingPoint;
public static bool IsActive { set; get; }
public static bool SetPosition { set; get; }
private static Vector2 StartingPoint;
private static bool IsActive { set; get; }
private static bool SetPosition { set; get; }
public string Property { set; get; }
public Action Press => () =>
@ -42,16 +41,8 @@ namespace PrecisionControl
if (IsActive)
{
switch (Info.Driver.OutputMode)
{
case AbsoluteOutputMode _:
var delta = (OriginalPoint - StartingPoint) * Scale;
return StartingPoint + delta;
case RelativeOutputMode _:
return OriginalPoint * Scale;
default:
return OriginalPoint;
}
var delta = (OriginalPoint - StartingPoint) * Scale;
return StartingPoint + delta;
}
else
{

View file

@ -12,7 +12,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../.modules/OpenTabletDriver/OpenTabletDriver.Plugin/OpenTabletDriver.Plugin.csproj" />
<ProjectReference Include="../../.modules/OpenTabletDriver/OpenTabletDriver.Plugin/OpenTabletDriver.Plugin.csproj" />
</ItemGroup>
</Project>

View file

@ -1,4 +1,4 @@
namespace VoiDPlugins
namespace VoiDPlugins.Filter
{
enum ReconstructionAlg
{

View file

@ -4,7 +4,7 @@ using System.Numerics;
using OpenTabletDriver.Plugin.Attributes;
using OpenTabletDriver.Plugin.Tablet;
namespace VoiDPlugins
namespace VoiDPlugins.Filter
{
[PluginName("Reconstructor")]
public class Reconstructor : IFilter

View file

@ -11,7 +11,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../.modules/OpenTabletDriver/OpenTabletDriver.Plugin/OpenTabletDriver.Plugin.csproj" />
<ProjectReference Include="../../.modules/OpenTabletDriver/OpenTabletDriver.Plugin/OpenTabletDriver.Plugin.csproj" />
</ItemGroup>
</Project>

View file

@ -2,7 +2,7 @@ using System;
using System.Collections;
using System.Collections.Generic;
namespace VoiDPlugins
namespace VoiDPlugins.Filter
{
internal class RingBuffer<T> : IEnumerable<T>
{

View file

@ -1,3 +0,0 @@
# MeLFilter
MeLFilter is a general purpose filter which uses machine learning techniques to process cursor points of up to N samples and M degree of complexity. It can be configured to be used as a latency compensation filter, a low latency cursor correction filter, or a smart smoothing filter.

View file

@ -1,5 +0,0 @@
# MeLInterp
MeLInterp is an interpolation plugin for OTD which uses machine learning to upscale report rate to specified target.
Unlike hawku smoothing or devocub antichatter, MeLInterp have a concept of time for the interpolation itself and does not add any additional latency to the cursor except for the computation itself.

View file

@ -1,74 +0,0 @@
# MeL
Machine Learning Plugin for OpenTabletDriver.
## Parts
> ### [MeLFilter](https://github.com/X9VoiD/VoiDPlugins/wiki/MeLFilter)
> ### [MeLInterp](https://github.com/X9VoiD/VoiDPlugins/wiki/MeLInterp)
## Installation
Download MeL from [latest releases.](https://github.com/X9VoiD/VoiDPlugins/releases/latest)
Then copy zip contents to:
| Platform | Path |
| :-- | :-- |
| Windows | `%localappdata%\OpenTabletDriver\Plugins` |
| Linux | `~/.config/OpenTabletDriver/Plugins` |
| MacOS | `$HOME/Library/Application Support/OpenTabletDriver/Plugins` |
## Configuration
These are the different configuration knobs for MeL.
### Offset (only in MeLFilter)
Amount of time in milliseconds to offset the prediction for the next point.
* `Zero Offset` - MeL will apply low latency cursor correction. (to mostly correct MeLInterp's output)
* `Positive Offset` - MeL will try to predict future cursor position.
* `Negative Offset` - MeL will delay cursor position to smooth out movement.
High positive offset may result in inaccurate and erratic cursor movement.
High negative offset does not guarantee smoother cursor movement.
### Samples
Determines how long of a history to keep to feed into the filter.
A sample is defined as an update in cursor position.
* `Sample count` is generally a trade-off between CPU usage and accuracy.
Samples must always be higher than Complexity!
### Complexity
Determines the complexity of prediction to compute by the filter.
### Weight
Determines how much more important the later samples will be. This modifies how strict the MeL is with overshooting.
* A `Weight` of 2 for example will say that the later samples will be two times more important.
A high Weight like 1.5 might introduce jagged edges on the cursor.
A low Weight like 1.1 below will cause overshooting when using with low Complexity.
If you see your cursor getting jagged or jumps back-and-forth, it's because MeL tries too hard to correct itself (due to high `Weight`) when MeL decides that its decisions are too far away from the truth.
## Recommended Settings
**The default values below are optimized for 250+hz tablet devices with hardware smoothing.**
Minimum and Maximum recommended values are a hint for what values are sensible but not necessarily a limit.
| Settings | Min Recommended Value | Max Recommended Value | Default Value |
| :--- | :--- | :--- | :--- |
| Offset | -10 | 10 | **0** |
| Samples | 16 | 25 | **20** |
| Complexity | 1 | 3 | **2** |
| Weight | 1.15 | 1.8 | **1.4** |

View file

@ -1,29 +0,0 @@
# OemKill
Automatically kills OEM tablet driver processes. (Windows only)
## Installation
Download OemKill plugin from [latest releases.](https://github.com/X9VoiD/VoiDPlugins/releases/latest)
Then copy zip contents to:
| Platform | Path |
| :-- | :-- |
| Windows | `%localappdata%\OpenTabletDriver\Plugins` |
| Linux | `~/.config/OpenTabletDriver/Plugins` |
| MacOS | `$HOME/Library/Application Support/OpenTabletDriver/Plugins` |
## Usage
Enable OemKill on Tool tab then restart OTD
## Currently Supported OEM Drivers
| OEM | Support |
| :-- | :--: |
| Wacom | Yes |
| XP Pen | Yes |
| Gaomon | Yes |
| VEIKK | Yes |
| Huion | No |

View file

@ -1,7 +1,7 @@
using System;
using System.Runtime.InteropServices;
namespace VoiDPlugins.TouchEmu
namespace VoiDPlugins.OutputMode
{
using HANDLE = IntPtr;
using HWND = IntPtr;

View file

@ -1,7 +1,7 @@
using System;
using System.Runtime.InteropServices;
namespace VoiDPlugins.TouchEmu
namespace VoiDPlugins.OutputMode
{
public static class Touch
{

View file

@ -12,7 +12,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../.modules/OpenTabletDriver/OpenTabletDriver.Plugin/OpenTabletDriver.Plugin.csproj" />
<ProjectReference Include="../../.modules/OpenTabletDriver/OpenTabletDriver.Plugin/OpenTabletDriver.Plugin.csproj" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,14 @@
using OpenTabletDriver.Plugin;
using OpenTabletDriver.Plugin.Attributes;
using OpenTabletDriver.Plugin.Output;
using OpenTabletDriver.Plugin.Platform.Pointer;
namespace VoiDPlugins.OutputMode
{
[PluginName("Touch Emu"), SupportedPlatform(PluginPlatform.Windows)]
public class TouchOutputMode : AbsoluteOutputMode
{
private readonly IAbsolutePointer TouchPointer = new TouchPointerHandler();
public override IAbsolutePointer Pointer => TouchPointer;
}
}

View file

@ -1,18 +1,8 @@
using System.Numerics;
using OpenTabletDriver.Plugin;
using OpenTabletDriver.Plugin.Attributes;
using OpenTabletDriver.Plugin.Output;
using OpenTabletDriver.Plugin.Platform.Pointer;
namespace VoiDPlugins.TouchEmu
namespace VoiDPlugins.OutputMode
{
[PluginName("Touch Emu"), SupportedPlatform(PluginPlatform.Windows)]
public class TouchOutputMode : AbsoluteOutputMode
{
private readonly IAbsolutePointer TouchPointer = new TouchPointerHandler();
public override IAbsolutePointer Pointer => TouchPointer;
}
public class TouchPointerHandler : IAbsolutePointer, IVirtualTablet
{
private bool _inContact;

View file

@ -0,0 +1,13 @@
using OpenTabletDriver.Plugin.Attributes;
using OpenTabletDriver.Plugin.Output;
using OpenTabletDriver.Plugin.Platform.Pointer;
namespace VoiDPlugins.OutputMode
{
[PluginName("VMulti Absolute Mode")]
public class VMultiAbsoluteMode : AbsoluteOutputMode
{
private readonly VMultiAbsolutePointer pointer = new VMultiAbsolutePointer();
public override IAbsolutePointer Pointer => pointer;
}
}

View file

@ -0,0 +1,13 @@
using OpenTabletDriver.Plugin.Attributes;
using OpenTabletDriver.Plugin.Output;
using OpenTabletDriver.Plugin.Platform.Pointer;
namespace VoiDPlugins.OutputMode
{
[PluginName("VMulti Relative Mode")]
public class VMultiRelativeMode : AbsoluteOutputMode
{
private readonly VMultiRelativePointer pointer = new VMultiRelativePointer();
public override IAbsolutePointer Pointer => pointer;
}
}

View file

@ -0,0 +1,22 @@
using System.Numerics;
using VoiDPlugins.Library.VMulti;
using VoiDPlugins.Library.VMulti.Device;
namespace VoiDPlugins.OutputMode
{
public class VMultiAbsolutePointer : BasePointer<AbsoluteInputReport>
{
public VMultiAbsolutePointer() : base(0x09, "VMultiAbs")
{
ButtonHandler.SetReport(Report);
}
public override void SetPosition(Vector2 pos)
{
var newPos = Convert(pos);
Report.X = (ushort)newPos.X;
Report.Y = (ushort)newPos.Y;
Device.Write(Report.ToBytes());
}
}
}

View file

@ -0,0 +1,31 @@
using System;
using System.Numerics;
using VoiDPlugins.Library.VMulti;
using VoiDPlugins.Library.VMulti.Device;
namespace VoiDPlugins.OutputMode
{
public class VMultiRelativePointer : BasePointer<RelativeInputReport>
{
public VMultiRelativePointer() : base(0x04, "VMultiRel")
{
ButtonHandler.SetReport(Report);
}
private Vector2 lastPos;
private DateTime lastTime = DateTime.UtcNow;
public override void SetPosition(Vector2 pos)
{
var now = DateTime.UtcNow;
if ((now - lastTime).TotalMilliseconds > 20)
{
var newPos = Convert(lastPos - pos);
Report.X = (byte)newPos.X;
Report.Y = (byte)newPos.Y;
Device.Write(Report.ToBytes());
}
lastPos = pos;
lastTime = now;
}
}
}

View file

@ -0,0 +1,19 @@
using System.Collections.Generic;
using OpenTabletDriver.Plugin.Attributes;
using VoiDPlugins.Library.VMulti;
namespace VoiDPlugins.OutputMode
{
[PluginName("VMulti Mode")]
public class VMultiButtonHandler : ButtonHandler
{
private readonly Dictionary<string, int> bindings = new()
{
{ "Left", 1 },
{ "Right", 2 },
{ "Middle", 4 }
};
public override Dictionary<string, int> Bindings => bindings;
}
}

View file

@ -12,8 +12,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="HidSharpCore" Version="1.0.1" />
<ProjectReference Include="../.modules/OpenTabletDriver/OpenTabletDriver.Plugin/OpenTabletDriver.Plugin.csproj" />
<ProjectReference Include="../../.modules/OpenTabletDriver/OpenTabletDriver.Plugin/OpenTabletDriver.Plugin.csproj" />
<ProjectReference Include="../../VoiDPlugins.Library/VMulti/VMulti.csproj" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,13 @@
using OpenTabletDriver.Plugin.Attributes;
using OpenTabletDriver.Plugin.Output;
using OpenTabletDriver.Plugin.Platform.Pointer;
namespace VoiDPlugins.OutputMode
{
[PluginName("Windows Ink Absolute Mode")]
public class WinInkAbsoluteMode : AbsoluteOutputMode
{
private readonly WinInkAbsolutePointer pointer = new WinInkAbsolutePointer();
public override IAbsolutePointer Pointer => pointer;
}
}

View file

@ -0,0 +1,13 @@
using OpenTabletDriver.Plugin.Attributes;
using OpenTabletDriver.Plugin.Output;
using OpenTabletDriver.Plugin.Platform.Pointer;
namespace VoiDPlugins.OutputMode
{
[PluginName("Windows Ink Relative Mode")]
public class WinInkRelativeMode : AbsoluteOutputMode
{
private readonly WinInkRelativePointer pointer = new WinInkRelativePointer();
public override IAbsolutePointer Pointer => pointer;
}
}

View file

@ -0,0 +1,29 @@
using System.Numerics;
using OpenTabletDriver.Plugin.Platform.Pointer;
using VoiDPlugins.Library.VMulti;
using VoiDPlugins.Library.VMulti.Device;
namespace VoiDPlugins.OutputMode
{
public class WinInkAbsolutePointer : BasePointer<DigitizerInputReport>, IVirtualTablet
{
public WinInkAbsolutePointer() : base(0x05, "WindowsInk")
{
WinInkButtonHandler.SetReport(Report);
WinInkButtonHandler.SetDevice(Device);
}
public override void SetPosition(Vector2 pos)
{
var newPos = Convert(pos);
Report.X = (ushort)newPos.X;
Report.Y = (ushort)newPos.Y;
Device.Write(Report.ToBytes());
}
public void SetPressure(float percentage)
{
Report.Pressure = (ushort)(percentage * 8191);
}
}
}

View file

@ -0,0 +1,38 @@
using System;
using System.Numerics;
using OpenTabletDriver.Plugin.Platform.Pointer;
using VoiDPlugins.Library.VMulti;
using VoiDPlugins.Library.VMulti.Device;
namespace VoiDPlugins.OutputMode
{
public class WinInkRelativePointer : BasePointer<DigitizerInputReport>, IVirtualTablet
{
public WinInkRelativePointer() : base(0x05, "WindowsInk")
{
WinInkButtonHandler.SetReport(Report);
WinInkButtonHandler.SetDevice(Device);
}
private Vector2 lastPos;
private DateTime lastTime = DateTime.UtcNow;
public override void SetPosition(Vector2 pos)
{
var now = DateTime.UtcNow;
if ((now - lastTime).TotalMilliseconds > 100)
{
var newPos = Convert(lastPos - pos);
Report.X = (byte)newPos.X;
Report.Y = (byte)newPos.Y;
Device.Write(Report.ToBytes());
}
lastPos = pos;
lastTime = now;
}
public void SetPressure(float percentage)
{
Report.Pressure = (ushort)(percentage * 8191);
}
}
}

View file

@ -0,0 +1,126 @@
using System.Collections.Generic;
using HidSharp;
using OpenTabletDriver.Plugin.Attributes;
using VoiDPlugins.Library.VMulti;
using VoiDPlugins.Library.VMulti.Device;
namespace VoiDPlugins.OutputMode
{
[PluginName("Windows Ink")]
public class WinInkButtonHandler : ButtonHandler
{
public override Dictionary<string, int> Bindings => null;
public readonly static string[] validProperties = new string[]
{
"Pen Tip",
"Pen Button",
"Eraser (Toggle)",
"Eraser (Hold)"
};
public override string[] ValidProperties => validProperties;
private enum Button : int
{
Press = 1,
Barrel = 2,
Eraser = 4,
Invert = 8,
InRange = 16
}
private bool EraserState;
private static HidStream Device;
private static new DigitizerInputReport Report;
public override void Press(string input)
{
switch (input)
{
case "Pen Tip":
{
EnableBit((int)(EraserState ? Button.Eraser : Button.Press));
break;
}
case "Pen Button":
{
EnableBit((int)Button.Barrel);
break;
}
case "Eraser (Toggle)":
{
if (EraserState)
{
DisableBit((int)Button.Invert);
EraserState = false;
StateChange();
}
else
{
EnableBit((int)Button.Invert);
DisableBit((int)Button.Press);
EraserState = true;
StateChange();
}
break;
}
case "Eraser (Hold)":
{
EnableBit((int)Button.Invert);
DisableBit((int)Button.Press);
EraserState = true;
StateChange();
break;
}
}
}
public override void Release(string input)
{
switch (input)
{
case "Pen Tip":
{
DisableBit((int)Button.Press);
DisableBit((int)Button.Eraser);
break;
}
case "Pen Button":
{
DisableBit((int)Button.Barrel);
break;
}
case "Eraser (Hold)":
{
DisableBit((int)Button.Invert);
EraserState = false;
StateChange();
break;
}
}
}
private static void StateChange()
{
var buttons = Report.Buttons;
var pressure = Report.Pressure;
Report.Buttons = 0;
Report.Pressure = 0;
Device.Write(Report.ToBytes());
Report.Buttons = buttons;
Report.Pressure = pressure;
}
public static void SetReport(DigitizerInputReport Report)
{
ButtonHandler.SetReport(Report);
WinInkButtonHandler.Report = Report;
EnableBit((int)Button.InRange);
}
public static void SetDevice(HidStream device)
{
Device = device;
}
}
}

View file

@ -12,8 +12,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="HidSharpCore" Version="1.0.1" />
<ProjectReference Include="../.modules/OpenTabletDriver/OpenTabletDriver.Plugin/OpenTabletDriver.Plugin.csproj" />
<ProjectReference Include="../../.modules/OpenTabletDriver/OpenTabletDriver.Plugin/OpenTabletDriver.Plugin.csproj" />
<ProjectReference Include="../../VoiDPlugins.Library/VMulti/VMulti.csproj" />
</ItemGroup>
</Project>

View file

@ -1,24 +0,0 @@
# PrecisionControl
Adds the ability to switch sensitivity on runtime like a DPI switch.
## Installation
Download PrecisionControl plugin from [latest releases.](https://github.com/X9VoiD/VoiDPlugins/releases/latest)
Then copy zip contents to:
| Platform | Path |
| :-- | :-- |
| Windows | `%localappdata%\OpenTabletDriver\Plugins` |
| Linux | `~/.config/OpenTabletDriver/Plugins` |
| MacOS | `$HOME/Library/Application Support/OpenTabletDriver/Plugins` |
## Usage
Enable PrecisionControl on Filter tab then set desired `PrecisionMultiplier`.
It should then be binded to any of the bindable buttons by right-clicking, then:
- Set Binding Type to `Precision Control`
- Set Binding Property to either `Toggle` or `Hold`

View file

@ -1,4 +1,4 @@
namespace VoiDPlugins.OemKill
namespace VoiDPlugins.Tool
{
class IndexedInf
{

View file

@ -1,6 +1,6 @@
using System.Collections.Generic;
namespace VoiDPlugins.OemKill
namespace VoiDPlugins.Tool
{
internal static class OemData
{

View file

@ -9,10 +9,10 @@ using System.Threading;
using OpenTabletDriver.Plugin;
using OpenTabletDriver.Plugin.Attributes;
namespace VoiDPlugins.OemKill
namespace VoiDPlugins.Tool
{
[PluginName("OEM Kill"), SupportedPlatform(PluginPlatform.Windows)]
public class OemKillTool : ITool
public class OemKill : ITool
{
public bool Initialize()
{

View file

@ -11,7 +11,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../.modules/OpenTabletDriver/OpenTabletDriver.Plugin/OpenTabletDriver.Plugin.csproj" />
<ProjectReference Include="../../.modules/OpenTabletDriver/OpenTabletDriver.Plugin/OpenTabletDriver.Plugin.csproj" />
</ItemGroup>
</Project>

View file

@ -1,29 +0,0 @@
## TouchEmu
Emulates touch input on Windows 10 and enables all features available for touch devices except multi-touch:
> ##### Natural Scrolling
> ##### Hold to Right Click
> ##### Hold-and-Drag to Select
Provides one new output mode
TouchEmu
## Installation
Download TouchEmu from [latest releases.](https://github.com/X9VoiD/VoiDPlugins/releases/latest)
Then copy zip contents to:
| Platform | Path |
| :-- | :-- |
| Windows | `%localappdata%\OpenTabletDriver\Plugins` |
| Linux | `~/.config/OpenTabletDriver/Plugins` |
| MacOS | `$HOME/Library/Application Support/OpenTabletDriver/Plugins` |
## Usage
Enable TouchEmu by selecting it as an output mode on the OutputModeSelector of Output tab.

View file

@ -1,26 +0,0 @@
## VMultiMode
VMultiMode is a plugin providing two new output modes
VMulti Absolute Output Mode
VMulti Relative Output Mode
## Requirements
Install [VMulti](https://github.com/X9VoiD/vmulti-bin/releases/latest)
## Installation
Download VMultiMode plugin from [latest releases.](https://github.com/X9VoiD/VoiDPlugins/releases/latest)
Then copy zip contents to:
| Platform | Path |
| :-- | :-- |
| Windows | `%localappdata%\OpenTabletDriver\Plugins` |
| Linux | `~/.config/OpenTabletDriver/Plugins` |
| MacOS | `$HOME/Library/Application Support/OpenTabletDriver/Plugins` |
## Usage
Enable VMultiMode by selecting it as an output mode on the OutputModeSelector of Output tab.

View file

@ -1,156 +0,0 @@
using System.Numerics;
using HidSharp;
using OpenTabletDriver.Plugin;
using OpenTabletDriver.Plugin.Platform.Display;
using OpenTabletDriver.Plugin.Platform.Pointer;
namespace VoiDPlugins.VMultiMode
{
public static class VMulti
{
public abstract class VMultiReport
{
public byte VMultiID; // ID to communicate to the Mouse device
public byte ReportLength; // Size of the report in bytes.
public byte ReportID; // ID of the report.
public byte Buttons; // Byte with switches for mouse buttons
public abstract byte Size { get; }
public abstract byte[] ToBytes();
}
public class VMultiAbsReport : VMultiReport
{
public ushort X; // X position of the mouse from 0 to 32767
public ushort Y; // Y position of the mouse from 0 to 32767
public ushort Pressure; // Pressure of the mouse? from 0 to 8191
public override byte[] ToBytes()
{
var bytes = new byte[Size];
bytes[0] = VMultiID;
bytes[1] = ReportLength;
bytes[2] = ReportID;
bytes[3] = Buttons;
bytes[4] = (byte)(X & 0xFF);
bytes[5] = (byte)((X & 0xFF00) >> 8);
bytes[6] = (byte)(Y & 0xFF);
bytes[7] = (byte)((Y & 0xFF00) >> 8);
bytes[8] = (byte)(Pressure & 0xFF);
bytes[9] = (byte)((Pressure & 0xFF00) >> 8);
return bytes;
}
public override byte Size => 10;
}
public class VMultiRelReport : VMultiReport
{
public byte X; // X position of the mouse from -127 to 127
public byte Y; // Y position of the mouse from -127 to 127
public byte WheelPos; // Wheel position of the mouse from -127 to 127
public override byte[] ToBytes()
{
var bytes = new byte[Size];
bytes[0] = VMultiID;
bytes[1] = ReportLength;
bytes[2] = ReportID;
bytes[3] = Buttons;
bytes[4] = X;
bytes[5] = Y;
bytes[6] = WheelPos;
return bytes;
}
public override byte Size => 7;
}
public enum ButtonMask : int
{
Left = 1,
Right = 2,
Middle = 4,
}
public class VMultiHandler<T> where T : VMultiReport, new()
{
protected T Report;
protected HidStream VMultiDev;
protected Vector2 ScreenMax, ScreenToVMulti;
private readonly IVirtualScreen VirtualScreen = (Info.Driver as IVirtualDisplayDriver).VirtualScreen;
protected void Init(string Name, byte ReportID)
{
Report = new T()
{
VMultiID = 0x40,
ReportID = ReportID
};
Report.ReportLength = Report.Size;
VMultiDev = null;
foreach (var device in DeviceList.Local.GetHidDevices(productID: 47820))
{
if (device.GetMaxOutputReportLength() == 65 && device.GetMaxInputReportLength() == 65)
{
device.TryOpen(out VMultiDev);
if (VMultiDev != null)
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");
}
ScreenMax = new Vector2(VirtualScreen.Width, VirtualScreen.Height);
ScreenToVMulti = ScreenMax / 32767;
}
public void MouseDown(MouseButton button)
{
switch (button)
{
case MouseButton.Left:
EnableBit(ButtonMask.Left);
break;
case MouseButton.Right:
EnableBit(ButtonMask.Right);
break;
case MouseButton.Middle:
EnableBit(ButtonMask.Middle);
break;
}
VMultiDev.Write(Report.ToBytes());
}
public void MouseUp(MouseButton button)
{
switch (button)
{
case MouseButton.Left:
DisableBit(ButtonMask.Left);
break;
case MouseButton.Right:
DisableBit(ButtonMask.Right);
break;
case MouseButton.Middle:
DisableBit(ButtonMask.Middle);
break;
}
VMultiDev.Write(Report.ToBytes());
}
private void EnableBit(ButtonMask mask)
{
Report.Buttons = (byte)(Report.Buttons | (int)mask);
}
private void DisableBit(ButtonMask mask)
{
Report.Buttons = (byte)(Report.Buttons & ~(int)mask);
}
}
}
}

View file

@ -1,60 +0,0 @@
using System.Numerics;
using OpenTabletDriver.Plugin;
using OpenTabletDriver.Plugin.Attributes;
using OpenTabletDriver.Plugin.Output;
using OpenTabletDriver.Plugin.Platform.Pointer;
using static VoiDPlugins.VMultiMode.VMulti;
namespace VoiDPlugins.VMultiMode
{
[PluginName("VMulti Absolute Output Mode"), SupportedPlatform(PluginPlatform.Windows)]
public class VMultiAbsMode : AbsoluteOutputMode
{
private readonly IAbsolutePointer AbsHandler = new VMultiAbsHandler();
public override IAbsolutePointer Pointer => AbsHandler;
}
[PluginName("VMulti Relative Output Mode"), SupportedPlatform(PluginPlatform.Windows)]
public class VMultiRelMode : AbsoluteOutputMode
{
private readonly IAbsolutePointer RelHandler = new VMultiRelHandler();
public override IAbsolutePointer Pointer => RelHandler;
}
public class VMultiAbsHandler : VMultiHandler<VMultiAbsReport>, IAbsolutePointer
{
public VMultiAbsHandler()
{
Init("VMultiAbs", 0x09);
}
public void SetPosition(Vector2 pos)
{
var newPos = pos / ScreenToVMulti;
Report.X = (ushort)newPos.X;
Report.Y = (ushort)newPos.Y;
VMultiDev.Write(Report.ToBytes());
}
}
public class VMultiRelHandler : VMultiHandler<VMultiRelReport>, IAbsolutePointer
{
private ushort prevX, prevY;
public VMultiRelHandler()
{
Init("VMultiRel", 0x04);
}
public void SetPosition(Vector2 pos)
{
var X = (ushort)pos.X;
var Y = (ushort)pos.Y;
Report.X = (byte)(X - prevX);
Report.Y = (byte)(Y - prevY);
prevX = X;
prevY = Y;
VMultiDev.Write(Report.ToBytes());
}
}
}

View file

@ -0,0 +1,39 @@
using System.Numerics;
using HidSharp;
using OpenTabletDriver.Plugin;
using OpenTabletDriver.Plugin.Attributes;
using OpenTabletDriver.Plugin.Platform.Display;
using OpenTabletDriver.Plugin.Platform.Pointer;
using VoiDPlugins.Library.VMulti.Device;
namespace VoiDPlugins.Library.VMulti
{
[PluginIgnore]
public abstract class BasePointer<T> : IAbsolutePointer where T : Report, new()
{
public T Report;
protected readonly HidStream Device;
private Vector2 ScreenToVMulti;
public BasePointer(byte ReportID, string Name)
{
Report = new T
{
ReportID = ReportID
};
Device = VMultiDevice.Retrieve(Name);
var VirtualScreen = (Info.Driver as IVirtualDisplayDriver).VirtualScreen;
ScreenToVMulti = new Vector2(VirtualScreen.Width, VirtualScreen.Height) / 32767;
}
protected Vector2 Convert(Vector2 pos)
{
return pos / ScreenToVMulti;
}
public abstract void SetPosition(Vector2 pos);
}
}

View file

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using OpenTabletDriver.Plugin;
using OpenTabletDriver.Plugin.Attributes;
using VoiDPlugins.Library.VMulti.Device;
namespace VoiDPlugins.Library.VMulti
{
[PluginIgnore]
public abstract class ButtonHandler : IBinding, IValidateBinding
{
protected static Report Report;
public abstract Dictionary<string, int> Bindings { get; }
[Property("Property")]
public string Property { get; set; }
public virtual string[] ValidProperties => Bindings.Keys.ToArray();
Action IBinding.Press => () => Press(Property);
Action IBinding.Release => () => Release(Property);
public virtual void Press(string input)
{
EnableBit(Bindings[input]);
}
public virtual void Release(string input)
{
DisableBit(Bindings[input]);
}
public static void SetReport(Report report)
{
Report = report;
}
public static void EnableBit(int bit)
{
Report.Buttons = (byte)(Report.Buttons | bit);
}
public static void DisableBit(int bit)
{
Report.Buttons = (byte)(Report.Buttons & ~bit);
}
}
}

View file

@ -0,0 +1,27 @@
namespace VoiDPlugins.Library.VMulti.Device
{
public class AbsoluteInputReport : Report
{
public ushort X; // X position of the mouse from 0 to 32767
public ushort Y; // Y position of the mouse from 0 to 32767
public ushort Pressure; // Pressure of the mouse? from 0 to 8191
public override byte[] ToBytes()
{
var bytes = new byte[Size];
bytes[0] = VMultiID;
bytes[1] = ReportLength;
bytes[2] = ReportID;
bytes[3] = Buttons;
bytes[4] = (byte)(X & 0xFF);
bytes[5] = (byte)((X & 0xFF00) >> 8);
bytes[6] = (byte)(Y & 0xFF);
bytes[7] = (byte)((Y & 0xFF00) >> 8);
bytes[8] = (byte)(Pressure & 0xFF);
bytes[9] = (byte)((Pressure & 0xFF00) >> 8);
return bytes;
}
public override byte Size => 10;
}
}

View file

@ -0,0 +1,30 @@
namespace VoiDPlugins.Library.VMulti.Device
{
public class DigitizerInputReport : Report
{
public ushort X; // X position of the pen from 0 to 32767
public ushort Y; // Y position of the pen from 0 to 32767
public ushort Pressure; // Pressure level from 0 to 8191
public byte XTilt; // X tilt of the pen from -127 to 127
public byte YTilt; // Y tilt of the pen from -127 to 127
public override byte[] ToBytes()
{
var bytes = new byte[Size];
bytes[0] = VMultiID;
bytes[1] = ReportLength;
bytes[2] = ReportID;
bytes[3] = Buttons;
bytes[4] = (byte)(X & 0xFF);
bytes[5] = (byte)((X & 0xFF00) >> 8);
bytes[6] = (byte)(Y & 0xFF);
bytes[7] = (byte)((Y & 0xFF00) >> 8);
bytes[8] = (byte)(Pressure & 0xFF);
bytes[9] = (byte)((Pressure & 0xFF00) >> 8);
bytes[10] = XTilt;
bytes[11] = YTilt;
return bytes;
}
public override byte Size => 12;
}
}

View file

@ -0,0 +1,24 @@
namespace VoiDPlugins.Library.VMulti.Device
{
public class RelativeInputReport : Report
{
public byte X; // X position of the mouse from -127 to 127
public byte Y; // Y position of the mouse from -127 to 127
public byte WheelPos; // Wheel position of the mouse from -127 to 127
public override byte[] ToBytes()
{
var bytes = new byte[Size];
bytes[0] = VMultiID;
bytes[1] = ReportLength;
bytes[2] = ReportID;
bytes[3] = Buttons;
bytes[4] = X;
bytes[5] = Y;
bytes[6] = WheelPos;
return bytes;
}
public override byte Size => 7;
}
}

View file

@ -0,0 +1,12 @@
namespace VoiDPlugins.Library.VMulti.Device
{
public abstract class Report
{
public byte VMultiID = 0x40;
public byte ReportID;
public byte Buttons;
public byte ReportLength => (byte)(Size - 1);
public abstract byte Size { get; }
public abstract byte[] ToBytes();
}
}

View file

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net5</TargetFrameworks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<DebugType>none</DebugType>
<DebugSymbols>false</DebugSymbols>
<CopyOutputSymbolsToOutputDirectory>false</CopyOutputSymbolsToOutputDirectory>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../.modules/OpenTabletDriver/OpenTabletDriver.Plugin/OpenTabletDriver.Plugin.csproj" />
<PackageReference Include="HidSharpCore" Version="1.1.0" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,31 @@
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;
}
}
}

View file

@ -1,67 +1,167 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30309.148
# Visual Studio 15
VisualStudioVersion = 15.0.26124.0
MinimumVisualStudioVersion = 15.0.26124.0
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OemKill", "OemKill\OemKill.csproj", "{4EC8FA2D-0CCC-4FC3-A32A-BC063924A803}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Binding", "Binding", "{CFC2BC9E-CFD6-4B01-946D-43C26E6C2108}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TouchEmu", "TouchEmu\TouchEmu.csproj", "{FC135341-4870-4555-8917-7248CFE07FCC}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptRunner", "Binding\ScriptRunner\ScriptRunner.csproj", "{33F0E415-AB65-43F2-8AE2-3462B56B9E91}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WindowsInk", "WindowsInk\WindowsInk.csproj", "{5DDEBB0A-D359-49F4-B1AE-7A13DB28987B}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Filter", "Filter", "{6EFE4444-C6E7-4743-8EE5-7A2BE7493457}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VMultiMode", "VMultiMode\VMultiMode.csproj", "{7D086384-9E50-45A1-BD7A-ECF44CB31223}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MeL", "Filter\MeL\MeL.csproj", "{DA5A9F04-F22A-46EE-A26D-B308548BC232}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MeL", "MeL\MeL.csproj", "{F0931C43-4A63-4CDB-9B5F-A8DC50557109}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PrecisionControl", "Filter\PrecisionControl\PrecisionControl.csproj", "{4D72A437-03CB-4869-9E34-7424A3CFCF46}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PrecisionControl", "PrecisionControl\PrecisionControl.csproj", "{3315D19C-54CB-4947-8CF5-54953870FB4F}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Reconstructor", "Filter\Reconstructor\Reconstructor.csproj", "{A71AF919-AC3C-4F99-9525-6A48A69502A0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScriptRunner", "ScriptRunner\ScriptRunner.csproj", "{7B727343-91A8-44DA-AF2A-9FC8A0986AA4}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "OutputMode", "OutputMode", "{44DF0884-9B34-45CA-92B7-2D57DCA3A1A8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Reconstructor", "Reconstructor\Reconstructor.csproj", "{22628430-4AC4-4F9C-BAF4-229092C90979}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TouchEmu", "OutputMode\TouchEmu\TouchEmu.csproj", "{40F46E98-3485-4805-A70A-EAC5C6E0BACC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VMultiMode", "OutputMode\VMultiMode\VMultiMode.csproj", "{A0101CA9-B8C8-4715-81E6-0A1EB34CA739}"
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}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{4EC8FA2D-0CCC-4FC3-A32A-BC063924A803}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4EC8FA2D-0CCC-4FC3-A32A-BC063924A803}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4EC8FA2D-0CCC-4FC3-A32A-BC063924A803}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4EC8FA2D-0CCC-4FC3-A32A-BC063924A803}.Release|Any CPU.Build.0 = Release|Any CPU
{FC135341-4870-4555-8917-7248CFE07FCC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FC135341-4870-4555-8917-7248CFE07FCC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC135341-4870-4555-8917-7248CFE07FCC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FC135341-4870-4555-8917-7248CFE07FCC}.Release|Any CPU.Build.0 = Release|Any CPU
{5DDEBB0A-D359-49F4-B1AE-7A13DB28987B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5DDEBB0A-D359-49F4-B1AE-7A13DB28987B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5DDEBB0A-D359-49F4-B1AE-7A13DB28987B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5DDEBB0A-D359-49F4-B1AE-7A13DB28987B}.Release|Any CPU.Build.0 = Release|Any CPU
{7D086384-9E50-45A1-BD7A-ECF44CB31223}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7D086384-9E50-45A1-BD7A-ECF44CB31223}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7D086384-9E50-45A1-BD7A-ECF44CB31223}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7D086384-9E50-45A1-BD7A-ECF44CB31223}.Release|Any CPU.Build.0 = Release|Any CPU
{F0931C43-4A63-4CDB-9B5F-A8DC50557109}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F0931C43-4A63-4CDB-9B5F-A8DC50557109}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F0931C43-4A63-4CDB-9B5F-A8DC50557109}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F0931C43-4A63-4CDB-9B5F-A8DC50557109}.Release|Any CPU.Build.0 = Release|Any CPU
{3315D19C-54CB-4947-8CF5-54953870FB4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3315D19C-54CB-4947-8CF5-54953870FB4F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3315D19C-54CB-4947-8CF5-54953870FB4F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3315D19C-54CB-4947-8CF5-54953870FB4F}.Release|Any CPU.Build.0 = Release|Any CPU
{7B727343-91A8-44DA-AF2A-9FC8A0986AA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7B727343-91A8-44DA-AF2A-9FC8A0986AA4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7B727343-91A8-44DA-AF2A-9FC8A0986AA4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7B727343-91A8-44DA-AF2A-9FC8A0986AA4}.Release|Any CPU.Build.0 = Release|Any CPU
{22628430-4AC4-4F9C-BAF4-229092C90979}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{22628430-4AC4-4F9C-BAF4-229092C90979}.Debug|Any CPU.Build.0 = Debug|Any CPU
{22628430-4AC4-4F9C-BAF4-229092C90979}.Release|Any CPU.ActiveCfg = Release|Any CPU
{22628430-4AC4-4F9C-BAF4-229092C90979}.Release|Any CPU.Build.0 = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {2BABACBE-E6E4-4641-BD76-927BFF428316}
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{33F0E415-AB65-43F2-8AE2-3462B56B9E91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{33F0E415-AB65-43F2-8AE2-3462B56B9E91}.Debug|Any CPU.Build.0 = Debug|Any CPU
{33F0E415-AB65-43F2-8AE2-3462B56B9E91}.Debug|x64.ActiveCfg = Debug|Any CPU
{33F0E415-AB65-43F2-8AE2-3462B56B9E91}.Debug|x64.Build.0 = Debug|Any CPU
{33F0E415-AB65-43F2-8AE2-3462B56B9E91}.Debug|x86.ActiveCfg = Debug|Any CPU
{33F0E415-AB65-43F2-8AE2-3462B56B9E91}.Debug|x86.Build.0 = Debug|Any CPU
{33F0E415-AB65-43F2-8AE2-3462B56B9E91}.Release|Any CPU.ActiveCfg = Release|Any CPU
{33F0E415-AB65-43F2-8AE2-3462B56B9E91}.Release|Any CPU.Build.0 = Release|Any CPU
{33F0E415-AB65-43F2-8AE2-3462B56B9E91}.Release|x64.ActiveCfg = Release|Any CPU
{33F0E415-AB65-43F2-8AE2-3462B56B9E91}.Release|x64.Build.0 = Release|Any CPU
{33F0E415-AB65-43F2-8AE2-3462B56B9E91}.Release|x86.ActiveCfg = Release|Any CPU
{33F0E415-AB65-43F2-8AE2-3462B56B9E91}.Release|x86.Build.0 = Release|Any CPU
{DA5A9F04-F22A-46EE-A26D-B308548BC232}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DA5A9F04-F22A-46EE-A26D-B308548BC232}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DA5A9F04-F22A-46EE-A26D-B308548BC232}.Debug|x64.ActiveCfg = Debug|Any CPU
{DA5A9F04-F22A-46EE-A26D-B308548BC232}.Debug|x64.Build.0 = Debug|Any CPU
{DA5A9F04-F22A-46EE-A26D-B308548BC232}.Debug|x86.ActiveCfg = Debug|Any CPU
{DA5A9F04-F22A-46EE-A26D-B308548BC232}.Debug|x86.Build.0 = Debug|Any CPU
{DA5A9F04-F22A-46EE-A26D-B308548BC232}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DA5A9F04-F22A-46EE-A26D-B308548BC232}.Release|Any CPU.Build.0 = Release|Any CPU
{DA5A9F04-F22A-46EE-A26D-B308548BC232}.Release|x64.ActiveCfg = Release|Any CPU
{DA5A9F04-F22A-46EE-A26D-B308548BC232}.Release|x64.Build.0 = Release|Any CPU
{DA5A9F04-F22A-46EE-A26D-B308548BC232}.Release|x86.ActiveCfg = Release|Any CPU
{DA5A9F04-F22A-46EE-A26D-B308548BC232}.Release|x86.Build.0 = Release|Any CPU
{4D72A437-03CB-4869-9E34-7424A3CFCF46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4D72A437-03CB-4869-9E34-7424A3CFCF46}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4D72A437-03CB-4869-9E34-7424A3CFCF46}.Debug|x64.ActiveCfg = Debug|Any CPU
{4D72A437-03CB-4869-9E34-7424A3CFCF46}.Debug|x64.Build.0 = Debug|Any CPU
{4D72A437-03CB-4869-9E34-7424A3CFCF46}.Debug|x86.ActiveCfg = Debug|Any CPU
{4D72A437-03CB-4869-9E34-7424A3CFCF46}.Debug|x86.Build.0 = Debug|Any CPU
{4D72A437-03CB-4869-9E34-7424A3CFCF46}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4D72A437-03CB-4869-9E34-7424A3CFCF46}.Release|Any CPU.Build.0 = Release|Any CPU
{4D72A437-03CB-4869-9E34-7424A3CFCF46}.Release|x64.ActiveCfg = Release|Any CPU
{4D72A437-03CB-4869-9E34-7424A3CFCF46}.Release|x64.Build.0 = Release|Any CPU
{4D72A437-03CB-4869-9E34-7424A3CFCF46}.Release|x86.ActiveCfg = Release|Any CPU
{4D72A437-03CB-4869-9E34-7424A3CFCF46}.Release|x86.Build.0 = Release|Any CPU
{A71AF919-AC3C-4F99-9525-6A48A69502A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A71AF919-AC3C-4F99-9525-6A48A69502A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A71AF919-AC3C-4F99-9525-6A48A69502A0}.Debug|x64.ActiveCfg = Debug|Any CPU
{A71AF919-AC3C-4F99-9525-6A48A69502A0}.Debug|x64.Build.0 = Debug|Any CPU
{A71AF919-AC3C-4F99-9525-6A48A69502A0}.Debug|x86.ActiveCfg = Debug|Any CPU
{A71AF919-AC3C-4F99-9525-6A48A69502A0}.Debug|x86.Build.0 = Debug|Any CPU
{A71AF919-AC3C-4F99-9525-6A48A69502A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A71AF919-AC3C-4F99-9525-6A48A69502A0}.Release|Any CPU.Build.0 = Release|Any CPU
{A71AF919-AC3C-4F99-9525-6A48A69502A0}.Release|x64.ActiveCfg = Release|Any CPU
{A71AF919-AC3C-4F99-9525-6A48A69502A0}.Release|x64.Build.0 = Release|Any CPU
{A71AF919-AC3C-4F99-9525-6A48A69502A0}.Release|x86.ActiveCfg = Release|Any CPU
{A71AF919-AC3C-4F99-9525-6A48A69502A0}.Release|x86.Build.0 = Release|Any CPU
{40F46E98-3485-4805-A70A-EAC5C6E0BACC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{40F46E98-3485-4805-A70A-EAC5C6E0BACC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{40F46E98-3485-4805-A70A-EAC5C6E0BACC}.Debug|x64.ActiveCfg = Debug|Any CPU
{40F46E98-3485-4805-A70A-EAC5C6E0BACC}.Debug|x64.Build.0 = Debug|Any CPU
{40F46E98-3485-4805-A70A-EAC5C6E0BACC}.Debug|x86.ActiveCfg = Debug|Any CPU
{40F46E98-3485-4805-A70A-EAC5C6E0BACC}.Debug|x86.Build.0 = Debug|Any CPU
{40F46E98-3485-4805-A70A-EAC5C6E0BACC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{40F46E98-3485-4805-A70A-EAC5C6E0BACC}.Release|Any CPU.Build.0 = Release|Any CPU
{40F46E98-3485-4805-A70A-EAC5C6E0BACC}.Release|x64.ActiveCfg = Release|Any CPU
{40F46E98-3485-4805-A70A-EAC5C6E0BACC}.Release|x64.Build.0 = Release|Any CPU
{40F46E98-3485-4805-A70A-EAC5C6E0BACC}.Release|x86.ActiveCfg = Release|Any CPU
{40F46E98-3485-4805-A70A-EAC5C6E0BACC}.Release|x86.Build.0 = Release|Any CPU
{A0101CA9-B8C8-4715-81E6-0A1EB34CA739}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A0101CA9-B8C8-4715-81E6-0A1EB34CA739}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A0101CA9-B8C8-4715-81E6-0A1EB34CA739}.Debug|x64.ActiveCfg = Debug|Any CPU
{A0101CA9-B8C8-4715-81E6-0A1EB34CA739}.Debug|x64.Build.0 = Debug|Any CPU
{A0101CA9-B8C8-4715-81E6-0A1EB34CA739}.Debug|x86.ActiveCfg = Debug|Any CPU
{A0101CA9-B8C8-4715-81E6-0A1EB34CA739}.Debug|x86.Build.0 = Debug|Any CPU
{A0101CA9-B8C8-4715-81E6-0A1EB34CA739}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A0101CA9-B8C8-4715-81E6-0A1EB34CA739}.Release|Any CPU.Build.0 = Release|Any CPU
{A0101CA9-B8C8-4715-81E6-0A1EB34CA739}.Release|x64.ActiveCfg = Release|Any CPU
{A0101CA9-B8C8-4715-81E6-0A1EB34CA739}.Release|x64.Build.0 = Release|Any CPU
{A0101CA9-B8C8-4715-81E6-0A1EB34CA739}.Release|x86.ActiveCfg = Release|Any CPU
{A0101CA9-B8C8-4715-81E6-0A1EB34CA739}.Release|x86.Build.0 = Release|Any CPU
{D8DBD60E-BE5C-43DE-AEB6-D6ADBAC3BE8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D8DBD60E-BE5C-43DE-AEB6-D6ADBAC3BE8C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D8DBD60E-BE5C-43DE-AEB6-D6ADBAC3BE8C}.Debug|x64.ActiveCfg = Debug|Any CPU
{D8DBD60E-BE5C-43DE-AEB6-D6ADBAC3BE8C}.Debug|x64.Build.0 = Debug|Any CPU
{D8DBD60E-BE5C-43DE-AEB6-D6ADBAC3BE8C}.Debug|x86.ActiveCfg = Debug|Any CPU
{D8DBD60E-BE5C-43DE-AEB6-D6ADBAC3BE8C}.Debug|x86.Build.0 = Debug|Any CPU
{D8DBD60E-BE5C-43DE-AEB6-D6ADBAC3BE8C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D8DBD60E-BE5C-43DE-AEB6-D6ADBAC3BE8C}.Release|Any CPU.Build.0 = Release|Any CPU
{D8DBD60E-BE5C-43DE-AEB6-D6ADBAC3BE8C}.Release|x64.ActiveCfg = Release|Any CPU
{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
{E6A1BA35-D3D4-4F28-9B59-FA946B3039C7}.Debug|x64.Build.0 = Debug|Any CPU
{E6A1BA35-D3D4-4F28-9B59-FA946B3039C7}.Debug|x86.ActiveCfg = Debug|Any CPU
{E6A1BA35-D3D4-4F28-9B59-FA946B3039C7}.Debug|x86.Build.0 = Debug|Any CPU
{E6A1BA35-D3D4-4F28-9B59-FA946B3039C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E6A1BA35-D3D4-4F28-9B59-FA946B3039C7}.Release|Any CPU.Build.0 = Release|Any CPU
{E6A1BA35-D3D4-4F28-9B59-FA946B3039C7}.Release|x64.ActiveCfg = Release|Any CPU
{E6A1BA35-D3D4-4F28-9B59-FA946B3039C7}.Release|x64.Build.0 = Release|Any CPU
{E6A1BA35-D3D4-4F28-9B59-FA946B3039C7}.Release|x86.ActiveCfg = Release|Any CPU
{E6A1BA35-D3D4-4F28-9B59-FA946B3039C7}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{33F0E415-AB65-43F2-8AE2-3462B56B9E91} = {CFC2BC9E-CFD6-4B01-946D-43C26E6C2108}
{DA5A9F04-F22A-46EE-A26D-B308548BC232} = {6EFE4444-C6E7-4743-8EE5-7A2BE7493457}
{4D72A437-03CB-4869-9E34-7424A3CFCF46} = {6EFE4444-C6E7-4743-8EE5-7A2BE7493457}
{A71AF919-AC3C-4F99-9525-6A48A69502A0} = {6EFE4444-C6E7-4743-8EE5-7A2BE7493457}
{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

View file

@ -1,37 +0,0 @@
## WindowsInk
WindowsInk provides two new output modes
Artist Mode (Windows Ink)
Artist Mode (Relative Windows Ink)
This output mode enables pen pressure support for all apps compatible to Windows Ink API like:
* Adobe Photoshop
* Paint Tool SAI
* Clip Studio Paint
* Corel Painter
* etc...
## Requirements
Install [VMulti](https://github.com/X9VoiD/vmulti-bin/releases/latest)
## Installation
Download WindowsInk plugin from [latest releases.](https://github.com/X9VoiD/VoiDPlugins/releases/latest)
Then copy zip contents to:
| Platform | Path |
| :-- | :-- |
| Windows | `%localappdata%\OpenTabletDriver\Plugins` |
| Linux | `~/.config/OpenTabletDriver/Plugins` |
| MacOS | `$HOME/Library/Application Support/OpenTabletDriver/Plugins` |
## Usage
Enable WindowsInk by selecting it as an output mode on the OutputModeSelector of Output tab.
## Acknowledgements
Huge thanks to [skyborgff](https://github.com/skyborgff) for the [base implementation](https://github.com/skyborgff/OpenTabletDriverPlugins/tree/WindowsInk)!

View file

@ -1,45 +0,0 @@
namespace VoiDPlugins.WindowsInk
{
public static class VMulti
{
// HID report structure for XP-Pen drivers. It is used to send Windows Ink packets.
public struct InkReport
{
public byte VMultiID; // ID to communicate to the Digitizer device
public byte ReportLength; // Size of the report in bytes.
public byte ReportID; // ID of the report.
public byte Buttons; // Byte with switches for pen buttons / states
public ushort X; // X position of the pen from 0 to 32767
public ushort Y; // Y position of the pen from 0 to 32767
public ushort Pressure; // Pressure level from 0 to 8191
public byte[] ToBytes()
{
var bytes = new byte[10];
bytes[0] = VMultiID;
bytes[1] = ReportLength;
bytes[2] = ReportID;
bytes[3] = Buttons;
bytes[4] = (byte)(X & 0xFF);
bytes[5] = (byte)((X & 0xFF00) >> 8);
bytes[6] = (byte)(Y & 0xFF);
bytes[7] = (byte)((Y & 0xFF00) >> 8);
bytes[8] = (byte)(Pressure & 0xFF);
bytes[9] = (byte)((Pressure & 0xFF00) >> 8);
return bytes;
}
public static implicit operator byte[](InkReport report)
{
return report.ToBytes();
}
}
public enum ButtonMask : int
{
Press = 1,
Barrel = 2,
Eraser = 4,
Invert = 8,
InRange = 16
}
}
}

View file

@ -1,190 +0,0 @@
using System;
using System.Numerics;
using HidSharp;
using OpenTabletDriver.Plugin;
using OpenTabletDriver.Plugin.Attributes;
using OpenTabletDriver.Plugin.Output;
using OpenTabletDriver.Plugin.Platform.Display;
using OpenTabletDriver.Plugin.Platform.Pointer;
using static VoiDPlugins.WindowsInk.VMulti;
namespace VoiDPlugins.WindowsInk
{
[PluginName("Artist Mode (Windows Ink)"), SupportedPlatform(PluginPlatform.Windows)]
public class WindowsInk : AbsoluteOutputMode
{
private readonly IAbsolutePointer InkHandler = new InkHandler();
public override IAbsolutePointer Pointer => InkHandler;
}
[PluginName("Artist Mode (Relative Windows Ink)"), SupportedPlatform(PluginPlatform.Windows)]
public class WindowsInkRelative : RelativeOutputMode
{
private readonly IRelativePointer InkHandler = new InkHandler();
public override IRelativePointer Pointer => InkHandler;
}
[SupportedPlatform(PluginPlatform.Windows)]
public class InkHandler : IAbsolutePointer, IRelativePointer, IVirtualTablet
{
private readonly IVirtualScreen VirtualScreen = (Info.Driver as IVirtualDisplayDriver).VirtualScreen;
internal static HidStream VMultiDev;
internal static InkReport InkReport;
private Vector2 LastPos;
internal static bool EraserState;
private readonly Vector2 ScreenMax, ScreenToVMulti;
public InkHandler()
{
InkReport = new InkReport()
{
VMultiID = 0x40,
ReportLength = 0x0a,
ReportID = 0x05,
Buttons = (byte)ButtonMask.InRange
};
VMultiDev = null;
foreach (var device in DeviceList.Local.GetHidDevices(productID: 47820))
{
if (device.GetMaxOutputReportLength() == 65 && device.GetMaxInputReportLength() == 65)
{
device.TryOpen(out VMultiDev);
if (VMultiDev != null)
break;
}
}
if (VMultiDev == null)
{
Log.Write("WindowsInk", "Cannot find VirtualHID", LogLevel.Error);
Log.Write("WindowsInk", "Install VMulti driver here: https://github.com/X9VoiD/vmulti-bin/releases/latest");
}
ScreenMax = new Vector2(VirtualScreen.Width, VirtualScreen.Height);
ScreenToVMulti = ScreenMax / 32767;
EraserState = false;
}
public void SetPosition(Vector2 pos)
{
var newPos = pos / ScreenToVMulti;
InkReport.X = (ushort)newPos.X;
InkReport.Y = (ushort)newPos.Y;
VMultiDev.Write(InkReport);
}
public void Translate(Vector2 delta)
{
var newPos = LastPos + delta;
LastPos.X = Math.Clamp(newPos.X, 0, ScreenMax.X);
LastPos.Y = Math.Clamp(newPos.Y, 0, ScreenMax.Y);
var reportPos = LastPos / ScreenToVMulti;
InkReport.X = (ushort)reportPos.X;
InkReport.Y = (ushort)reportPos.Y;
VMultiDev.Write(InkReport);
}
public void SetPressure(float percentage)
{
InkReport.Pressure = (ushort)(percentage * 8191);
}
internal static void EnableBit(ButtonMask mask)
{
InkReport.Buttons = (byte)(InkReport.Buttons | (int)mask);
}
internal static void DisableBit(ButtonMask mask)
{
InkReport.Buttons = (byte)(InkReport.Buttons & ~(int)mask);
}
internal static void StateChange()
{
var prevState = InkReport.Buttons;
var prevPressure = InkReport.Pressure;
InkReport.Buttons = 0;
InkReport.Pressure = 0;
VMultiDev.Write(InkReport);
InkReport.Buttons = prevState;
InkReport.Pressure = prevPressure;
}
}
[PluginName("Windows Ink"), SupportedPlatform(PluginPlatform.Windows)]
public class InkBinding : IBinding, IValidateBinding
{
[Property("Property")]
public string Property { get; set; }
public Action Press => () =>
{
switch (Property)
{
case "Pen Tip":
if (!InkHandler.EraserState)
{
InkHandler.EnableBit(ButtonMask.Press);
}
else
{
InkHandler.EnableBit(ButtonMask.Eraser);
}
break;
case "Barrel Button":
InkHandler.EnableBit(ButtonMask.Barrel);
break;
case "Eraser (Hold)":
InkHandler.EnableBit(ButtonMask.Invert);
InkHandler.DisableBit(ButtonMask.Press);
InkHandler.EraserState = true;
InkHandler.StateChange();
break;
case "Eraser (Toggle)":
if (InkHandler.EraserState)
{
InkHandler.DisableBit(ButtonMask.Invert);
InkHandler.EraserState = false;
InkHandler.StateChange();
}
else
{
InkHandler.EnableBit(ButtonMask.Invert);
InkHandler.DisableBit(ButtonMask.Press);
InkHandler.EraserState = true;
InkHandler.StateChange();
}
break;
}
};
public Action Release => () =>
{
switch (Property)
{
case "Pen Tip":
InkHandler.DisableBit(ButtonMask.Press);
InkHandler.DisableBit(ButtonMask.Eraser);
break;
case "Barrel Button":
InkHandler.DisableBit(ButtonMask.Barrel);
break;
case "Eraser (Hold)":
InkHandler.DisableBit(ButtonMask.Invert);
InkHandler.EraserState = false;
InkHandler.StateChange();
break;
}
};
public string[] ValidProperties => new string[]
{
"Pen Tip",
"Eraser (Toggle)",
"Eraser (Hold)",
"Barrel Button"
};
}
}