FWVGA TouchLocation incorrect

Hi eveyone,
I’ve written a small class that simulates an analog stick based on some snippets I’ve found online.

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input.Touch;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Toho
{
    internal class InputHelper
    {
        private const float OriginalThumbDist = 80f;
        private static Vector2 OriginalButtSize = new Vector2(200, 200);
        private const float InternalScale = .8f;

        private int leftId = -1; // Id del tocco sinistro
        private Vector2? leftPos; // Posizione sinistra
        private float maxThumbstickDistance = OriginalThumbDist; //  sensibilità del controller
        private Vector2 buttonSize = OriginalButtSize; // grandezza in pixel di ogni bottone
        private Color HUDColor = new Color(255, 255, 255, 200);
        /// <summary>
        /// Centro del controller sinistro
        /// </summary>
        private Vector2 LeftThumbstickCenter;
        /// <summary>
        /// Posizione del controller modificata e normalizzata (sinistro)
        /// </summary>
        private Vector2 LeftThumb
        {
            get
            {
                if (!leftPos.HasValue)
                    return Vector2.Zero;

                Vector2 l = (leftPos.Value - LeftThumbstickCenter) / maxThumbstickDistance;

                if (l.LengthSquared() > 1f)
                    l.Normalize();

                return l;
            }
        }
        /// <summary>
        /// Stato in cui possono trovarsi i bottoni virtuali
        /// </summary>
        public enum StickState
        {
            Resting,
            Up,
            Down,
            Left,
            Right,
            Center
        }
        /// <summary>
        /// Tipo di comando dei bottoni virtuali
        /// </summary>
        public enum StickCommand
        {
            StickLeftCommandLeft,
            StickLeftCommandUp,
            StickLeftCommandRight,
            StickLeftCommandDown,
            StickLeftResting,
        }
        private StickState[] oldLeftStickState = new StickState[2];
        private StickState[] newLeftStickState = new StickState[2];
        private Vector2? oldGenericPos;
        private int genericId = -1;
        private Vector2? newGenericPos;
        private Vector2 startGenericPos;

        public InputHelper()
        {
            maxThumbstickDistance = OriginalThumbDist * Globals.Scale * InternalScale;
            buttonSize = OriginalButtSize * Globals.Scale * InternalScale;
            LeftThumbstickCenter = new Vector2(Globals.ScreenWidth / 4, Globals.ScreenHeight - 100 * Globals.Scale);
        }

        public void Update(GameTime gameTime)
        {
            if (!StorageHelper.Loading)
            {
                UpdateGame();
                UpdateGeneric();
            }
        }

        /// <summary>
        /// Aggiorno il controller dei comandi durante il gameplay vero e proprio
        /// </summary>
        private void UpdateGame()
        {
            TouchLocation? leftTouch = null;
            TouchCollection touches = TouchPanel.GetState();

            foreach (var item in touches)
            {
                if(item.Id == leftId)
                {
                    leftTouch = item;
                    continue;
                }

                TouchLocation earliestTouch;
                if (!item.TryGetPreviousLocation(out earliestTouch))
                    earliestTouch = item;

                if (leftId == -1)
                {
                    if (earliestTouch.Position.X < TouchPanel.DisplayWidth / 2)
                    {
                        leftTouch = earliestTouch;
                        continue;
                    }
                }
            }

            if (leftTouch.HasValue)
            {
                leftPos = leftTouch.Value.Position;
                leftId = leftTouch.Value.Id;
            }
            else
            {
                leftPos = null;
                leftId = -1;
            }

            oldLeftStickState = newLeftStickState;
            int num = 0;
            if (Thumb_LEFT() && num < 2)
            {
                newLeftStickState[num] = StickState.Left;
                num++;
            }
            if (Thumb_RIGHT() && num < 2)
            {
                newLeftStickState[num] = StickState.Right;
                num++;
            }
            if (Thumb_TOP() && num < 2)
            {
                newLeftStickState[num] = StickState.Up;
                num++;
            }
            if(Thumb_BOT() && num < 2)
            {
                newLeftStickState[num] = StickState.Down;
                num++;
            }
            for (int i = num; i < 2; i++)
                newLeftStickState[i] = StickState.Resting;
        }

        /// <summary>
        /// Aggiorno il controller touch con posizioni genriche
        /// </summary>
        private void UpdateGeneric()
        {
            TouchLocation? touchPos = null;
            TouchCollection touches = TouchPanel.GetState();

            foreach (var item in touches)
            {
                if (item.Id == genericId)
                {
                    touchPos = item;
                    continue;
                }

                TouchLocation earliestTouch;
                if (!item.TryGetPreviousLocation(out earliestTouch))
                    earliestTouch = item;

                if (touchPos.HasValue)
                {
                    if (genericId == -1)
                        startGenericPos = touchPos.Value.Position;
                    oldGenericPos = newGenericPos;
                    newGenericPos = touchPos.Value.Position;
                    genericId = touchPos.Value.Id;
                }
                else
                {
                    oldGenericPos = newGenericPos;
                    newGenericPos = null;
                    genericId = -1;
                }
            }
        }

        public void Draw(GameTime gameTime)
        {
            if(Globals.scene.GetSceneType == Scene_Type.GamePlay)
            {
                Globals.spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.NonPremultiplied);
                Globals.spriteBatch.Draw(Globals.textureControl, LeftThumbstickCenter - buttonSize / 2, new Rectangle(200, 0, 200, 200), HUDColor, 0, Vector2.Zero, Globals.Scale * InternalScale, SpriteEffects.None, .99f);
                Globals.spriteBatch.Draw(Globals.textureControl, LeftThumb * maxThumbstickDistance + LeftThumbstickCenter - buttonSize / 2, new Rectangle(0, 0, 200, 200), HUDColor, 0, Vector2.Zero, Globals.Scale * InternalScale, SpriteEffects.None, 1);
                Globals.spriteBatch.End();
            }
        }

        /// <summary>
        /// Posizione sinistra del controller sinistro
        /// </summary>
        /// <returns>True se c'è un movimento verso sinistra</returns>
        private bool Thumb_LEFT()
        {
            if (leftPos.HasValue)
            {
                double angle = Math.Atan2(-LeftThumb.Y, LeftThumb.X);
                if (LeftThumb.Length() >= .5f && ((angle > MathHelper.Pi * 2 / 3 && angle <= MathHelper.Pi) || (angle >= -MathHelper.Pi && angle <= -MathHelper.Pi * 2 / 3)))
                {
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// Posizione destra del controller sinistro
        /// </summary>
        /// <returns>True se c'è un movimento verso destra</returns>
        private bool Thumb_RIGHT()
        {
            if (leftPos.HasValue)
            {
                double angle = Math.Atan2(-LeftThumb.Y, LeftThumb.X);
                if (LeftThumb.Length() >= .5f && ((angle > -MathHelper.Pi / 3 && angle <= 0) || (angle >= 0 && angle <= MathHelper.Pi / 3)))
                {
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// Posizione alta del controller sinistro
        /// </summary>
        /// <returns>True se c'è un movimento verso l'alto</returns>
        private bool Thumb_TOP()
        {
            if (leftPos.HasValue)
            {
                double angle = Math.Atan2(-LeftThumb.Y, LeftThumb.X);
                if (LeftThumb.Length() >= .5f && angle > MathHelper.Pi / 6 && angle <= MathHelper.Pi * 5 / 6)
                {
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// Posizione bassa del controller sinistro
        /// </summary>
        /// <returns>True se c'è un movimento verso il basso</returns>
        private bool Thumb_BOT()
        {
            if (leftPos.HasValue)
            {
                double angle = Math.Atan2(-LeftThumb.Y, LeftThumb.X);
                if (LeftThumb.Length() >= .5f && angle > -MathHelper.Pi * 5 / 6 && angle <= -MathHelper.Pi / 6)
                {
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// Controlla se il comando passato come parametro è premuto nel frame corrente e lo è stato nel frame precedente
        /// </summary>
        /// <param name="command">Tipo di comando da controllare</param>
        /// <returns></returns>
        public bool StickHold(StickCommand command)
        {
            switch (command)
            {
                case StickCommand.StickLeftCommandUp:
                    return ((newLeftStickState[0] == StickState.Up || newLeftStickState[1] == StickState.Up) && (oldLeftStickState[0] == StickState.Up || oldLeftStickState[1] == StickState.Up));
                case StickCommand.StickLeftCommandDown:
                    return ((newLeftStickState[0] == StickState.Down || newLeftStickState[1] == StickState.Down) && (oldLeftStickState[0] == StickState.Down || oldLeftStickState[1] == StickState.Down));
                case StickCommand.StickLeftCommandLeft:
                    return ((newLeftStickState[0] == StickState.Left || newLeftStickState[1] == StickState.Left) && (oldLeftStickState[0] == StickState.Left || oldLeftStickState[1] == StickState.Left));
                case StickCommand.StickLeftCommandRight:
                    return ((newLeftStickState[0] == StickState.Right || newLeftStickState[1] == StickState.Right) && (oldLeftStickState[0] == StickState.Right || oldLeftStickState[1] == StickState.Right));
            }

            return false;
        }

        /// <summary>
        /// Controlla se il comando passato come parametro è premuto nel frame corrente
        /// </summary>
        /// <param name="command">Tipo di comando da controllare</param>
        /// <returns></returns>
        public bool StickPress(StickCommand command)
        {
            switch (command)
            {
                case StickCommand.StickLeftCommandUp:
                    return (newLeftStickState[0] == StickState.Up || newLeftStickState[1] == StickState.Up);
                case StickCommand.StickLeftCommandDown:
                    return (newLeftStickState[0] == StickState.Down || newLeftStickState[1] == StickState.Down);
                case StickCommand.StickLeftCommandLeft:
                    return (newLeftStickState[0] == StickState.Left || newLeftStickState[1] == StickState.Left);
                case StickCommand.StickLeftCommandRight:
                    return (newLeftStickState[0] == StickState.Right || newLeftStickState[1] == StickState.Right);
            }

            return false;
        }

        /// <summary>
        /// Controlla se il comando passato come parametro è premuto nel frame corrente e non lo era nel frame precedente
        /// </summary>
        /// <param name="command">Tipo di comando da controllare</param>
        /// <returns></returns>
        public bool StickClick(StickCommand command)
        {
            switch (command)
            {
                case StickCommand.StickLeftCommandUp:
                    return ((newLeftStickState[0] == StickState.Up || newLeftStickState[1] == StickState.Up) && (oldLeftStickState[0] != StickState.Up && oldLeftStickState[1] != StickState.Up));
                case StickCommand.StickLeftCommandDown:
                    return ((newLeftStickState[0] == StickState.Down || newLeftStickState[1] == StickState.Down) && (oldLeftStickState[0] != StickState.Down && oldLeftStickState[1] != StickState.Down));
                case StickCommand.StickLeftCommandLeft:
                    return ((newLeftStickState[0] == StickState.Left || newLeftStickState[1] == StickState.Left) && (oldLeftStickState[0] != StickState.Left && oldLeftStickState[1] != StickState.Left));
                case StickCommand.StickLeftCommandRight:
                    return ((newLeftStickState[0] == StickState.Right || newLeftStickState[1] == StickState.Right) && (oldLeftStickState[0] != StickState.Right && oldLeftStickState[1] != StickState.Right));
            }

            return false;
        }

        /// <summary>
        /// Controlla se il comando passato come parametro non è premuto nel frame corrente e lo è stato nel frame precedente
        /// </summary>
        /// <param name="command">Tipo di comando da controllare</param>
        /// <returns></returns>
        public bool StickReverseClick(StickCommand command)
        {
            switch (command)
            {
                case StickCommand.StickLeftCommandUp:
                    return ((newLeftStickState[0] != StickState.Up && newLeftStickState[1] != StickState.Up) && (oldLeftStickState[0] == StickState.Up || oldLeftStickState[1] == StickState.Up));
                case StickCommand.StickLeftCommandDown:
                    return ((newLeftStickState[0] != StickState.Down && newLeftStickState[1] != StickState.Down) && (oldLeftStickState[0] == StickState.Down || oldLeftStickState[1] == StickState.Down));
                case StickCommand.StickLeftCommandLeft:
                    return ((newLeftStickState[0] != StickState.Left && newLeftStickState[1] != StickState.Left) && (oldLeftStickState[0] == StickState.Left || oldLeftStickState[1] == StickState.Left));
                case StickCommand.StickLeftCommandRight:
                    return ((newLeftStickState[0] != StickState.Right && newLeftStickState[1] != StickState.Right) && (oldLeftStickState[0] == StickState.Right || oldLeftStickState[1] == StickState.Right));
            }

            return false;
        }

        /// <summary>
        /// Controlla se c'è un tocco al frame corrente e al frame precendente
        /// </summary>
        /// <returns></returns>
        public bool GenericHold()
        {
            if (oldGenericPos.HasValue && newGenericPos.HasValue)
                return true;
            return false;
        }

        /// <summary>
        /// Controlla se c'è un tocco
        /// </summary>
        /// <returns></returns>
        public bool GenricPress()
        {
            if (newGenericPos.HasValue)
                return true;
            return false;
        }

        /// <summary>
        /// Controlla se c'è un tocco al frame corrente ma non al precedente
        /// </summary>
        /// <returns></returns>
        public bool GenericClick()
        {
            if (newGenericPos.HasValue && !oldGenericPos.HasValue)
                return true;
            return false;
        }

        /// <summary>
        /// Controlla se c'è un tocco al frame precedente ma non al corrente
        /// </summary>
        /// <returns></returns>
        public bool GenericReverseClick()
        {
            if (!newGenericPos.HasValue && oldGenericPos.HasValue)
                return true;
            return false;
        }

        /// <summary>
        /// Controlla che la posizione generica del tocco corrente sia all'interno di un rettangolo sia al frame corrente che al frame precedente
        /// </summary>
        /// <param name="startPosition">Punto iniziale del rettangolo. 0,0</param>
        /// <param name="endPosition">Punto finale del rettangolo. larghezza,altezza</param>
        /// <returns></returns>
        public bool GenericHold(Vector2 startPosition, Vector2 endPosition)
        {
            if (newGenericPos.HasValue && oldGenericPos.HasValue)
            {
                if (newGenericPos.Value.X >= startPosition.X && newGenericPos.Value.X <= endPosition.X &&
                    newGenericPos.Value.Y >= startPosition.Y && newGenericPos.Value.Y <= endPosition.Y &&
                    oldGenericPos.Value.X >= startPosition.X && oldGenericPos.Value.X <= endPosition.X &&
                    oldGenericPos.Value.Y >= startPosition.Y && oldGenericPos.Value.Y <= endPosition.Y &&
                    startGenericPos.X >= startPosition.X && startGenericPos.X <= endPosition.X &&
                    startGenericPos.Y >= startPosition.Y && startGenericPos.Y <= endPosition.Y)
                {
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// Controlla che la posizione generica del tocco corrente sia all'interno di un rettangolo
        /// </summary>
        /// <param name="startPosition">Punto iniziale del rettangolo. 0,0</param>
        /// <param name="endPosition">Punto finale del rettangolo. larghezza,altezza</param>
        /// <returns></returns>
        public bool GenericPress(Vector2 startPosition, Vector2 endPosition)
        {
            if (newGenericPos.HasValue)
            {
                if (newGenericPos.Value.X >= startPosition.X && newGenericPos.Value.X <= endPosition.X &&
                    newGenericPos.Value.Y >= startPosition.Y && newGenericPos.Value.Y <= endPosition.Y &&
                    startGenericPos.X >= startPosition.X && startGenericPos.X <= endPosition.X &&
                    startGenericPos.Y >= startPosition.Y && startGenericPos.Y <= endPosition.Y)
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// Controlla che la posizione generica del tocco corrente sia all'interno di un rettangolo al frame attuale ma non al frame precedente
        /// </summary>
        /// <param name="startPosition">Punto iniziale del rettangolo. 0,0</param>
        /// <param name="endPosition">Punto finale del rettangolo. larghezza,altezza</param>
        /// <returns></returns>
        public bool GenericClick(Vector2 startPosition, Vector2 endPosition)
        {
            if (newGenericPos.HasValue)
            {
                if (newGenericPos.Value.X >= startPosition.X && newGenericPos.Value.X <= endPosition.X &&
                    newGenericPos.Value.Y >= startPosition.Y && newGenericPos.Value.Y <= endPosition.Y &&
                    oldGenericPos == null &&
                    startGenericPos.X >= startPosition.X && startGenericPos.X <= endPosition.X &&
                    startGenericPos.Y >= startPosition.Y && startGenericPos.Y <= endPosition.Y)
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// Controlla che la posizione generica del tocco corrente sia all'interno di un rettangolo nel frame precedente ma non nel frame attuale
        /// </summary>
        /// <param name="startPosition">Punto iniziale del rettangolo. 0,0</param>
        /// <param name="endPosition">Punto finale del rettangolo. larghezza,altezza</param>
        /// <returns></returns>
        public bool GenericReverseClick(Vector2 startPosition, Vector2 endPosition)
        {
            if (oldGenericPos.HasValue)
            {
                if (newGenericPos == null &&
                    oldGenericPos.Value.X >= startPosition.X && oldGenericPos.Value.X <= endPosition.X &&
                    oldGenericPos.Value.Y >= startPosition.Y && oldGenericPos.Value.Y <= endPosition.Y &&
                    startGenericPos.X >= startPosition.X && startGenericPos.X <= endPosition.X &&
                    startGenericPos.Y >= startPosition.Y && startGenericPos.Y <= endPosition.Y)
                {
                    return true;
                }
            }
            return false;
        }
    }
}

I’ve tested it using the emulator on 1080p and a real device with WVGA resoultion.
I recently bought a Lumia 635 with FWVGA resolution and something is wrong with touch locations.
I read online that the resolution of the screen is a bit bigger than a standard WVGA (800x480 vs 854x480).
Game sprites ad other thing are handled correctly, but I tried stepping through the debugger and the backbuffer sizes are 800x480, which is right (if you remove the navigation bar size). But the TouchLocations are calculated using the full display resolution. Is there some kind of hack to fix this thing?

EDIT: the game I’m developing is in “Portrait” mode :wink: