Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save ulatekh/f37b1a973c7a1b09f18a457e3a4af54a to your computer and use it in GitHub Desktop.
Save ulatekh/f37b1a973c7a1b09f18a457e3a4af54a to your computer and use it in GitHub Desktop.
Globally disable the conversion of touch events to mouse events in Windows 7
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.
/// Or, at least, that's the promise. But the system mouse-cursor still gets set to the position of the last
/// touch-event, and so far, there seems to be no way to prevent that.
/// </summary>
class DisableTouchConversionToMouse : IDisposable
{
// The window on which to disable the conversion of touch-events to
// mouse-events (including all of its child windows).
// If null, conversion is disabled globally.
private IntPtr m_hWnd;
// The installed hook-callbacks.
private HookProc hookCallback, hookCallbackLL;
private IntPtr hookId, hookIdLL;
// Disable touch-conversion globally.
public DisableTouchConversionToMouse()
: this(IntPtr.Zero)
{
}
// Disable touch-conversion for a single window (including all its child windows).
public DisableTouchConversionToMouse(IntPtr hWnd)
{
// Remember the window on which to disable event-conversion, if any.
m_hWnd = hWnd;
// Install both styles of mouse hooks.
// Save a reference to the callback, so that it doesn't get
// garbage-collected.
hookCallback = this.HookCallback;
hookId = SetHook(hookCallback);
hookCallbackLL = this.HookCallbackLL;
hookIdLL = SetHookLL(hookCallbackLL);
}
// Set a WH_MOUSE callback.
static IntPtr SetHook(HookProc proc)
{
var moduleHandle = UnsafeNativeMethods.GetModuleHandle(null);
var threadHandle = UnsafeNativeMethods.GetCurrentThreadId();
var setHookResult = UnsafeNativeMethods.SetWindowsHookEx(WH_MOUSE, proc, moduleHandle, threadHandle);
if (setHookResult == IntPtr.Zero)
{
throw new Win32Exception();
}
return setHookResult;
}
// Set a WH_MOUSE_LL callback.
static IntPtr SetHookLL(HookProc 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;
}
// The WH_MOUSE callback.
private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0)
{
var info = (MOUSEHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MOUSEHOOKSTRUCT));
// Determine whether this mouse-event was generated from a touch event.
// Fix for 64-bit Windows found in a comment from giangurgolo at the
// end of http://stackoverflow.com/a/8012213 .
bool bMouseEventFromTouch = false;
if (IntPtr.Size == 4)
{
var extraInfo = (uint)info.dwExtraInfo.ToInt32();
if ((extraInfo & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH)
{
bMouseEventFromTouch = true;
}
}
else if (IntPtr.Size == 8)
{
var extraInfo = (ulong)info.dwExtraInfo.ToInt64();
if ((extraInfo & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH)
{
bMouseEventFromTouch = true;
}
}
if (bMouseEventFromTouch)
{
// If we weren't initialized with a window-handle, then
// converting touch-events to mouse events is disabled
// for all windows.
if (m_hWnd == null)
return new IntPtr(1);
// Otherwise, disable converting touch-events to mouse events
// for the given window, and all its child windows.
IntPtr hwnd = info.hwnd;
while (hwnd != null)
{
if (hwnd == m_hWnd)
return new IntPtr(1);
hwnd = UnsafeNativeMethods.GetParent(hwnd);
}
}
}
return UnsafeNativeMethods.CallNextHookEx(hookIdLL, nCode, wParam, lParam);
}
// The WH_MOUSE_LL callback.
private IntPtr HookCallbackLL(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0)
{
var info = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
// Determine whether this mouse-event was generated from a touch event.
// Fix for 64-bit Windows found in a comment from giangurgolo at the
// end of http://stackoverflow.com/a/8012213 .
bool bMouseEventFromTouch = false;
if (IntPtr.Size == 4)
{
var extraInfo = (uint)info.dwExtraInfo.ToInt32();
if ((extraInfo & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH)
{
bMouseEventFromTouch = true;
}
}
else if (IntPtr.Size == 8)
{
var extraInfo = (ulong)info.dwExtraInfo.ToInt64();
if ((extraInfo & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH)
{
bMouseEventFromTouch = true;
}
}
if (bMouseEventFromTouch)
{
// If we weren't initialized with a window-handle, then
// converting touch-events to mouse events is disabled
// for all windows.
if (m_hWnd == null)
return new IntPtr(1);
// Otherwise, disable converting touch-events to mouse events
// for the given window, and all its child windows.
IntPtr hwnd = UnsafeNativeMethods.WindowFromPoint(info.pt);
while (hwnd != null)
{
if (hwnd == m_hWnd)
return new IntPtr(1);
hwnd = UnsafeNativeMethods.GetParent(hwnd);
}
}
}
return UnsafeNativeMethods.CallNextHookEx(hookIdLL, nCode, wParam, lParam);
}
bool disposed;
public void Dispose()
{
if (disposed) return;
UnsafeNativeMethods.UnhookWindowsHookEx(hookId);
UnsafeNativeMethods.UnhookWindowsHookEx(hookIdLL);
disposed = true;
GC.SuppressFinalize(this);
}
~DisableTouchConversionToMouse()
{
Dispose();
}
#region Interop
// ReSharper disable InconsistentNaming
// ReSharper disable MemberCanBePrivate.Local
// ReSharper disable FieldCanBeMadeReadOnly.Local
const uint MOUSEEVENTF_FROMTOUCH = 0xFF515700;
const int WH_MOUSE = 7;
const int WH_MOUSE_LL = 14;
[StructLayout(LayoutKind.Sequential)]
struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
struct MOUSEHOOKSTRUCT
{
public POINT pt;
public IntPtr hwnd;
public uint wHitTestCode;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
struct MSLLHOOKSTRUCT
{
public POINT pt;
public uint mouseData;
public uint flags;
public uint time;
public IntPtr dwExtraInfo;
}
delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);
[SuppressUnmanagedCodeSecurity]
static class UnsafeNativeMethods
{
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr SetWindowsHookEx(int idHook, HookProc 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);
[DllImport("kernel32.dll")]
public static extern uint GetCurrentThreadId();
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr WindowFromPoint(POINT p);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetParent(IntPtr hWnd);
}
// ReSharper restore InconsistentNaming
// ReSharper restore FieldCanBeMadeReadOnly.Local
// ReSharper restore MemberCanBePrivate.Local
#endregion
}
}
@SaveTheHuman5
Copy link

SaveTheHuman5 commented Dec 27, 2017

Hello, this code prevent cursor be moved when is present on touch Aplication and I press a touch enabled button as example?

@SaveTheHuman5
Copy link

OK i test this, and i think do what is supposed have to do block all mouse events generated by touchscreen globally.
Im trying to find a way the cursor of mouse not is moved to position where I perform the touch and remain in the position indicated by the mouse. If have some idea, please i really appreciate.
For sure this code work also in windows 10

@tpst
Copy link

tpst commented May 13, 2022

@SaveTheHuman5 Hello, did you find a way to stop the mouse moving? I am trying to do the same thing. Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment