WP 8.1 TouchEvent has incorrect coordinates on hi-res screens.

I am having an issue with the Nokia 1520 where the positions of the touch events, do not match the proper coordinates on the screen. I’m using a Windows Phone 8.1 project.

For example, I tap on the bottom-right of the screen. Debugging in XamlGame, in the OnPointerPressed method, I can see that the incoming pointerPoint is {818,455}. The LogicalDpi is reported as 144, so the point gets converted to {1227,682}. The problem is though that the screen resolution is actually 1920x1080.

This does not appear to be an issue on a Nokia 920 ( 1280x768 resolution).

I’m baffled and not sure how to fix this.
Has anybody else experienced anything similar?

This other post sounds similar:

Thanks, those links ended up being quite helpful. I eventually got this figured out from the Nokia site: UI_Framework_for_XNA_and_MonoGame_with_high_DPI_support

The trick was calculating the displaySizeCoef, and using that to scale my input.

float displaySizeCoef = 1f; // 1f = normal screen, 1.5f = 6 inch screen (items on the display will be smaller)

Arg! Well, I thought I had a solution, even though it works fine now on Lumia 520, 920, and 1520 it’s apparently not working on the Lumia Icon, which naturally I don’t have and can’t test.

It’s unfortunate that the TouchPanel.DisplayWidth and TouchPanel.DisplayHeight don’t actually match the width/height of the coordinates in the touch events.

Well… this is a really bad hack, but for the time being it fixes my problem.

        private void OnPointerPressed(DrawingSurfaceManipulationHost sender, PointerEventArgs args)
        {
            var pointerPoint = args.CurrentPoint;

            // To convert from DIPs (device independent pixels) to screen resolution pixels.
            //var dipFactor = DisplayProperties.LogicalDpi / 96.0f;
			var dipFactor = (float)WindowsPhoneGameWindow.Height / 480.0f;
			var pos = new Vector2((float)pointerPoint.Position.X, (float)pointerPoint.Position.Y) * dipFactor;
            TouchPanel.AddEvent((int)pointerPoint.PointerId, TouchLocationState.Pressed, pos);
        }

The issue seems to involve the fact that the DrawingSurface that is sending the Pointer Events is only about 800x480 (landscape in my scenario). The previous solution of using the Device’s LogicalDpi to scale the input works fine. . . . until you hit one of the larger screen sizes added in Windows Phone 8.1

I’m sure there is a better way to do this, I tried to poll the size from the DrawingSurface itself (which oddly enough is always 0,0 when I peek at it).

There is no support for 1920x1080 in the Windows Phone SDK. Phones with a Full HD screen act like they are 720p. You have to rely on some hacks to make 1080p act like it’s 1080p.

The reason for this is that when the first full HD device, the Lumia 1520 was released, they wanted existing apps to run without trouble and Microsoft probably did not want to release a new version of the SDK because of the device and drag the release of the device even further.

http://msdn.microsoft.com/en-us/library/windows/apps/jj206974(v=vs.105).aspx
“On a 1080p resolution screen, the ScaleFactor property will return 1.5, although a 2.25x scale is used internally by the OS.”

Here’s how you can detect 1080p and work with it:
http://blogs.windows.com/buildingapps/2013/11/22/taking-advantage-of-large-screen-windows-phones/

Thanks for the info, those links are quite helpful.

Should this functionality be included in the MonoGame framework? I was expecting the TouchEvents to be in relation to the full resolution of the device.

I’m not sure what your setup is, but for my situation I’ve solved this problem on a Windows Store (XAML) project in Monogame.

The issue is that the back buffer width and height are not the same as the screen resolution, so when you tap, it gets the position relative to the screen resolution. However, when you render something on XNA, it renders its position relative to the back buffer width and height. These two coordinate systems lead to the discrepancy that you are experiencing.

To solve it, I created the following methods:

 public static int GetX(int X)
            {
                return ((int)((float)X * ResolutionScaleFactor.X));
            }
    
            public static int GetY(int Y)
            {
                return ((int)((float)Y * ResolutionScaleFactor.Y));
            }

public static bool IsTapInRect(Rectangle Rect)
        {
            // Check if a gesture is NOT available, and return false if so
            if (TouchPanel.IsGestureAvailable == false) return false;

            // Get the gesture
            GestureSample gesture = TouchPanel.ReadGesture();

            // Check if the gesture was a tap
            if (gesture.GestureType == GestureType.Tap)
            {
                // Create a rectangle for the tap on the screen
                Rectangle TapRect = new Rectangle(GetX((int)gesture.Position.X), GetY((int)gesture.Position.Y), 1, 1);

                // Return true if the tap is within the Rectangle's bounds; otherwise, return false
                return Rect.Intersects(TapRect);
            }

            // A tap gesture was not found, so return false
            return false;
        }

The GetX and GetY methods multiply the preferred back buffer width and height by the resolution scale factor to get the actual X and Y coordinates on your game. They are used in the IsTapInRect method to find out whether or not a rectangle was tapped.

Here are the values that I’m using for the preferred back buffer width, height, and the resolution scale factor:

Vector2 ScreenSize = new Vector2(640, 384);

graphics.PreferredBackBufferWidth = (int)ScreenSize.X;
graphics.PreferredBackBufferHeight = (int)ScreenSize.Y;

// Get the resolution scale factor
Vector2 ResolutionScaleFactor = new Vector2((ScreenSize.X / Window.ClientBounds.Width), (ScreenSize.Y / Window.ClientBounds.Height));

I hope that helps!