Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid mouse move on Touch

Tags:

I have a WPF application that is capable of being used both with a mouse and using Touch. I disable all windows "enhancements" to just have touch events :

Stylus.IsPressAndHoldEnabled="False" Stylus.IsTapFeedbackEnabled="False" Stylus.IsTouchFeedbackEnabled="False" Stylus.IsFlicksEnabled="False" 

The result is that a click behave like I want except on two points :

  • The small "touch" cursor (little white star) appears where clicked an when dragging.
    Completely useless as the user finger is already at this location no feedback is required (Except my element potentially changing color if actionable).
  • Elements stay in the "Hover" state after the movement / Click ends.

Both are the consequences of the fact that while windows transmit correctly touch events, he still move the mouse to the last main-touch-event.

I don't want windows to move the mouse at all when I use touch inside my application. Is there a way to completely avoid that?

Notes:

  • Handling touch events change nothing to this.
  • Using SetCursorPos to move the mouse away make the cursor blink and isn't really user-friendly.
  • Disabling the touch panel to act as an input device completely disable all events (And I also prefer an application-local solution, not system wide).
  • I don't care if the solution involve COM/PInvoke or is provided in C/C++ i'll translate.
  • If it is necessary to patch/hook some windows dlls so be it, the software will run on a dedicated device anyway.
  • I'm investigating the surface SDK but I doubt that it'll show any solution. As a surface is a pure-touch device there is no risk of bad interaction with the mouse.
like image 353
Julien Roncaglia Avatar asked Nov 04 '11 13:11

Julien Roncaglia


People also ask

Why does my touchpad move on its own?

If you set your touchpad sensitivity on your laptop too high, the cursor will move at the slightest touch. As such, you should take a look at its sensitivity setting.

Why does my cursor Keep jumping around touchpad?

According to a survey, mouse jumping around is often related to faulty hardware including mouse, USB port, and cable. In addition, an outdated device driver, improper touchpad settings, mouse pointer, and even malware are responsible for cursor jumps around.

Does Touchstart work on desktop?

onTouchStart works only for mobile. Also, this event goes before the onClick event.


1 Answers

Here is the best solution I found from now. Don't hesitate to post your own, especially if it is better.

Using SetWindowsHookEx low level mouse event catching (WH_MOUSE_LL) and the fact that all events converted from Touch to Mouse are marked as such (The MOUSEEVENTF_FROMTOUCH flag is set in the event's ExtraInfo, see Microsoft's FAQ) I was able to Globally remove all mouse events comming from the touch panel.

It isn't an ideal solution but it'll do for now in my application when it is running fullscreen (99% of the time as it is a dedicated hardware device).

The second step also good only in fullscreen (That i won't provide code for as it is pretty simple) is just moving the mouse to "safe" position like the bottom right of the screen with SetCursorPos.

If you need the code it is in a Gist on Github and i'll post the current version at the end of this article. To use it :

// As long as the instance is alive the conversion won't occur var disableTouchMouse = new DisableTouchConversionToMouse();  // To let the conversion happen again, Dispose the class. disableTouchMouse.Dispose(); 

Full source code of the class :

namespace BlackFox {     using System;     using System.ComponentModel;     using System.Runtime.InteropServices;     using System.Security;      /// <summary>     /// As long as this object exists all mouse events created from a touch event for legacy support will be disabled.     /// </summary>     class DisableTouchConversionToMouse : IDisposable     {         static readonly LowLevelMouseProc hookCallback = HookCallback;         static IntPtr hookId = IntPtr.Zero;          public DisableTouchConversionToMouse()         {             hookId = SetHook(hookCallback);         }          static IntPtr SetHook(LowLevelMouseProc proc)         {             var moduleHandle = UnsafeNativeMethods.GetModuleHandle(null);              var setHookResult = UnsafeNativeMethods.SetWindowsHookEx(WH_MOUSE_LL, proc, moduleHandle, 0);             if (setHookResult == IntPtr.Zero)             {                 throw new Win32Exception();             }             return setHookResult;         }          delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);          static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)         {             if (nCode >= 0)             {                 var info = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));                  var extraInfo = (uint)info.dwExtraInfo.ToInt32();                 if ((extraInfo & MOUSEEVENTF_MASK) == MOUSEEVENTF_FROMTOUCH)                 {                     if((extraInfo & 0x80) != 0)                     {                         //Touch Input                         return new IntPtr(1);                     }                     else                     {                         //Pen Input                         return new IntPtr(1);                     }                  }             }              return UnsafeNativeMethods.CallNextHookEx(hookId, nCode, wParam, lParam);         }          bool disposed;          public void Dispose()         {             if (disposed) return;              UnsafeNativeMethods.UnhookWindowsHookEx(hookId);             disposed = true;             GC.SuppressFinalize(this);         }          ~DisableTouchConversionToMouse()         {             Dispose();         }          #region Interop          // ReSharper disable InconsistentNaming         // ReSharper disable MemberCanBePrivate.Local         // ReSharper disable FieldCanBeMadeReadOnly.Local          const uint MOUSEEVENTF_MASK = 0xFFFFFF00;          const uint MOUSEEVENTF_FROMTOUCH = 0xFF515700;         const int WH_MOUSE_LL = 14;          [StructLayout(LayoutKind.Sequential)]         struct POINT         {              public int x;             public int y;         }          [StructLayout(LayoutKind.Sequential)]         struct MSLLHOOKSTRUCT         {             public POINT pt;             public uint mouseData;             public uint flags;             public uint time;             public IntPtr dwExtraInfo;         }          [SuppressUnmanagedCodeSecurity]         static class UnsafeNativeMethods         {             [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]             public static extern IntPtr SetWindowsHookEx(int idHook, LowLevelMouseProc lpfn, IntPtr hMod,                 uint dwThreadId);              [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]             [return: MarshalAs(UnmanagedType.Bool)]             public static extern bool UnhookWindowsHookEx(IntPtr hhk);              [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]             public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,                 IntPtr wParam, IntPtr lParam);              [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]             public static extern IntPtr GetModuleHandle(string lpModuleName);         }          // ReSharper restore InconsistentNaming         // ReSharper restore FieldCanBeMadeReadOnly.Local         // ReSharper restore MemberCanBePrivate.Local          #endregion     } } 

edit: From the comments section of Troubleshooting Applications and System Events and Mouse Messages additional information to disambiguate pen from touch.

like image 178
Julien Roncaglia Avatar answered Oct 23 '22 20:10

Julien Roncaglia