Browse Source

Implemented WM_TOUCH support

pull/2581/head
Nikita Tsukanov 7 years ago
parent
commit
d39bc04dc9
  1. 3
      samples/ControlCatalog.NetCore/Program.cs
  2. 72
      src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
  3. 7
      src/Windows/Avalonia.Win32/Win32Platform.cs
  4. 46
      src/Windows/Avalonia.Win32/WindowImpl.cs

3
samples/ControlCatalog.NetCore/Program.cs

@ -46,7 +46,8 @@ namespace ControlCatalog.NetCore
public static AppBuilder BuildAvaloniaApp() public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>() => AppBuilder.Configure<App>()
.UsePlatformDetect() .UsePlatformDetect()
.With(new X11PlatformOptions{EnableMultiTouch = true}) .With(new X11PlatformOptions {EnableMultiTouch = true})
.With(new Win32PlatformOptions {EnableMultitouch = true})
.UseSkia() .UseSkia()
.UseReactiveUI(); .UseReactiveUI();

72
src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs

@ -574,6 +574,7 @@ namespace Avalonia.Win32.Interop
WM_AFXLAST = 0x037F, WM_AFXLAST = 0x037F,
WM_PENWINFIRST = 0x0380, WM_PENWINFIRST = 0x0380,
WM_PENWINLAST = 0x038F, WM_PENWINLAST = 0x038F,
WM_TOUCH = 0x0240,
WM_APP = 0x8000, WM_APP = 0x8000,
WM_USER = 0x0400, WM_USER = 0x0400,
@ -836,10 +837,16 @@ namespace Avalonia.Win32.Interop
[DllImport("user32.dll")] [DllImport("user32.dll")]
public static extern bool PeekMessage(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax, uint wRemoveMsg); public static extern bool PeekMessage(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax, uint wRemoveMsg);
[DllImport("user32")]
public static extern IntPtr GetMessageExtraInfo();
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "RegisterClassExW")] [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "RegisterClassExW")]
public static extern ushort RegisterClassEx(ref WNDCLASSEX lpwcx); public static extern ushort RegisterClassEx(ref WNDCLASSEX lpwcx);
[DllImport("user32.dll")]
public static extern void RegisterTouchWindow(IntPtr hWnd, int flags);
[DllImport("user32.dll")] [DllImport("user32.dll")]
public static extern bool ReleaseCapture(); public static extern bool ReleaseCapture();
@ -1035,6 +1042,17 @@ namespace Avalonia.Win32.Interop
[return: MarshalAs(UnmanagedType.Bool)] [return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetMonitorInfo([In] IntPtr hMonitor, ref MONITORINFO lpmi); public static extern bool GetMonitorInfo([In] IntPtr hMonitor, ref MONITORINFO lpmi);
[DllImport("user32")]
public static extern bool GetTouchInputInfo(
IntPtr hTouchInput,
uint cInputs,
[Out]TOUCHINPUT[] pInputs,
int cbSize
);
[DllImport("user32")]
public static extern bool CloseTouchInputHandle(IntPtr hTouchInput);
[return: MarshalAs(UnmanagedType.Bool)] [return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "PostMessageW")] [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "PostMessageW")]
public static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); public static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
@ -1309,6 +1327,60 @@ namespace Avalonia.Win32.Interop
public IntPtr hIconSm; public IntPtr hIconSm;
} }
[StructLayout(LayoutKind.Sequential)]
public struct TOUCHINPUT
{
public int X;
public int Y;
public IntPtr Source;
public uint Id;
public TouchInputFlags Flags;
public int Mask;
public uint Time;
public IntPtr ExtraInfo;
public int CxContact;
public int CyContact;
}
[Flags]
public enum TouchInputFlags
{
/// <summary>
/// Movement has occurred. Cannot be combined with TOUCHEVENTF_DOWN.
/// </summary>
TOUCHEVENTF_MOVE = 0x0001,
/// <summary>
/// The corresponding touch point was established through a new contact. Cannot be combined with TOUCHEVENTF_MOVE or TOUCHEVENTF_UP.
/// </summary>
TOUCHEVENTF_DOWN = 0x0002,
/// <summary>
/// A touch point was removed.
/// </summary>
TOUCHEVENTF_UP = 0x0004,
/// <summary>
/// A touch point is in range. This flag is used to enable touch hover support on compatible hardware. Applications that do not want support for hover can ignore this flag.
/// </summary>
TOUCHEVENTF_INRANGE = 0x0008,
/// <summary>
/// Indicates that this TOUCHINPUT structure corresponds to a primary contact point. See the following text for more information on primary touch points.
/// </summary>
TOUCHEVENTF_PRIMARY = 0x0010,
/// <summary>
/// When received using GetTouchInputInfo, this input was not coalesced.
/// </summary>
TOUCHEVENTF_NOCOALESCE = 0x0020,
/// <summary>
/// The touch event came from the user's palm.
/// </summary>
TOUCHEVENTF_PALM = 0x0080
}
[Flags] [Flags]
public enum OpenFileNameFlags public enum OpenFileNameFlags
{ {

7
src/Windows/Avalonia.Win32/Win32Platform.cs

@ -40,6 +40,7 @@ namespace Avalonia
{ {
public bool UseDeferredRendering { get; set; } = true; public bool UseDeferredRendering { get; set; } = true;
public bool AllowEglInitialization { get; set; } public bool AllowEglInitialization { get; set; }
public bool? EnableMultitouch { get; set; }
} }
} }
@ -59,7 +60,8 @@ namespace Avalonia.Win32
CreateMessageWindow(); CreateMessageWindow();
} }
public static bool UseDeferredRendering { get; set; } public static bool UseDeferredRendering => Options.UseDeferredRendering;
public static Win32PlatformOptions Options { get; private set; }
public Size DoubleClickSize => new Size( public Size DoubleClickSize => new Size(
UnmanagedMethods.GetSystemMetrics(UnmanagedMethods.SystemMetric.SM_CXDOUBLECLK), UnmanagedMethods.GetSystemMetrics(UnmanagedMethods.SystemMetric.SM_CXDOUBLECLK),
@ -74,6 +76,7 @@ namespace Avalonia.Win32
public static void Initialize(Win32PlatformOptions options) public static void Initialize(Win32PlatformOptions options)
{ {
Options = options;
AvaloniaLocator.CurrentMutable AvaloniaLocator.CurrentMutable
.Bind<IClipboard>().ToSingleton<ClipboardImpl>() .Bind<IClipboard>().ToSingleton<ClipboardImpl>()
.Bind<IStandardCursorFactory>().ToConstant(CursorFactory.Instance) .Bind<IStandardCursorFactory>().ToConstant(CursorFactory.Instance)
@ -88,7 +91,7 @@ namespace Avalonia.Win32
.Bind<IPlatformIconLoader>().ToConstant(s_instance); .Bind<IPlatformIconLoader>().ToConstant(s_instance);
if (options.AllowEglInitialization) if (options.AllowEglInitialization)
Win32GlManager.Initialize(); Win32GlManager.Initialize();
UseDeferredRendering = options.UseDeferredRendering;
_uiThread = Thread.CurrentThread; _uiThread = Thread.CurrentThread;
if (OleContext.Current != null) if (OleContext.Current != null)

46
src/Windows/Avalonia.Win32/WindowImpl.cs

@ -30,6 +30,8 @@ namespace Avalonia.Win32
private UnmanagedMethods.WndProc _wndProcDelegate; private UnmanagedMethods.WndProc _wndProcDelegate;
private string _className; private string _className;
private IntPtr _hwnd; private IntPtr _hwnd;
private bool _multitouch;
private TouchDevice _touchDevice = new TouchDevice();
private IInputRoot _owner; private IInputRoot _owner;
private bool _trackingMouse; private bool _trackingMouse;
private bool _decorated = true; private bool _decorated = true;
@ -414,6 +416,15 @@ namespace Avalonia.Win32
IntPtr.Zero); IntPtr.Zero);
} }
bool ShouldIgnoreTouchEmulatedMessage()
{
if (!_multitouch)
return false;
var marker = 0xFF515700L;
var info = GetMessageExtraInfo().ToInt64();
return (info & marker) == marker;
}
[SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "Using Win32 naming for consistency.")] [SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "Using Win32 naming for consistency.")]
protected virtual IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) protected virtual IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
{ {
@ -519,6 +530,8 @@ namespace Avalonia.Win32
case UnmanagedMethods.WindowsMessage.WM_LBUTTONDOWN: case UnmanagedMethods.WindowsMessage.WM_LBUTTONDOWN:
case UnmanagedMethods.WindowsMessage.WM_RBUTTONDOWN: case UnmanagedMethods.WindowsMessage.WM_RBUTTONDOWN:
case UnmanagedMethods.WindowsMessage.WM_MBUTTONDOWN: case UnmanagedMethods.WindowsMessage.WM_MBUTTONDOWN:
if(ShouldIgnoreTouchEmulatedMessage())
break;
e = new RawMouseEventArgs( e = new RawMouseEventArgs(
WindowsMouseDevice.Instance, WindowsMouseDevice.Instance,
timestamp, timestamp,
@ -534,6 +547,8 @@ namespace Avalonia.Win32
case UnmanagedMethods.WindowsMessage.WM_LBUTTONUP: case UnmanagedMethods.WindowsMessage.WM_LBUTTONUP:
case UnmanagedMethods.WindowsMessage.WM_RBUTTONUP: case UnmanagedMethods.WindowsMessage.WM_RBUTTONUP:
case UnmanagedMethods.WindowsMessage.WM_MBUTTONUP: case UnmanagedMethods.WindowsMessage.WM_MBUTTONUP:
if(ShouldIgnoreTouchEmulatedMessage())
break;
e = new RawMouseEventArgs( e = new RawMouseEventArgs(
WindowsMouseDevice.Instance, WindowsMouseDevice.Instance,
timestamp, timestamp,
@ -547,6 +562,8 @@ namespace Avalonia.Win32
break; break;
case UnmanagedMethods.WindowsMessage.WM_MOUSEMOVE: case UnmanagedMethods.WindowsMessage.WM_MOUSEMOVE:
if(ShouldIgnoreTouchEmulatedMessage())
break;
if (!_trackingMouse) if (!_trackingMouse)
{ {
var tm = new UnmanagedMethods.TRACKMOUSEEVENT var tm = new UnmanagedMethods.TRACKMOUSEEVENT
@ -611,7 +628,30 @@ namespace Avalonia.Win32
: RawMouseEventType.MiddleButtonDown, : RawMouseEventType.MiddleButtonDown,
new Point(0, 0), GetMouseModifiers(wParam)); new Point(0, 0), GetMouseModifiers(wParam));
break; break;
case WindowsMessage.WM_TOUCH:
var touchInputs = new TOUCHINPUT[wParam.ToInt32()];
if (GetTouchInputInfo(lParam, (uint)wParam.ToInt32(), touchInputs, Marshal.SizeOf<TOUCHINPUT>()))
{
foreach (var touchInput in touchInputs)
{
var pt = new POINT {X = touchInput.X / 100, Y = touchInput.Y / 100};
UnmanagedMethods.ScreenToClient(_hwnd, ref pt);
Input?.Invoke(new RawTouchEventArgs(_touchDevice, touchInput.Time,
_owner,
touchInput.Flags.HasFlag(TouchInputFlags.TOUCHEVENTF_UP) ?
RawMouseEventType.TouchEnd :
touchInput.Flags.HasFlag(TouchInputFlags.TOUCHEVENTF_DOWN) ?
RawMouseEventType.TouchBegin :
RawMouseEventType.TouchUpdate,
new Point(pt.X, pt.Y),
WindowsKeyboardDevice.Instance.Modifiers,
touchInput.Id));
}
CloseTouchInputHandle(lParam);
return IntPtr.Zero;
}
break;
case WindowsMessage.WM_NCPAINT: case WindowsMessage.WM_NCPAINT:
if (!_decorated) if (!_decorated)
{ {
@ -754,6 +794,10 @@ namespace Avalonia.Win32
Handle = new PlatformHandle(_hwnd, PlatformConstants.WindowHandleType); Handle = new PlatformHandle(_hwnd, PlatformConstants.WindowHandleType);
_multitouch = Win32Platform.Options.EnableMultitouch ?? false;
if (_multitouch)
RegisterTouchWindow(_hwnd, 0);
if (UnmanagedMethods.ShCoreAvailable) if (UnmanagedMethods.ShCoreAvailable)
{ {
uint dpix, dpiy; uint dpix, dpiy;

Loading…
Cancel
Save