How do I disable the press-and-hold gesture for my window?


A customer had a program which responded to left mouse clicks, but they found that when used with a touch screen, when users touched the screen, the WM_LBUTTON­DOWN message didn't arrive until the users lifted their fingers from the screen. They wanted to know whether this was by design, and also whether there was a way to get the WM_LBUTTON­DOWN message as soon as the finger touches the screen.

Yes, this behavior is by design. The system is waiting to see whether the user is making a press-and-hold gesture. If so, then the touch events are converted to right-mouse-button messages (WM_RBUTTON­DOWN and WM_RBUTTON­UP). But if the finger does not remain in contact for a long time, then the touch events are converted to left-mouse-button messages (WM_LBUTTON­DOWN and WM_LBUTTON­UP).

The customer's program was targeting Windows 7, so they were looking for solutions that would work on that platform.

Take our scratch program and add the following:

#include <strsafe.h> // StringCchPrintf
#include <tpcshrd.h> // WM_TABLET_QUERYSYSTEMGESTURESTATUS

BOOL
OnCreate(HWND hwnd, LPCREATESTRUCT lpcs)
{
  g_hwndChild = CreateWindow(TEXT("listbox"), NULL,
        LBS_HASSTRINGS | WS_CHILD | WS_VISIBLE | WS_VSCROLL,
        0, 0, 0, 0, hwnd, NULL, g_hinst, 0);
  return TRUE;
}

void
OnSize(HWND hwnd, UINT state, int cx, int cy)
{
    if (g_hwndChild) {
        MoveWindow(g_hwndChild, 0, 0, cx, cy/2, TRUE);
    }
}


LRESULT CALLBACK
WndProc(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
  ...
  case WM_LBUTTONDOWN:
  case WM_LBUTTONUP:
  case WM_RBUTTONDOWN:
  case WM_RBUTTONUP:
  {
    TCHAR buffer[80];
    StringCchPrintf(buffer, 80, TEXT("%04x %d %d"), uiMsg,
                    GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
    ListBox_AddString(g_hwndChild, buffer);
  }
  break;

  case WM_TABLET_QUERYSYSTEMGESTURESTATUS:
    return TABLET_DISABLE_PRESSANDHOLD;
  ...
}

Most of this code is just creating a logging window so we can see the message traffic. (Note that we divide cy by 2 in the OnSize function so that there is room at the bottom of the window for touch activity.)

The interesting part is adding a handler for the WM_TABLET_QUERY­SYSTEM­GESTURE­STATUS message and responding that we want to disable press-and-hold.

This successfully disables the press-and-hold gesture on Tablet PC (remember that?), allowing the left-button messages to be generated immediately upon contact. But it doesn't help for Windows 7 and above. For that, we need something else:

BOOL
OnCreate(HWND hwnd, LPCREATESTRUCT lpcs)
{
  g_hwndChild = CreateWindow(TEXT("listbox"), NULL,
        LBS_HASSTRINGS | WS_CHILD | WS_VISIBLE | WS_VSCROLL,
        0, 0, 0, 0, hwnd, NULL, g_hinst, 0);

  GESTURECONFIG config;
  config.dwID = 0;
  config.dwWant = 0;
  config.dwBlock = GC_ALLGESTURES;
  SetGestureConfig(hwnd, 0, 1, &config, sizeof(config));

  return TRUE;
}

This time, we disable all gestures using Set­Gesture­Config. This takes care of Windows 7 and higher.

So there are your options: There's a "Windows XP and Windows Vista" solution, and there's a "Windows 7 and higher" solution. Or you can just play it safe and use both.

Comments (6)
  1. Muzer says:

    It seems to me surprising that the new touchscreen features weren’t made to take advantage of the (admittedly few) existing things written for Tablet PC. I assume there’s a good reason for this (perhaps there were even fewer things written for it than I’m imagining so that it just wasn’t worth the time, or perhaps adding support caused more trouble than it’s worth)? Can anyone shed some light on this?

    1. Brian says:

      Apps written for XP-era Tablet PC are backwards compatible. The new APIs simply expose more functionality. SetGestureConfig was a new API for Win7 that allowed you to block ALL gestures of certain types rather than having to respond to each attempt to make a gesture. Similarly, Windows 8 introduced WM_POINTER to replace the older WM_TOUCH model (and whatever API XP Tablet Mode used – I’ve forgotten), but apps coded against those old models will still function.

      1. smf says:

        >Apps written for XP-era Tablet PC are backwards compatible. The new APIs simply expose more functionality.

        Raymond appears to be suggesting that old Tablet PC apps will only successfully disable press-and-hold on XP & not Windows 7. Which I wouldn’t consider very compatible.

        “This successfully disables the press-and-hold gesture on Tablet PC (remember that?), allowing the left-button messages to be generated immediately upon contact. But it doesn’t help for Windows 7 and above. For that, we need something else:”

        1. Ben Voigt (Visual Studio and Development Technologies MVP with C++ focus) says:

          It is a bit unclear, but I think what is happening is that the touch-and-hold gesture that existed in XP Tablet edition IS disabled. However, other gestures remain enabled, so the decision that a touch is translated to a mouse event again has to be delayed to allow for gesture detection.

          It’s not “disabling touch-and-hold” that fails on 7 and later, it’s the consequent behavior of event generation on contact, that no longer happens.

  2. Pierre B. says:

    If SetGestureConfig was introduced in Windows 7 (and MSDN confirms that), then calling it won’t make the app compatible with Windows XP and up: it just won’t run on Windows XP and Vista.

    (Unless you use GetProcAddress to get the function entry-point dynamically, of course.)

  3. IInspectable says:

    As I recall, there’s also the option to set a window property named “MicrosoftTabletPenServiceProperty” calling SetProp, that supports the same flags as the WM_TABLET_QUERYSYSTEMGESTURESTATUS message. This seems to be undocumented, with occasional MSDN entries hinting at it (like https://msdn.microsoft.com/en-us/library/ms812373.aspx). Unless my memory betrays me, this did work for Windows 7 as well.
    I’m wondering what’s the historic background, and why it isn’t documented.

  4. IInspectable says:

    As I recall, there’s also the option to set a window property named “MicrosoftTabletPenServiceProperty” calling SetProp, that supports the same flags as the WM_TABLET_QUERYSYSTEMGESTURESTATUS message. This seems to be undocumented, with occasional MSDN entries hinting at it (like https://msdn.microsoft.com/en-us/library/ms812373.aspx). Unless my memory betrays me, this did work for Windows 7 as well.
    I’m wondering what’s the historic background, and why it isn’t documented.

Comments are closed.

Skip to main content