Browse Source

Merge branch 'multitouch' of github.com:AvaloniaUI/Avalonia into multitouch

pull/2581/head
Nikita Tsukanov 7 years ago
parent
commit
2967166dd5
  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()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.With(new X11PlatformOptions{EnableMultiTouch = true})
.With(new X11PlatformOptions {EnableMultiTouch = true})
.With(new Win32PlatformOptions {EnableMultitouch = true})
.UseSkia()
.UseReactiveUI();

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

@ -574,6 +574,7 @@ namespace Avalonia.Win32.Interop
WM_AFXLAST = 0x037F,
WM_PENWINFIRST = 0x0380,
WM_PENWINLAST = 0x038F,
WM_TOUCH = 0x0240,
WM_APP = 0x8000,
WM_USER = 0x0400,
@ -836,10 +837,16 @@ namespace Avalonia.Win32.Interop
[DllImport("user32.dll")]
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")]
public static extern ushort RegisterClassEx(ref WNDCLASSEX lpwcx);
[DllImport("user32.dll")]
public static extern void RegisterTouchWindow(IntPtr hWnd, int flags);
[DllImport("user32.dll")]
public static extern bool ReleaseCapture();
@ -1035,6 +1042,17 @@ namespace Avalonia.Win32.Interop
[return: MarshalAs(UnmanagedType.Bool)]
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)]
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "PostMessageW")]
public static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
@ -1309,6 +1327,60 @@ namespace Avalonia.Win32.Interop
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]
public enum OpenFileNameFlags
{

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

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

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

@ -30,6 +30,8 @@ namespace Avalonia.Win32
private UnmanagedMethods.WndProc _wndProcDelegate;
private string _className;
private IntPtr _hwnd;
private bool _multitouch;
private TouchDevice _touchDevice = new TouchDevice();
private IInputRoot _owner;
private bool _trackingMouse;
private bool _decorated = true;
@ -414,6 +416,15 @@ namespace Avalonia.Win32
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.")]
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_RBUTTONDOWN:
case UnmanagedMethods.WindowsMessage.WM_MBUTTONDOWN:
if(ShouldIgnoreTouchEmulatedMessage())
break;
e = new RawMouseEventArgs(
WindowsMouseDevice.Instance,
timestamp,
@ -534,6 +547,8 @@ namespace Avalonia.Win32
case UnmanagedMethods.WindowsMessage.WM_LBUTTONUP:
case UnmanagedMethods.WindowsMessage.WM_RBUTTONUP:
case UnmanagedMethods.WindowsMessage.WM_MBUTTONUP:
if(ShouldIgnoreTouchEmulatedMessage())
break;
e = new RawMouseEventArgs(
WindowsMouseDevice.Instance,
timestamp,
@ -547,6 +562,8 @@ namespace Avalonia.Win32
break;
case UnmanagedMethods.WindowsMessage.WM_MOUSEMOVE:
if(ShouldIgnoreTouchEmulatedMessage())
break;
if (!_trackingMouse)
{
var tm = new UnmanagedMethods.TRACKMOUSEEVENT
@ -611,7 +628,30 @@ namespace Avalonia.Win32
: RawMouseEventType.MiddleButtonDown,
new Point(0, 0), GetMouseModifiers(wParam));
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:
if (!_decorated)
{
@ -754,6 +794,10 @@ namespace Avalonia.Win32
Handle = new PlatformHandle(_hwnd, PlatformConstants.WindowHandleType);
_multitouch = Win32Platform.Options.EnableMultitouch ?? false;
if (_multitouch)
RegisterTouchWindow(_hwnd, 0);
if (UnmanagedMethods.ShCoreAvailable)
{
uint dpix, dpiy;

Loading…
Cancel
Save