Detecting a 2in1 convertable's state using C#

Detecting a 2in1 convertable's state using C#

I thought I'd add this here since Intel already has great docs up on how to do this using C++.  I wanted to be able to detect the state change in a WPF application.  Fortunately it's not overly difficult but just technical enough that it might not be obvious.

Below is a copy/paste from my blog: http://www.themethodology.net/2014/05/detecting-2-in-1-state-using-wpf-c... 

 

I’ve been wanting to experiment with changing UIs in my code between “tablet” mode and the “laptop” mode on my new Dell XPS 12 (or any other Ultrabook 2 in 1 that happened across my desk).  There’s already a really great article on how us developers can detect the state change on Intel’s developer portal; but the example code is in C++ and not my preferred C#.

Before we go any further, I recommend heading over to software.intel.com and reading Detecting Slate/Clamshell Mode & Screen Orientation in a 2 in 1.

The code we’re looking to implement is basically this (done in a WndProc):

   1: case WM_SETTINGCHANGE:
   2:     if (wcscmp ( TEXT ("ConvertableSlateMode"), (TCHAR*)lParam ) == 0)
   3:         NotifySlateModeChange ();
   4:    else if wcscmp ( TEXT ("SystemDockMode"), (TCHAR*)lParam ) == 0)
   5:         NotifyDockingModeChange ();
Simply stated, we need to monitor WM_SETTINGCHANGE or equivalent, detect which state we’re in, and respond accordingly.
Now that we know what our goal is, let’s make it work in a modern WPF C# application.  I looked a few approaches before settling on my solution, and hopefully it will make sense why I’ve done it this way as we work through the code.
Our first step is to import user32.dll so we can define and use the GetSystemMetrics method.

 

 

   1: public partial class MainWindow : Window
   2: {
   3:     [DllImport("user32.dll")]
   4:     static extern int GetSystemMetrics(SystemMetric smIndex);
   5:     ...

 

 

 

To do that we’ll need to reference the InteropServices:

using System.Runtime.InteropServices;
At this point you may have noticed that we don’t have the SystemMetric enum defined.  We could create our own with just the two metrics we need, but we might as well jump over to www.pinvoke.net and get a fairly complete enum, and just copy that into our window class or somewhere else convenient (this might just be useful for other purposes as well):
http://www.pinvoke.net/default.aspx/Enums/SystemMetric.html 
Unfortunately this list doesn’t contain the two metrics we want to check against as we saw in the Intel doc, namely
SM_CONVERTABLESLATEMODE and SM_SYSTEMDOCKED
so we’ll add these to the end of the enum ourselves:

 

 

   1: public enum SystemMetric
   2: {   
   3:    ...    
   4:    SM_CONVERTABLESLATEMODE = 0x2003,    
   5:    SM_SYSTEMDOCKED = 0x2004
   6: }

 

(* after writing this post I decided I should update the pinvoke.net page so the enum should now be up to date)
We’re almost ready to watch for the 2 in 1 state change.  In C++ we would just capture the WM_SETTINGSCHANGED message.
We could do this in C# by overriding OnSourceInitialized() and hooking into the WndProc.  Truth be told this was my first approach.  But on my machine I wasn’t receiving “SystemDockMode” from the lParam – it would always give me “ConvertableSlateMode” regardless of the state.  
So I decided to do it the “C# way” and just watch UserPreferenceChanging.  To try it out just add 

 

 

   1: SystemEvents.UserPreferenceChanging += SystemEvents_UserPreferenceChanging; 
to the constructor and create a method with the correct signature.  You’ll need to include “using Microsoft.Win32;” for SystemEvents.
We’ll get a UserPreferenceChanging event every time the device changes state, and it will come in under the General Category of UserPreferenceCategory. This is passed in with the UserPreferenceChagingEventArgs.  Unfortunately we don’t get any additional information, and we don’t have access to the lParam as we would if we were handling the message directly.
And that’s where the GetSystemMetrics() method comes in.  We’ll simply query for the state every time we change comes in under the General category.  Uou’ll likely want to add some logic to remember your current state and only update your UI if it changes.
See the code below: 

 

 

   1: void SystemEvents_UserPreferenceChanging(object sender, UserPreferenceChangingEventArgs e)
   2: {    
   3:     if(e.Category == UserPreferenceCategory.General)    
   4:     {        
   5:         if (GetSystemMetrics(SystemMetric.SM_CONVERTABLESLATEMODE) == 0)        
   6:         {            
   7:             Debug.WriteLine("detected slate mode");        
   8:         }        
   9:         else if (GetSystemMetrics(SystemMetric.SM_SYSTEMDOCKED) == 0)        
  10:         {            
  11:             Debug.WriteLine("detected docked mode");        
  12:         }    
  13:     }
  14: }

And that should give you everything you need to get started making 2 in 1 C# apps in WPF. 

 

Finally, there’s a sample project with all of the above code on github here:

https://github.com/adrianstevens/WPF-CSharp-2in1-mode-detection

 

http://www.themethodology.net
http://www.vancouvermobile.net
publicaciones de 5 / 0 nuevos
Último envío
Para obtener más información sobre las optimizaciones del compilador, consulte el aviso sobre la optimización.

Very good post. Congratulations.

I could make it work with Windows Application, but not with a Windows application by RT can not import the Win32.

Do you have any idea how to solve?

Hi Leandro,

I'm very glad to hear you got it working.

I haven't tried it with an RT app yet.  I suspect what you would need to do is create a C++ library using the Intel example code and then reference it from your C# Windows Store project.  

I'll look into this week and I'll post again if I make any progress.

Cheers

Adrian

 

 

http://www.themethodology.net
http://www.vancouvermobile.net

Hi Leandro and Adrian,

Here it is: https://github.com/ITSoftin/DeviceExtCapabilitiesUniversal

Cheers,

Breno S.

Fantastic thanks - and nice job!

http://www.themethodology.net
http://www.vancouvermobile.net

Deje un comentario

Por favor inicie sesión para agregar un comentario. ¿No es socio? Únase ya