5
\$\begingroup\$

I have an application on win7 which needs to support touch and mouse input using monogame. But reading touch taps proves to be a very hard thing.

The TouchPanel is initialized like this:

TouchPanel.EnableMouseTouchPoint = true;
TouchPanel.EnabledGestures = GestureType.Tap | GestureType.DoubleTap | GestureType.Hold | GestureType.Pinch |
                             GestureType.FreeDrag | GestureType.DragComplete | GestureType.Flick | GestureType.HorizontalDrag |
                             GestureType.VerticalDrag;
TouchPanel.EnableMouseGestures = true;

Without EnableMouseTouchPoint and EnableMouseGestures there is no reaction from the touchscreen. Enabling both will at least get me touch locations and gestures on drag moves (this already makes me think that there is something essential missing here).

I have the following code to read input which is called on every Update:

private void GetInput(GameTime gameTime)
    {
        var gesture = default(GestureSample);
        MouseState mouseState = Mouse.GetState();

        TouchCollection touchCol = TouchPanel.GetState();
        foreach (var touch in touchCol)
        {
            Console.WriteLine(touch.Position);                
        }

        while (TouchPanel.IsGestureAvailable)
        {
            gesture = TouchPanel.ReadGesture();
            Console.WriteLine(gesture.GestureType);
            if (gesture.GestureType == GestureType.Tap)
            {
                DoHitTest(mouseState.X, mouseState.Y);
            }                
        }
     }

The touch collection will remain empty until the finger is dragged across the screen. Taps are not showing up. To get an actual tap i have to do a very short flick. In this case, there is a touch in the touch collection.

What am i missing? Am i doing something fundamentally wrong here?

\$\endgroup\$
1
\$\begingroup\$

I just had this same problem with Monogame on Windows 7. The problem is that Win7 doesn't support WM_POINTERxxx messages, but instead sends WM_TOUCH messages (which are not handled by MonoGame). And for some reason, short flicks get translated into fake mouse events which are then picked up by MonoGame.

There are two solutions:

  1. Decide to use Windows 8 and skip support for Windows 7, or

  2. Register the window for legacy touch events by p/invoking RegisterTouchWindow from user32, and then add handlers for WM_TOUCH, as described in this article.

Even after doing this, depending on your touch screen driver, you might get awkward touch events now and then (like the long-press right click, which seems impossible to disable in Windows 7). Which is the reason why XNA initially chose not to support touch on desktops (prior to Windows 8 which introduced proper touch handling).

\$\endgroup\$
0
\$\begingroup\$

I have a game using MonoGame that supports touch and mouse. It is sort of a hack. Essentially I use conditionals to see if it is a touchscreen. If it is, I use gst = TouchPanel.ReadGesture();. If not, I "fake" the gesture by detecting the mouse state and coding it accordingly:

#if (!WINDOWS_APP)
            while (TouchPanel.IsGestureAvailable)
            {
                GestureSample gst = TouchPanel.ReadGesture();
#else
            int use = 0;
            while (use < 1)
            {
                use++;
                MouseState ms = Mouse.GetState();
                GestureSample gst = new GestureSample();
                if (ms.ScrollWheelValue != PreviousScrollState) { gst = new GestureSample(GestureType.FreeDrag, gameTime.ElapsedGameTime, new Vector2(), new Vector2(), new Vector2(0, (ms.ScrollWheelValue - PreviousScrollState)/3), new Vector2()); }
                else if (ms.LeftButton == ButtonState.Released && PreviousState == ButtonState.Pressed) { PreviousDragPosition = Vector2.Zero; gst = new GestureSample(GestureType.Tap, gameTime.ElapsedGameTime, new Vector2(ms.X, ms.Y), new Vector2(), new Vector2(), new Vector2()); }
                else if (ms.LeftButton == ButtonState.Pressed && PreviousState == ButtonState.Released) { PreviousDragPosition = new Vector2(ms.X, ms.Y); }
                else if (ms.LeftButton == ButtonState.Pressed && PreviousState == ButtonState.Pressed) { gst = new GestureSample(GestureType.FreeDrag, gameTime.ElapsedGameTime, PreviousDragPosition, new Vector2(), (Vector2.Distance(PreviousDragPosition, new Vector2(ms.X, ms.Y)) >= 2) ? -new Vector2(PreviousDragPosition.X - ms.X, PreviousDragPosition.Y - ms.Y) : Vector2.Zero, new Vector2()); PreviousDragPosition = new Vector2(ms.X, ms.Y); }
                PreviousState = ms.LeftButton;
                PreviousScrollState = ms.ScrollWheelValue;
#endif
                // Do stuff with the 'gst' variable
            }

I also pre-define these variables somewhere:

ButtonState PreviousState = ButtonState.Released;
int PreviousScrollState = Mouse.GetState().ScrollWheelValue;
Vector2 PreviousDragPosition = Vector2.Zero;

This code will detect taps and drags (which are the only gestures my games uses). It will consider scrolling a FreeDrag in the vertical direction, and will correctly detect dragging the mouse across the screen.

\$\endgroup\$
1
  • \$\begingroup\$ If you set TouchPanel.EnableMouseTouchPoint to true, you should get mouse events through TouchPanel.GetState() also, so there is no need to implement this yourself. \$\endgroup\$
    – Groo
    Dec 24 '15 at 8:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.