@@ -109,16 +109,89 @@ public DeviceType DeviceType
109109 }
110110 }
111111
112- static readonly int SM_CONVERTIBLESLATEMODE = 0x2003 ;
113- static readonly int SM_TABLETPC = 0x56 ;
112+ /// <summary>
113+ /// Whether or not the device is in "tablet mode" or not. This
114+ /// has to be implemented by the device manufacturer.
115+ /// </summary>
116+ const int SM_CONVERTIBLESLATEMODE = 0x2003 ;
117+
118+ /// <summary>
119+ /// How many fingers (aka touches) are supported for touch control
120+ /// </summary>
121+ const int SM_MAXIMUMTOUCHES = 95 ;
122+
123+ /// <summary>
124+ /// Whether a physical keyboard is attached or not.
125+ /// Manufacturers have to remember to set this.
126+ /// Defaults to not-attached.
127+ /// </summary>
128+ const int SM_ISDOCKED = 0x2004 ;
129+
114130
115131 [ DllImport ( "user32.dll" , SetLastError = true , CharSet = CharSet . Auto ) ]
116132 static extern int GetSystemMetrics ( int nIndex ) ;
117133
134+ [ DllImport ( "user32.dll" , SetLastError = true , CharSet = CharSet . Auto ) ]
135+ static extern bool GetAutoRotationState ( ref AutoRotationState pState ) ;
136+
137+ [ DllImport ( "Powrprof.dll" , SetLastError = true , CharSet = CharSet . Auto ) ]
138+ static extern PowerPlatformRole PowerDeterminePlatformRoleEx ( ulong Version ) ;
139+
118140 static bool GetIsInTabletMode ( )
119141 {
120- var supportsTablet = GetSystemMetrics ( SM_TABLETPC ) != 0 ;
121- var inTabletMode = GetSystemMetrics ( SM_CONVERTIBLESLATEMODE ) == 0 ;
122- return inTabletMode && supportsTablet ;
142+ // Adopt Chromium's methodology for determining tablet mode
143+ // https://source.chromium.org/chromium/chromium/src/+/main:base/win/win_util.cc;l=537;drc=ac83a5a2d3c04763d86ce16d92f3904cc9566d3a;bpv=0;bpt=1
144+ // Device does not have a touchscreen
145+ if ( GetSystemMetrics ( SM_MAXIMUMTOUCHES ) == 0 )
146+ {
147+ return false ;
148+ }
149+
150+ // If the device is docked, user is treating as a PC
151+ if ( GetSystemMetrics ( SM_ISDOCKED ) != 0 )
152+ {
153+ return false ;
154+ }
155+
156+ // Fetch device rotation. Possible for this to fail.
157+ AutoRotationState rotationState = AutoRotationState . AR_ENABLED ;
158+ bool success = GetAutoRotationState ( ref rotationState ) ;
159+
160+ // Fetch succeeded and device does not support rotation
161+ if ( success && ( rotationState & ( AutoRotationState . AR_NOT_SUPPORTED | AutoRotationState . AR_LAPTOP | AutoRotationState . AR_NOSENSOR ) ) != 0 )
162+ {
163+ return false ;
164+ }
165+
166+ // Check if power management says we are mobile (laptop) or a tablet
167+ if ( ( PowerDeterminePlatformRoleEx ( 2 ) & ( PowerPlatformRole . PlatformRoleMobile | PowerPlatformRole . PlatformRoleSlate ) ) != 0 )
168+ {
169+ // Check if tablet mode is 0. 0 is default value.
170+ return GetSystemMetrics ( SM_CONVERTIBLESLATEMODE ) == 0 ;
171+ }
172+
173+ return false ;
123174 }
124175}
176+
177+ /// <summary>
178+ /// Represents the OEM's preferred power management profile,
179+ /// Useful in-case OEM implements one but not the other
180+ /// </summary>
181+ enum PowerPlatformRole
182+ {
183+ PlatformRoleMobile = 2 ,
184+ PlatformRoleSlate = 8 ,
185+ }
186+
187+ /// <summary>
188+ /// Whether rotation is supported or not.
189+ /// Rotation is only supported if AR_ENABLED is true
190+ /// </summary>
191+ enum AutoRotationState
192+ {
193+ AR_ENABLED = 0x0 ,
194+ AR_NOT_SUPPORTED = 0x20 ,
195+ AR_LAPTOP = 0x80 ,
196+ AR_NOSENSOR = 0x10 ,
197+ }
0 commit comments