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 EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OemKill", "OemKill\OemKill.csproj", "{4EC8FA2D-0CCC-4FC3-A32A-BC063924A803}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OemKill", "OemKill\OemKill.csproj", "{4EC8FA2D-0CCC-4FC3-A32A-BC063924A803}"
EndProject 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 EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution

View file

@ -1,7 +1,7 @@
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace WindowsInk namespace TouchEmu
{ {
using HANDLE = IntPtr; using HANDLE = IntPtr;
using HWND = IntPtr; using HWND = IntPtr;
@ -143,10 +143,10 @@ namespace WindowsInk
public unsafe struct POINTER_DEVICE_INFO public unsafe struct POINTER_DEVICE_INFO
{ {
public DWORD displayOrientation; public DWORD displayOrientation;
public IntPtr device; public void* device;
public POINTER_DEVICE_TYPE pointerDeviceType; public POINTER_DEVICE_TYPE pointerDeviceType;
public IntPtr monitor; public void* monitor;
public ulong startingCursorId; public uint startingCursorId;
public ushort maxActiveContacts; public ushort maxActiveContacts;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 520)] [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); 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)] [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 System.Runtime.InteropServices;
using TabletDriverPlugin; using TabletDriverPlugin;
namespace WindowsInk namespace TouchEmu
{ {
public static class Pen public static class Touch
{ {
private static IntPtr _penHandle; private static IntPtr _penHandle;
private static POINTER_TYPE_INFO[] pointer; private static POINTER_TYPE_INFO[] pointer;
private static uint _pointerId; private static uint _pointerId;
private static IntPtr _sourceDevice; private static IntPtr _sourceDevice;
public static void Init() public static unsafe void Init()
{ {
uint count = 0; NativeMethods.GetPointerDevices(out uint count, null);
NativeMethods.GetPointerDevices(ref count, out var pointerDevices); POINTER_DEVICE_INFO[] pointerDevices = new POINTER_DEVICE_INFO[count];
foreach (var device in pointerDevices) NativeMethods.GetPointerDevices(out count, pointerDevices);
for (int i = 0; i < count; i++)
{ {
var device = pointerDevices[i];
if (device.pointerDeviceType == POINTER_DEVICE_TYPE.EXTERNAL_PEN || if (device.pointerDeviceType == POINTER_DEVICE_TYPE.EXTERNAL_PEN ||
device.pointerDeviceType == POINTER_DEVICE_TYPE.INTEGRATED_PEN) device.pointerDeviceType == POINTER_DEVICE_TYPE.INTEGRATED_PEN)
{ {
_pointerId = (uint)device.startingCursorId; _pointerId = (uint)device.startingCursorId;
_sourceDevice = device.device; _sourceDevice = new IntPtr(device.device);
} }
} }
Log.Write("WindowsInk", "Pen created", LogLevel.Debug);
var _pointerInfo = new POINTER_INFO var _pointerInfo = new POINTER_INFO
{ {
pointerType = POINTER_INPUT_TYPE.PT_PEN, pointerType = POINTER_INPUT_TYPE.PT_PEN,
pointerId = _pointerId, pointerId = _pointerId,
frameId = 0, frameId = 0,
pointerFlags = POINTER_FLAGS.NONE, pointerFlags = POINTER_FLAGS.NONE,
sourceDevice = IntPtr.Zero, sourceDevice = _sourceDevice,
hwndTarget = IntPtr.Zero, hwndTarget = NativeMethods.GetForegroundWindow(),
ptPixelLocation = new POINT(), ptPixelLocation = new POINT(),
ptPixelLocationRaw = new POINT(), ptPixelLocationRaw = new POINT(),
dwTime = 0, dwTime = 0,
@ -67,9 +68,7 @@ namespace WindowsInk
_penHandle = NativeMethods.CreateSyntheticPointerDevice(POINTER_INPUT_TYPE.PT_PEN, 1, POINTER_FEEDBACK_MODE.INDIRECT); _penHandle = NativeMethods.CreateSyntheticPointerDevice(POINTER_INPUT_TYPE.PT_PEN, 1, POINTER_FEEDBACK_MODE.INDIRECT);
var err = Marshal.GetLastWin32Error(); var err = Marshal.GetLastWin32Error();
if (err < 0 || _penHandle == IntPtr.Zero) if (err < 0 || _penHandle == IntPtr.Zero)
Log.Write("WindowsInk", "Failed creating synthetic pointer. Reason: " + err, LogLevel.Error); throw new Exception("Failed to create handle.");
else
Log.Write("WindowsInk", "Pen handle retrieved successfully", LogLevel.Debug);
// Notify WindowsInk // Notify WindowsInk
ClearPointerFlags(POINTER_FLAGS.NEW); ClearPointerFlags(POINTER_FLAGS.NEW);
@ -83,16 +82,19 @@ namespace WindowsInk
{ {
if (!NativeMethods.InjectSyntheticPointerInput(_penHandle, pointer, 1)) 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) public static void SetPosition(POINT point)
{ {
pointer[0].penInfo.pointerInfo.ptPixelLocation = point; pointer[0].penInfo.pointerInfo.ptPixelLocation = point;
pointer[0].penInfo.pointerInfo.ptPixelLocationRaw = 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) public static void SetPressure(uint pressure)

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> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="TabletDriverPlugin" Version="0.3.2" /> <ProjectReference Include="../.modules/OpenTabletDriver/TabletDriverPlugin/TabletDriverPlugin.csproj" />
</ItemGroup> </ItemGroup>
</Project> </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;
}
}
}
}