I'm trying to disable most of the touch gestures that can effect my WebBrowser control in my winforms project and i've been unsuccessfull so far.
Edge Gestures have been disabled with PKEY_EdgeGesture_DisableTouchWhenFullScreen => working
I'm using a PreFilterMessage but it seems that WM_GESTURE can't be filtered from there :
public bool PreFilterMessage(ref Message m)
{
// Messages to be filtered
const int WM_MOUSEWHEEL = 0x20A;
const int WM_SYSCOMMAND = 0x0112;
const int WM_GESTURE = 0x0119;
const int WM_GESTURENOTIFY = 0x011A;
const int SC_MOVE = 0xF010;
switch (m.Msg)
{
case WM_MOUSEWHEEL:
Debug.WriteLine("Filtering WM_MOUSEWHEEL !"); // Working
return true;
case WM_GESTURE:
Debug.WriteLine("Filtering WM_GESTURE !"); // Not working
return true;
case WM_GESTURENOTIFY:
Debug.WriteLine("Filtering WM_GESTURENOTIFY !"); // Not working
return true;
case WM_SYSCOMMAND:
int command = m.WParam.ToInt32() & 0xfff0;
if (command == SC_MOVE) return true;
break;
}
Next i've moved to WndProc override and i see the messages in debug log but so far i haven't figured out how to filter message from there: the gesture got executed anyway.
protected override void WndProc(ref Message m)
{
const int WM_GESTURE = 0x0119;
const int WM_GESTURENOTIFY = 0x011A;
switch (m.Msg)
{
case WM_GESTURE:
Debug.WriteLine("WM_GESTURE go away !!!");
return;
case WM_GESTURENOTIFY:
Debug.WriteLine("WM_GESTURENOTIFY begone with thee !!");
return;
}
base.WndProc(ref m);
}
i try to avoid CSS injection in the html page or setting a registry value to globally disable zoom in internet explorer, anyone has an idea ?
Answering my own question :)
Filtering WM_GESUTURE and WM_TOUCH messages out have led to nowhere (never noticed a change in the app touch behavior)
WM_POINTER is the way to go... Filetering WM_POINTERUP and WM_POINTERDOWN messages has an effect on my application.
Working with WM_POINTER messages gives low level datas and you have to build your own gesture interpretation (which looks like a real pain, if your goal is only to disable theses)
The workaround : since WM_POINTER carries info about primary, secondary, ternary pointers, i filter out all the messages not related to primary pointer, thus disabling two fingers
public partial class Form1 : Form, IMessageFilter
{
internal static int HIWORD(IntPtr wParam)
{
return (int)((wParam.ToInt64() >> 16) & 0xffff);
}
internal static int LOWORD(IntPtr wParam)
{
return (int)(wParam.ToInt64() & 0xffff);
}
[Flags]
internal enum VIRTUAL_KEY_STATES
{
NONE = 0x0000,
LBUTTON = 0x0001,
RBUTTON = 0x0002,
SHIFT = 0x0004,
CTRL = 0x0008,
MBUTTON = 0x0010,
XBUTTON1 = 0x0020,
XBUTTON2 = 0x0040
}
[StructLayout(LayoutKind.Sequential)]
internal struct POINT
{
public int X;
public int Y;
public POINT(int x, int y)
{
X = x;
Y = y;
}
public POINT(Point pt)
{
X = pt.X;
Y = pt.Y;
}
public Point ToPoint()
{
return new Point(X, Y);
}
public void AssignTo(ref Point destination)
{
destination.X = X;
destination.Y = Y;
}
public void CopyFrom(Point source)
{
X = source.X;
Y = source.Y;
}
public void CopyFrom(POINT source)
{
X = source.X;
Y = source.Y;
}
}
[StructLayout(LayoutKind.Sequential)]
internal struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
public RECT(Rectangle source)
{
Left = source.Left;
Top = source.Top;
Right = source.Right;
Bottom = source.Bottom;
}
public RECT(int x, int y, int width, int height)
{
Left = x;
Top = y;
Right = Left + width;
Bottom = Top + height;
}
public int Width
{
get { return Right - Left; }
}
public int Height
{
get { return Bottom - Top; }
}
public Rectangle ToRectangle()
{
return new Rectangle(Left, Top, Width, Height);
}
public void Inflate(int dx, int dy)
{
Left -= dx;
Top -= dy;
Right += dx;
Bottom += dy;
}
public void Deflate(int leftMargin, int topMargin, int rightMargin, int bottomMargin)
{
Left += leftMargin;
Top += topMargin;
Right -= rightMargin;
Bottom -= bottomMargin;
if (Bottom < Top)
{
Bottom = Top;
}
if (Right < Left)
{
Right = Left;
}
}
public void Offset(int dx, int dy)
{
Left += dx;
Top += dy;
Right += dx;
Bottom += dy;
}
}
[Flags]
internal enum TOUCH_FLAGS
{
NONE = 0x00000000
}
[Flags]
internal enum TOUCH_MASK
{
NONE = 0x00000000,
CONTACTAREA = 0x00000001,
ORIENTATION = 0x00000002,
PRESSURE = 0x00000004,
}
internal enum POINTER_INPUT_TYPE
{
POINTER = 0x00000001,
TOUCH = 0x00000002,
PEN = 0x00000003,
MOUSE = 0x00000004
}
[Flags]
internal enum POINTER_FLAGS
{
NONE = 0x00000000,
NEW = 0x00000001,
INRANGE = 0x00000002,
INCONTACT = 0x00000004,
FIRSTBUTTON = 0x00000010,
SECONDBUTTON = 0x00000020,
THIRDBUTTON = 0x00000040,
FOURTHBUTTON = 0x00000080,
FIFTHBUTTON = 0x00000100,
PRIMARY = 0x00002000,
CONFIDENCE = 0x00004000,
CANCELED = 0x00008000,
DOWN = 0x00010000,
UPDATE = 0x00020000,
UP = 0x00040000,
WHEEL = 0x00080000,
HWHEEL = 0x00100000,
CAPTURECHANGED = 0x00200000,
}
[StructLayout(LayoutKind.Sequential)]
internal struct POINTER_TOUCH_INFO
{
[MarshalAs(UnmanagedType.Struct)]
public POINTER_INFO PointerInfo;
public TOUCH_FLAGS TouchFlags;
public TOUCH_MASK TouchMask;
[MarshalAs(UnmanagedType.Struct)]
public RECT ContactArea;
[MarshalAs(UnmanagedType.Struct)]
public RECT ContactAreaRaw;
public uint Orientation;
public uint Pressure;
}
[StructLayout(LayoutKind.Sequential)]
internal struct POINTER_INFO
{
public POINTER_INPUT_TYPE pointerType;
public int PointerID;
public int FrameID;
public POINTER_FLAGS PointerFlags;
public IntPtr SourceDevice;
public IntPtr WindowTarget;
[MarshalAs(UnmanagedType.Struct)]
public POINT PtPixelLocation;
[MarshalAs(UnmanagedType.Struct)]
public POINT PtPixelLocationRaw;
[MarshalAs(UnmanagedType.Struct)]
public POINT PtHimetricLocation;
[MarshalAs(UnmanagedType.Struct)]
public POINT PtHimetricLocationRaw;
public uint Time;
public uint HistoryCount;
public uint InputData;
public VIRTUAL_KEY_STATES KeyStates;
public long PerformanceCount;
public int ButtonChangeType;
}
internal const int
WM_PARENTNOTIFY = 0x0210,
WM_NCPOINTERUPDATE = 0x0241,
WM_NCPOINTERDOWN = 0x0242,
WM_NCPOINTERUP = 0x0243,
WM_POINTERUPDATE = 0x0245,
WM_POINTERDOWN = 0x0246,
WM_POINTERUP = 0x0247,
WM_POINTERENTER = 0x0249,
WM_POINTERLEAVE = 0x024A,
WM_POINTERACTIVATE = 0x024B,
WM_POINTERCAPTURECHANGED = 0x024C,
WM_POINTERWHEEL = 0x024E,
WM_POINTERHWHEEL = 0x024F,
// WM_POINTERACTIVATE return codes
PA_ACTIVATE = 1,
PA_NOACTIVATE = 3,
MAX_TOUCH_COUNT = 256;
internal static int GET_POINTER_ID(IntPtr wParam)
{
return LOWORD(wParam);
}
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool GetPointerInfo(int pointerID, ref POINTER_INFO pointerInfo);
public bool PreFilterMessage(ref Message m)
{
switch (m.Msg)
{
case WM_POINTERDOWN:
case WM_POINTERUP:
case WM_POINTERUPDATE:
case WM_POINTERCAPTURECHANGED:
int pointerID = GET_POINTER_ID(m.WParam);
POINTER_INFO pi = new POINTER_INFO();
if (GetPointerInfo(pointerID, ref pi))
{
// Not a primary pointer => filter !
if ((pi.PointerFlags & POINTER_FLAGS.PRIMARY) == 0)
{
return true;
}
}
break;
}
return false;
}