From 3520973a5d6263cc194660961c120da8890e4c7f Mon Sep 17 00:00:00 2001 From: Dalton Smith Date: Mon, 3 Jun 2024 16:07:17 -0400 Subject: [PATCH 1/4] Adopt chromium methodology for determining tablet on Windows --- .../src/DeviceInfo/DeviceInfo.uwp.cs | 81 +++++++++++++++++-- 1 file changed, 75 insertions(+), 6 deletions(-) diff --git a/src/Essentials/src/DeviceInfo/DeviceInfo.uwp.cs b/src/Essentials/src/DeviceInfo/DeviceInfo.uwp.cs index c94c5940d078..13d33f894867 100644 --- a/src/Essentials/src/DeviceInfo/DeviceInfo.uwp.cs +++ b/src/Essentials/src/DeviceInfo/DeviceInfo.uwp.cs @@ -4,7 +4,6 @@ using Microsoft.Maui.ApplicationModel; using Windows.Security.ExchangeActiveSyncProvisioning; using Windows.System.Profile; -using Windows.UI.ViewManagement; namespace Microsoft.Maui.Devices { @@ -114,17 +113,87 @@ public DeviceType DeviceType } } - static readonly int SM_CONVERTIBLESLATEMODE = 0x2003; - static readonly int SM_TABLETPC = 0x56; + // Whether or not the device is in "tablet mode" or not + // This has to be implemented by the device manufacturer + const int SM_CONVERTIBLESLATEMODE = 0x2003; + + // Whether or not the OS supports tablet mode, usually always true + const int SM_TABLETPC = 0x56; + + // How many fingers (aka touches) are supported for touch control + const int SM_MAXIMUMTOUCHES = 95; + + // Whether a physical keyboard is attached or not + // Manufacturers have to remember to set this + // Defaults to not-attached + const int SM_ISDOCKED = 0x2004; + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] static extern int GetSystemMetrics(int nIndex); + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + static extern bool GetAutoRotationState(ref AutoRotationState pState); + + [DllImport("Powrprof.dll", SetLastError = true, CharSet = CharSet.Auto)] + static extern PowerPlatformRole PowerDeterminePlatformRoleEx(ulong Version); + static bool GetIsInTabletMode() { - var supportsTablet = GetSystemMetrics(SM_TABLETPC) != 0; - var inTabletMode = GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0; - return inTabletMode && supportsTablet; + // Adopt Chromium's methodology for determining tablet mode + // https://source.chromium.org/chromium/chromium/src/+/main:base/win/win_util.cc;l=537;drc=ac83a5a2d3c04763d86ce16d92f3904cc9566d3a;bpv=0;bpt=1 + // Device does not have a touchscreen + if (GetSystemMetrics(SM_MAXIMUMTOUCHES) == 0) + { + return false; + } + + // If the device is docked, user is treating as a PC + if (GetSystemMetrics(SM_ISDOCKED) != 0) + { + return false; + } + + // Fetch device rotation. Possible for this to fail. + AutoRotationState rotationState = AutoRotationState.AR_ENABLED; + bool success = GetAutoRotationState(ref rotationState); + + // Fetch succeeded and device does not support rotation + if (success && rotationState.HasFlag(AutoRotationState.AR_NOT_SUPPORTED | AutoRotationState.AR_LAPTOP | AutoRotationState.AR_NOSENSOR)) + { + return false; + } + + // Check if power management says we are mobile (laptop) or a tablet + if (PowerDeterminePlatformRoleEx(2).HasFlag(PowerPlatformRole.PlatformRoleMobile | PowerPlatformRole.PlatformRoleSlate)) + { + // Check if tablet mode is 0. 0 is default value. + return GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0; + } + + return false; } } + + /// + /// Represents the OEM's preferred power management profile, + /// Useful in-case OEM implements one but not the other + /// + enum PowerPlatformRole + { + PlatformRoleMobile = 2, + PlatformRoleSlate = 8, + } + + /// + /// Whether rotation is supported or not. + /// Rotation is only supported if AR_ENABLED is true + /// + enum AutoRotationState + { + AR_ENABLED, + AR_NOT_SUPPORTED, + AR_LAPTOP, + AR_NOSENSOR, + } } From 3546c3bb3a26717faf937c72ee1b844aa2ebc44a Mon Sep 17 00:00:00 2001 From: Dalton Smith Date: Mon, 3 Jun 2024 16:15:04 -0400 Subject: [PATCH 2/4] Fix auto rotation state enums being incorrect --- src/Essentials/src/DeviceInfo/DeviceInfo.uwp.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Essentials/src/DeviceInfo/DeviceInfo.uwp.cs b/src/Essentials/src/DeviceInfo/DeviceInfo.uwp.cs index 13d33f894867..55be33dbef05 100644 --- a/src/Essentials/src/DeviceInfo/DeviceInfo.uwp.cs +++ b/src/Essentials/src/DeviceInfo/DeviceInfo.uwp.cs @@ -191,9 +191,9 @@ enum PowerPlatformRole /// enum AutoRotationState { - AR_ENABLED, - AR_NOT_SUPPORTED, - AR_LAPTOP, - AR_NOSENSOR, + AR_ENABLED = 0x0, + AR_NOT_SUPPORTED = 0x20, + AR_LAPTOP = 0x80, + AR_NOSENSOR = 0x10, } } From a7bb552033ed004f475fb4a714c16a5a7e16adcb Mon Sep 17 00:00:00 2001 From: Dalton Smith Date: Mon, 3 Jun 2024 16:28:37 -0400 Subject: [PATCH 3/4] Fix bitfield comparison --- src/Essentials/src/DeviceInfo/DeviceInfo.uwp.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Essentials/src/DeviceInfo/DeviceInfo.uwp.cs b/src/Essentials/src/DeviceInfo/DeviceInfo.uwp.cs index 55be33dbef05..91d030fd929b 100644 --- a/src/Essentials/src/DeviceInfo/DeviceInfo.uwp.cs +++ b/src/Essentials/src/DeviceInfo/DeviceInfo.uwp.cs @@ -159,13 +159,13 @@ static bool GetIsInTabletMode() bool success = GetAutoRotationState(ref rotationState); // Fetch succeeded and device does not support rotation - if (success && rotationState.HasFlag(AutoRotationState.AR_NOT_SUPPORTED | AutoRotationState.AR_LAPTOP | AutoRotationState.AR_NOSENSOR)) + if (success && (rotationState & (AutoRotationState.AR_NOT_SUPPORTED | AutoRotationState.AR_LAPTOP | AutoRotationState.AR_NOSENSOR)) != 0) { return false; } // Check if power management says we are mobile (laptop) or a tablet - if (PowerDeterminePlatformRoleEx(2).HasFlag(PowerPlatformRole.PlatformRoleMobile | PowerPlatformRole.PlatformRoleSlate)) + if ((PowerDeterminePlatformRoleEx(2) & (PowerPlatformRole.PlatformRoleMobile | PowerPlatformRole.PlatformRoleSlate)) != 0) { // Check if tablet mode is 0. 0 is default value. return GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0; From 252e380fc58dc9979600669ca8151490a30edb3f Mon Sep 17 00:00:00 2001 From: Dalton Smith Date: Tue, 4 Jun 2024 11:19:03 -0400 Subject: [PATCH 4/4] Remove unused const, refactor comments --- .../src/DeviceInfo/DeviceInfo.uwp.cs | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/Essentials/src/DeviceInfo/DeviceInfo.uwp.cs b/src/Essentials/src/DeviceInfo/DeviceInfo.uwp.cs index 91d030fd929b..5b1034d10fbf 100644 --- a/src/Essentials/src/DeviceInfo/DeviceInfo.uwp.cs +++ b/src/Essentials/src/DeviceInfo/DeviceInfo.uwp.cs @@ -113,19 +113,22 @@ public DeviceType DeviceType } } - // Whether or not the device is in "tablet mode" or not - // This has to be implemented by the device manufacturer + /// + /// Whether or not the device is in "tablet mode" or not. This + /// has to be implemented by the device manufacturer. + /// const int SM_CONVERTIBLESLATEMODE = 0x2003; - // Whether or not the OS supports tablet mode, usually always true - const int SM_TABLETPC = 0x56; - - // How many fingers (aka touches) are supported for touch control + /// + /// How many fingers (aka touches) are supported for touch control + /// const int SM_MAXIMUMTOUCHES = 95; - // Whether a physical keyboard is attached or not - // Manufacturers have to remember to set this - // Defaults to not-attached + /// + /// Whether a physical keyboard is attached or not. + /// Manufacturers have to remember to set this. + /// Defaults to not-attached. + /// const int SM_ISDOCKED = 0x2004;