Repurpose WindowsInk to TouchEmu

This commit is contained in:
X9VoiD 2020-08-28 02:33:48 +08:00
parent 64e2271750
commit b30c73f52b
No known key found for this signature in database
GPG key ID: 3AC5DBB8A2717CFF
8 changed files with 118 additions and 104 deletions

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule ".modules/OpenTabletDriver"]
path = .modules/OpenTabletDriver
url = https://github.com/InfinityGhost/OpenTabletDriver

@ -0,0 +1 @@
Subproject commit 5ee2bae3d188cf6c468cf93df9a5815d2daa5ef1

View file

@ -7,7 +7,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MLFilter", "MLFilter\MLFilt
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OemKill", "OemKill\OemKill.csproj", "{4EC8FA2D-0CCC-4FC3-A32A-BC063924A803}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsInk", "WindowsInk\WindowsInk.csproj", "{FC135341-4870-4555-8917-7248CFE07FCC}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TouchEmu", "TouchEmu\TouchEmu.csproj", "{FC135341-4870-4555-8917-7248CFE07FCC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution

View file

@ -1,7 +1,7 @@
using System;
using System.Runtime.InteropServices;
namespace WindowsInk
namespace TouchEmu
{
using HANDLE = IntPtr;
using HWND = IntPtr;
@ -143,10 +143,10 @@ namespace WindowsInk
public unsafe struct POINTER_DEVICE_INFO
{
public DWORD displayOrientation;
public IntPtr device;
public void* device;
public POINTER_DEVICE_TYPE pointerDeviceType;
public IntPtr monitor;
public ulong startingCursorId;
public void* monitor;
public uint startingCursorId;
public ushort maxActiveContacts;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 520)]
@ -164,6 +164,10 @@ namespace WindowsInk
public static extern bool InjectSyntheticPointerInput(IntPtr device, [In, MarshalAs(UnmanagedType.LPArray)] POINTER_TYPE_INFO[] pointerInfo, uint count);
[DllImport("user32.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool GetPointerDevices(ref uint deviceCount, IntPtr pointerDevices);
[return: MarshalAs(UnmanagedType.Bool)]
public static unsafe extern bool GetPointerDevices(out uint deviceCount, [In, Out, MarshalAs(UnmanagedType.LPArray)] POINTER_DEVICE_INFO[] pointerDevices);
[DllImport("user32.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr GetForegroundWindow();
}
}

View file

@ -2,38 +2,39 @@ using System;
using System.Runtime.InteropServices;
using TabletDriverPlugin;
namespace WindowsInk
namespace TouchEmu
{
public static class Pen
public static class Touch
{
private static IntPtr _penHandle;
private static POINTER_TYPE_INFO[] pointer;
private static uint _pointerId;
private static IntPtr _sourceDevice;
public static void Init()
public static unsafe void Init()
{
uint count = 0;
NativeMethods.GetPointerDevices(ref count, out var pointerDevices);
foreach (var device in pointerDevices)
NativeMethods.GetPointerDevices(out uint count, null);
POINTER_DEVICE_INFO[] pointerDevices = new POINTER_DEVICE_INFO[count];
NativeMethods.GetPointerDevices(out count, pointerDevices);
for (int i = 0; i < count; i++)
{
var device = pointerDevices[i];
if (device.pointerDeviceType == POINTER_DEVICE_TYPE.EXTERNAL_PEN ||
device.pointerDeviceType == POINTER_DEVICE_TYPE.INTEGRATED_PEN)
{
_pointerId = (uint)device.startingCursorId;
_sourceDevice = device.device;
_sourceDevice = new IntPtr(device.device);
}
}
Log.Write("WindowsInk", "Pen created", LogLevel.Debug);
var _pointerInfo = new POINTER_INFO
{
pointerType = POINTER_INPUT_TYPE.PT_PEN,
pointerId = _pointerId,
frameId = 0,
pointerFlags = POINTER_FLAGS.NONE,
sourceDevice = IntPtr.Zero,
hwndTarget = IntPtr.Zero,
sourceDevice = _sourceDevice,
hwndTarget = NativeMethods.GetForegroundWindow(),
ptPixelLocation = new POINT(),
ptPixelLocationRaw = new POINT(),
dwTime = 0,
@ -67,9 +68,7 @@ namespace WindowsInk
_penHandle = NativeMethods.CreateSyntheticPointerDevice(POINTER_INPUT_TYPE.PT_PEN, 1, POINTER_FEEDBACK_MODE.INDIRECT);
var err = Marshal.GetLastWin32Error();
if (err < 0 || _penHandle == IntPtr.Zero)
Log.Write("WindowsInk", "Failed creating synthetic pointer. Reason: " + err, LogLevel.Error);
else
Log.Write("WindowsInk", "Pen handle retrieved successfully", LogLevel.Debug);
throw new Exception("Failed to create handle.");
// Notify WindowsInk
ClearPointerFlags(POINTER_FLAGS.NEW);
@ -83,16 +82,19 @@ namespace WindowsInk
{
if (!NativeMethods.InjectSyntheticPointerInput(_penHandle, pointer, 1))
{
Log.Write("WindowsInk", "Injection Failed. Reason: " + Marshal.GetLastWin32Error());
throw new Exception($"Input injection failed. Reason: {Marshal.GetLastWin32Error()}");
}
}
public static void SetTarget()
{
pointer[0].penInfo.pointerInfo.hwndTarget = NativeMethods.GetForegroundWindow();
}
public static void SetPosition(POINT point)
{
pointer[0].penInfo.pointerInfo.ptPixelLocation = point;
pointer[0].penInfo.pointerInfo.ptPixelLocationRaw = point;
// pointer[0].penInfo.pointerInfo.ptHimetricLocation = point;
// pointer[0].penInfo.pointerInfo.ptHimetricLocationRaw = point;
}
public static void SetPressure(uint pressure)
@ -120,4 +122,4 @@ namespace WindowsInk
pointer[0].penInfo.pointerInfo.pointerFlags = flags;
}
}
}
}

84
TouchEmu/TouchEmu.cs Normal file
View file

@ -0,0 +1,84 @@
using TabletDriverPlugin;
using TabletDriverPlugin.Attributes;
using TabletDriverPlugin.Output;
using TabletDriverPlugin.Platform.Pointer;
namespace TouchEmu
{
public static class TouchState
{
public static IVirtualTablet touchPointer = new TouchPointerHandler();
}
[PluginName("Touch Emu"), SupportedPlatform(PluginPlatform.Windows)]
public class TouchOutputMode : AbsoluteOutputMode
{
public override IVirtualTablet VirtualTablet => TouchState.touchPointer;
}
public class TouchPointerHandler : IVirtualTablet, IPressureHandler
{
private bool _inContact;
private bool _lastContact;
public TouchPointerHandler()
{
Touch.Init();
_inContact = false;
_lastContact = false;
}
public void MouseDown(MouseButton button)
{
return;
}
public void MouseUp(MouseButton button)
{
return;
}
public void SetPosition(Point pos)
{
Touch.SetPosition(new POINT((int)pos.X, (int)pos.Y));
if (_inContact != _lastContact)
{
if (_inContact)
{
Touch.UnsetPointerFlags(POINTER_FLAGS.UP | POINTER_FLAGS.UPDATE);
Touch.SetPointerFlags(POINTER_FLAGS.DOWN);
_lastContact = _inContact;
}
else
{
Touch.UnsetPointerFlags(POINTER_FLAGS.DOWN | POINTER_FLAGS.UPDATE);
Touch.SetPointerFlags(POINTER_FLAGS.UP);
_lastContact = _inContact;
}
}
else
{
Touch.SetPointerFlags(POINTER_FLAGS.UPDATE);
}
Touch.SetTarget();
Touch.Inject();
}
public void SetPressure(float percentage)
{
var pressure = (uint)(percentage * 1024);
if (pressure > 0)
{
Touch.SetPressure(pressure);
Touch.SetPointerFlags(POINTER_FLAGS.INCONTACT | POINTER_FLAGS.FIRSTBUTTON);
_inContact = true;
}
else
{
Touch.SetPressure(1);
Touch.UnsetPointerFlags(POINTER_FLAGS.INCONTACT | POINTER_FLAGS.FIRSTBUTTON);
_inContact = false;
}
}
}
}

View file

@ -6,7 +6,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TabletDriverPlugin" Version="0.3.2" />
<ProjectReference Include="../.modules/OpenTabletDriver/TabletDriverPlugin/TabletDriverPlugin.csproj" />
</ItemGroup>
</Project>

View file

@ -1,80 +0,0 @@
using TabletDriverPlugin;
using TabletDriverPlugin.Attributes;
using TabletDriverPlugin.Output;
using TabletDriverPlugin.Platform.Pointer;
namespace WindowsInk
{
public static class InkState
{
public static IPointerHandler inkPointer = new InkPointerHandler();
}
[PluginName("Windows Ink"), SupportedPlatform(PluginPlatform.Windows)]
public class InkOutputMode : AbsoluteOutputMode
{
public override IPointerHandler PointerHandler => InkState.inkPointer;
}
public class InkPointerHandler : IPointerHandler, IPressureHandler
{
private Point _lastPos;
private bool _inContact;
private bool _lastContact;
public InkPointerHandler()
{
Pen.Init();
_inContact = false;
_lastContact = false;
}
public Point GetPosition()
{
return _lastPos;
}
public void SetPosition(Point pos)
{
Pen.SetPosition(new POINT((int)pos.X, (int)pos.Y));
if (_inContact != _lastContact)
{
if (_inContact)
{
Pen.UnsetPointerFlags(POINTER_FLAGS.UP | POINTER_FLAGS.UPDATE);
Pen.SetPointerFlags(POINTER_FLAGS.DOWN);
_lastContact = _inContact;
}
else
{
Pen.UnsetPointerFlags(POINTER_FLAGS.DOWN | POINTER_FLAGS.UPDATE);
Pen.SetPointerFlags(POINTER_FLAGS.UP);
_lastContact = _inContact;
}
}
else
{
Pen.SetPointerFlags(POINTER_FLAGS.UPDATE);
}
Pen.Inject();
_lastPos = pos;
}
public void SetPressure(float percentage)
{
var pressure = (uint)(percentage * 1024);
if (pressure > 0)
{
Pen.SetPressure(pressure);
Pen.SetPointerFlags(POINTER_FLAGS.INCONTACT | POINTER_FLAGS.FIRSTBUTTON);
_inContact = true;
}
else
{
Pen.SetPressure(1);
Pen.UnsetPointerFlags(POINTER_FLAGS.INCONTACT | POINTER_FLAGS.FIRSTBUTTON);
_inContact = false;
}
}
}
}