This project demonstrates how to detect which mode a 2 in 1 laptop is in (slate vs. clamshell) on Windows* 8(.1) as well as Windows® 10’s new mouse and touch mode. Even though mouse / touch mode is similar in concept to slate / clamshell mode, Windows 10 has a new capability for users to override the mode, while Windows 8 depended only on the physical state of the convertible. Therefore, Windows 10 users are able to use the enhanced GUI designed for touch even if the machine is not a convertible as long as it has a touch screen (such as All-in-One). This new capability is based on the new UWP (Universal Windows Platform) APIs, and you’ll need to add a few lines of code to Windows 8 apps to take advantage of this feature for Windows 10. This white paper shows you how to enable Win32 apps to take advantage of the UWP APIs via WRL (Windows Runtime C++ Template Library) on Windows 10. For enabling UWP apps directly, refer to the sample code from Microsoft.
Requirements
- Windows 10
- Visual Studio* 2015. The new API doesn’t exist on Visual Studio 2013
Windows 10 Mouse and Touch Mode Overview
- Manual setting
- Slide in from the right and the Action Center will show up (known as charm menu on Windows 8).
- Tap the “Tablet mode” button to toggle between touch and mouse modes.
- Hardware-assisted setting
- When the convertible detects physical state changes, it notifies the OS.
- The OS asks the user to confirm. If the user confirms, the OS will toggle the mode.
- For testing purposes, go to Settings->System->Tablet mode and set the preferences to “Always ask me before switching.”
Sample App
Depending on the OS, the sample application, a dialog-based app, will either:
- Windows 10 - log the touch / mouse mode event and time, either from the manual settings or automatic switch.
- Windows 8 - report the physical state change events and the time (slate / clamshell mode.)
Just as Windows 8 broadcasts WM_SETTINGCHANGE (lParam == “ConvertibleSlateMode”) message for physical state changes, Windows 10 broadcasts WM_SETTINGCHANGE (lParam == “UserInteractionMode”) to the top-level window. However, it also broadcasts the old message as well. The application needs to detect the OS version and provide a different code path depending on it. Otherwise, it will end up responding to the messages twice on Windows 10.
void CMy2in1LogDlg::OnSettingChange(UINT uFlags, LPCTSTR lpszSection) { CDialogEx::OnSettingChange(uFlags, lpszSection); // TODO: Add your message handler code here if (lpszSection != NULL) { CString strMsg = CString(lpszSection); if (m_dwVersionMajor < 10 && strMsg == _T("ConvertibleSlateMode")) { CString strTime; GetTime(strTime); BOOL bSlate = GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0; CString strMsg = CString(bSlate ? _T("Slate Mode") : _T("Clamshell Mode")); m_ctrlEvents.InsertItem(m_iEvent, strTime); m_ctrlEvents.SetItemText(m_iEvent, 1, strMsg); m_iEvent++; return; } if (m_dwVersionMajor >= 10 && strMsg == _T("UserInteractionMode")) { CString strTime, strMsg; GetTime(strTime); int mode; if (GetUserInteractionMode(mode) == S_OK) { if (mode == UserInteractionMode_Mouse) strMsg.Format(_T("Mouse Mode")); else if (mode == UserInteractionMode_Touch) strMsg.Format(_T("Touch Mode")); m_ctrlEvents.InsertItem(m_iEvent, strTime); m_ctrlEvents.SetItemText(m_iEvent, 1, strMsg); m_iEvent++; } } } }
Once the application receives the message, it queries the current state because the message only notifies the OS of the mode change, but not what state it is. There is no Win32 API to directly query the new states, but WRL can be used to access Windows RT components from Win32 app as illustrated in the following code snippet.
HRESULT CMy2in1LogDlg::GetUserInteractionMode(int & iMode) { ComPtr<IUIViewSettingsInterop> uiViewSettingsInterop; HRESULT hr = GetActivationFactory( HStringReference(RuntimeClass_Windows_UI_ViewManagement_UIViewSettings).Get(), &uiViewSettingsInterop); if (SUCCEEDED(hr)) { ComPtr<IUIViewSettings> uiViewSettings; hr = uiViewSettingsInterop->GetForWindow(this->m_hWnd, IID_PPV_ARGS(&uiViewSettings)); if (SUCCEEDED(hr)) { UserInteractionMode mode; hr = uiViewSettings->get_UserInteractionMode(&mode); if (SUCCEEDED(hr)) { switch (mode) { case UserInteractionMode_Mouse: iMode = UserInteractionMode_Mouse; break; case UserInteractionMode_Touch: iMode = UserInteractionMode_Touch; break; default: break; } } } } return S_OK; }
Conclusion & Other Possibilities
This sample code shows how to enable 2 in 1 detection on Windows 8/8.1 and Windows 10 using Win32. It was not possible to detect 2 in 1 events on Windows Store Apps on Windows 8. With Windows 10, UWP APIs are provided so that universal apps can take advantage of 2 in 1 capability. Instead of providing a comparable Win32 API, a method to use the UWP API from Win32 app is presented. It may be worthwhile to note that UWP APIs do not have a specific notification for this, but use window resize events, followed by verifying the current state. If the state is different from the saved state, the state has changed. If it is not convenient to use Win32 messages (as in Java* applications), you can use Java’s window resize event and call the JNI wrapper to confirm the state.
License
Intel sample sources are provided to users under the Intel Sample Source Code License Agreement.