{"id":93815,"date":"2016-07-06T07:00:00","date_gmt":"2016-07-06T21:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=93815"},"modified":"2020-07-19T06:20:59","modified_gmt":"2020-07-19T13:20:59","slug":"20160706-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20160706-00\/?p=93815","title":{"rendered":"How can I detect whether my PC is in tablet mode?"},"content":{"rendered":"<p><a href=\"http:\/\/windows.microsoft.com\/en-us\/windows-10\/getstarted-like-a-tablet\">Tablet Mode<\/a>, introduced in Windows 10, is a blah blah blah blah.<\/p>\n<p>Okay, enough with the introduction.<\/p>\n<p>From a Store app, you detect whether you are in tablet mode by inspecting the <code>User\u00adInteraction\u00adMode<\/code> for your view. Sample code for this is given in <a href=\"http:\/\/go.microsoft.com\/fwlink\/p\/?LinkId=619894\">the UserInteractionMode sample<\/a>, but the short version is that you do this:<\/p>\n<pre>UIViewSettings^ uiViewSettings = UIViewSettings::GetForCurrentView();\r\nUserInteractionMode mode = uiViewSettings-&gt;UserInteractionMode;\r\nswitch (mode)\r\n{\r\ncase UserInteractionMode::Touch:\r\n  \/\/ PC is in tablet mode or other touch-first environment\r\n  break;\r\n\r\ncase UserInteractionMode::Mouse:\r\n  \/\/ PC is not in tablet mode or other mouse-first environment\r\n  break;\r\n}\r\n<\/pre>\n<p>The user interaction mode is a per-view property because the system may have multiple monitors, some of which are in tablet mode and some of which aren&#8217;t. An app can detect when the user interaction mode of a view has changed by listening for the <code>Size\u00adChanged<\/code> event.<\/p>\n<p>This is a general convention for view properties: View properties that affect layout generally raise the <code>Size\u00adChanged<\/code> event when they change. The idea behind this is that this gives you a single event to trigger the recalculation of your app&#8217;s layout policy. If multiple things change at once, such as the window size, the user interaction mode, and the full-screen mode, then you run only one layout recalculation instead of three.<\/p>\n<p>Okay, that&#8217;s great for a Store app, but what about your classic desktop app? How does a classic desktop app learn whether a window is on a monitor that is in tablet mode?<\/p>\n<p>You basically do exactly the same thing as the Store app: You get the <code>UIView\u00adSettings<\/code> and ask it for the user interaction mode. The gotcha is that <code>Get\u00adFor\u00adCurrent\u00adView<\/code> doesn&#8217;t make sense in a desktop app because desktop apps don&#8217;t have have a <code>Core\u00adApplication\u00adView<\/code>.<\/p>\n<p>The answer is to use the interop interface <code>IUIView\u00adSettings\u00adInterop<\/code>. The general design pattern for the interop interface is that it each view-related static method has a corresponding method on the interop interface that takes a window handle instead of a view.<\/p>\n<p>We&#8217;ll see these as we go through the Little Program. (Remember, Little Programs do little to no error checking.) Start with <a href=\"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20030723-00\/?p=43073\">the scratch program<\/a> and make these changes:<\/p>\n<pre><span style=\"color: blue;\">#include &lt;wrl\/client.h&gt;\r\n#include &lt;wrl\/wrappers\/corewrappers.h&gt;\r\n#include &lt;windows.ui.viewmanagement.h&gt;\r\n#include &lt;UIViewSettingsInterop.h&gt;\r\n#include &lt;tchar.h&gt; \/\/ Huh? Why are you still using ANSI?\r\n\r\nnamespace WRL = Microsoft::WRL;\r\nnamespace vm = ABI::Windows::UI::ViewManagement;\r\n\r\nWRL::ComPtr&lt;vm::IUIViewSettings&gt; g_viewSettings;\r\n\r\nvm::UserInteractionMode g_mode = vm::UserInteractionMode_Mouse;<\/span>\r\n<\/pre>\n<p>So far, we&#8217;re just declaring some global thingies. In a real program, these would probably be instance members of some C++ class, but I&#8217;m being lazy.<\/p>\n<pre><span style=\"color: blue;\">void CheckTabletMode(HWND hwnd)\r\n{\r\n  if (g_viewSettings)\r\n  {\r\n    vm::UserInteractionMode currentMode;\r\n    g_viewSettings-&gt;get_UserInteractionMode(&amp;currentMode);\r\n    if (g_mode != currentMode)\r\n    {\r\n      g_mode = currentMode;\r\n      \/\/ This sample just updates some text.\r\n      InvalidateRect(hwnd, nullptr, true);\r\n    }\r\n  }\r\n}<\/span>\r\n<\/pre>\n<p>Okay, here&#8217;s the part where we read the current user interaction mode from the <code>IUIView\u00adSettings<\/code>, and if it changed, we do whatever we do when the user interact mode changes. In a real problem, we would do some relayout, but in this sample program, we&#8217;re just going to update a string, so we invalidate our window so we can draw the new string.<\/p>\n<pre>BOOL\r\nOnCreate(HWND hwnd, LPCREATESTRUCT lpcs)\r\n{\r\n  <span style=\"color: blue;\">WRL::ComPtr&lt;IUIViewSettingsInterop&gt; interop;\r\n  Windows::Foundation::GetActivationFactory(WRL::Wrappers::HStringReference(\r\n     RuntimeClass_Windows_UI_ViewManagement_UIViewSettings).Get(),\r\n     &amp;interop);\r\n\r\n  interop-&gt;GetForWindow(hwnd, IID_PPV_ARGS(&amp;g_viewSettings));\r\n\r\n  CheckTabletMode(hwnd);<\/span>\r\n  return TRUE;\r\n}\r\n<\/pre>\n<p>Okay, now things get exciting. To get the <code>UIView\u00adSettings<\/code> for a window, you first get the activation factory (which is where all the static methods hang out) and ask for the <code>IUIView\u00adSettings\u00adInterop<\/code> interface. From there, call <code>Get\u00adFor\u00adWindow<\/code>, which is the window-based version of <code>Get\u00adFor\u00adCurrent\u00adView<\/code>.<\/p>\n<p>That&#8217;s the only wrinkle. Once you have the <code>UIView\u00adSettings<\/code>, you can get its user interaction mode as usual.<\/p>\n<pre>void\r\nOnDestroy(HWND hwnd)\r\n{\r\n  <span style=\"color: blue;\">g_viewSettings.Reset();<\/span>\r\n  PostQuitMessage(0);\r\n}\r\n<\/pre>\n<p>Naturally, we need to clean up when we&#8217;re done.<\/p>\n<pre>void\r\nPaintContent(HWND hwnd, PAINTSTRUCT *pps)\r\n{\r\n  <span style=\"color: blue;\">PCTSTR message = TEXT(\"?\");\r\n\r\n  \/\/ adapt to the new mode! We just update our string.\r\n  switch (g_mode)\r\n  {\r\n  case vm::UserInteractionMode_Mouse: message = TEXT(\"Mouse\"); break;\r\n  case vm::UserInteractionMode_Touch: message = TEXT(\"Touch\"); break;\r\n  }\r\n\r\n  TextOut(pps-&gt;hdc, 0, 0, message, _tcslen(message));<\/span>\r\n}\r\n<\/pre>\n<p>Our <code>Paint\u00adContent<\/code> function prints the current mode.<\/p>\n<p>Wait, what about the <code>Size\u00adChanged<\/code> event? Oh, right, for classic Win32, you can just use the <code>WM_WINDOW\u00adPOS\u00adCHANGED<\/code> message, which will give us a chance to see if we moved to a monitor that is in a different tablet mode state from where we were before.<\/p>\n<pre><span style=\"color: blue;\">void\r\nOnWindowPosChanged(HWND hwnd, LPWINDOWPOS lpwpos)\r\n{\r\n  CheckTabletMode(hwnd);\r\n}<\/span>\r\n<\/pre>\n<p>The last wrinkle is the case where the global tablet mode state changes.<\/p>\n<pre><span style=\"color: blue;\">void OnSettingsChange(HWND hwnd, LPCTSTR sectionName)\r\n{\r\n  if (sectionName &amp;&amp;\r\n      lstrcmpi(sectionName, TEXT(\"UserInteractionMode\")) == 0)\r\n  {\r\n    CheckTabletMode(hwnd);\r\n  }\r\n}<\/span>\r\n<\/pre>\n<p>When the global tablet mode state changes, the shell broadcasts the <code>\"User\u00adInteraction\u00adMode\"<\/code> setting change notification.<\/p>\n<pre><span style=\"color: blue;\">HANDLE_MSG(hwnd, WM_WINDOWPOSCHANGED, OnWindowPosChanged);\r\nHANDLE_MSG(hwnd, WM_WININICHANGE, OnSettingsChange);<\/span>\r\n<\/pre>\n<p>And finally, we hook up our message handlers.<\/p>\n<p>There you go, a program that knows whether it is in tablet mode.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>You ask for the user interaction mode.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-93815","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>You ask for the user interaction mode.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/93815","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=93815"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/93815\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=93815"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=93815"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=93815"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}