How to programmatically switch Windows 11 22H2 from Tablet mode to Desktop mode?
Asked Answered
H

2

6

My Lenovo Yoga 7i laptop starts in Tablet Mode by default, so I end up with large desktop/taskbar icons and other unpleasant UI artifacts.

This can be fixed by installing and running Lenovo Yoga Mode Control for Windows, a proprietarily Lenovo service (YMC.EXE), infamous by its aggressive CPU usage.

In my case, YMC is set to Manual in Windows Service Manager. To get Windows back into Desktop mode, I have to manually start and stop YMC from an admin console: net start ymc && net stop ymc upon every system restart.

I'm looking for a programming way of doing whatever YMC is doing to switch Windows 11 to Desktop mode., to wrap it as a small utility app.

The only related answer I've found so far is this one, mentioning the undocumented ITabletModeController:

var pSP = (IServiceProvider)Activator.CreateInstance(Type.GetTypeFromCLSID(CLSID_ImmersiveShell));
var pTMC = (ITabletModeController)pSP.QueryService(typeof(ITabletModeController).GUID, typeof(ITabletModeController).GUID);
if (pTMC != null)
{
    // 0 = Desktop, 1 = Tablet
    int nMode = 0;
    int nRet = pTMC.GetMode(ref nMode);
    nRet = pTMC.SetMode(nMode==0?1:0, 4);
}

I tried it to no avail. ChatGPT hasn't been helpful, either :)

Heavyset answered 31/3, 2023 at 1:3 Comment(11)
lifewire.com/use-tablet-mode-in-windows-11-5224864Bolanger
@HansPassant, there must be some (undocumented?) COM API which is still there, as YMC is clearly using it. ChatGPT was all over it too, suggesting dead links not found even in Web Archive :)Heavyset
Can you upload that ymc.exe file somewhere?Suspicion
Hi @SimonMourier, thank you, long time no talks :) Here's the file, downloaded from here.Heavyset
Looking at the exe, it doesn't look like it's using ITabletModelController (no calls to CoCreateInstance related guids), but it talks to hardware-specific drivers, and uses WMI with custom lenovo stuff (github.com/alesya-h/linux_detect_tablet_mode and forums.lenovo.com/t5/Lenovo-Yoga-Series-Laptops/…) so it may well be working "outside of Windows" somehow.Suspicion
Also tablet mode has gone with Windows 11 learn.microsoft.com/en-us/uwp/api/… which may explain why ITabletModeController doesn't workSuspicion
@SimonMourier, thanks for your research! Looks like there's no easy solution to this, I might just settle on running and stopping YMC from a script upon login. Why Microsoft keeps killing useful APIs is beyond my understanding. I understand UWP is on life support, but this is something that should be made available outside UWP.Heavyset
You might be overcomplicating this. Windows has a setting which allows you to change your startup mode. All you need to do is go into windows settings, and search for "Choose whether to enter tablet mode when you sign in", or just search tablet and click the closest option. I still use windows 10 (even though windows 11 is out) and this works just fine.Cath
@KeshavV. if you mean this one: i.sstatic.net/IUKME.png, I have it off on my Lenovo Win11 machine, but it still boots into Tablet mode.Heavyset
Sounds like your trying to find source code Microsoft used to implement switch from tablet mode to desktop. Good luck finding that online.Stereography
@SimonMourier typical Lenovo and HP approach since ~2008 .. create custom @#%^ that takes control over system and then drop support of it a couple of year later while notebook cannot run without it properlyWoven
I
3

Okay so I am posting this as an answer because I think it would be too much for a comment. If it doesn't relate to the question please comment so I can delete it. I do not have a Lenovo Yoga 7i but my Acer Travelmate Spin also has a tablet mode.

As per GetSystemMetrics GetSystemMetrics(SM_CONVERTIBLESLATEMODE); // 0x2003 we seem to be able to read if we are in slate mode 0 or 1 where slate 0 = tablet and slate 1 = laptop or other devices according to convertibleslatemode.

The docs claim that:

Reflects the state of the laptop or slate mode, 0 for Slate Mode and non-zero otherwise. When this system metric changes, the system sends a broadcast message via WM_SETTINGCHANGE with "ConvertibleSlateMode" in the LPARAM. Note that this system metric doesn't apply to desktop PCs. In that case, use GetAutoRotationState.

I tried to do this broadcast myself via:

DWORD_PTR res;
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM) L"ConvertibleSlateMode", SMTO_ABORTIFHUNG, 1000, &res);

Which did not work.

I then realised that there was a regkey at: Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\PriorityControl called ConvertibleSlateMode which reflected the values mentioned before of slate 0 and 1.

If you are in tablet mode (slate 0) and set the value of the regkey to 1 it enters desktop mode. I am unsure if the broadcast (mentioned above) is required or not but for me it worked to (while in tablet mode) set the regkey to 0 and then to 1.

In c++ this can be done with:

void setRegKey(const DWORD value) {
    HKEY hKey;
    LONG regStatus = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\PriorityControl", 0, KEY_SET_VALUE, &hKey);

    if (regStatus != ERROR_SUCCESS) {
        std::cout << "Error opening registry key.\n";
        return;
    }

    const wchar_t* valueName = L"ConvertibleSlateMode";


    regStatus = RegSetValueExW(hKey, valueName, 0, REG_DWORD, (BYTE*)&value, sizeof(DWORD));

    if (regStatus != ERROR_SUCCESS) {
        std::cout << "Error setting registry value.\n";
        RegCloseKey(hKey);
        return;
    }

    RegCloseKey(hKey);

    std::cout << "Registry value set successfully.\n";
}

and then in main:

int main() {
    setRegKey(0);
    setRegKey(1);
}

EDIT: As mentioned by @BenVoigt and @KeshavV. you can most likely also follow this: Windows 10 tablet mode Registry setting: 'When this device automatically switches tablet mode on or off'

More related links:
GetSystemMetrics
WM_SETTINGCHANGE
SendMessageTimeout
convertibleslatemode

Inclement answered 6/4, 2023 at 16:23 Comment(7)
And possibly all he needs is to set the SigninMode registry key: https://mcmap.net/q/1777295/-windows-10-tablet-mode-registry-setting-39-when-this-device-automatically-switches-tablet-mode-on-or-off-39/103167Catrinacatriona
@BenVoigt yeah that is true! I saw the comment above mentioning it. Maybe we can edit it into this answer as well I just thought the question was asking for a script to do it.Inclement
@Inclement thanks for the research! I'll try it out and report back here.Heavyset
@Inclement this didn't do anything on my Lenovo Yoga (same as the linked answer). Lenovo must be using some propriety hardware protocol via their YMC.exe. I'll reward the bounty to your answer anyway for the research unless someone posts a better solution - thank you!Heavyset
@Heavyset that is unfortunate. Did you also try to manually write the 0 --> 1 in regedit? (that's the first thing which worked for me) I am pretty sure the broadcast can do something but I am sadly not experienced enough with that to provide a good answer. I will keep looking!Inclement
@Inclement yep I've tried that with a quick PowerShell script that ChatGPT generated for me :) Thanks for your help anyway, a well deserved bounty!Heavyset
@Heavyset you are too kind :) I hope we will figure out a solution in the futureInclement
C
3

Using the answer above, I did the procedure below:

First, open Notepad from the start menu and paste the below code:

# Define the registry path and value
$registryPath = "HKLM:\SYSTEM\CurrentControlSet\Control\PriorityControl"
$registryName = "ConvertibleSlateMode"

# Check if the registry path exists
if (Test-Path $registryPath) {
    # Get the current value of the registry key
    $currentValue = Get-ItemProperty -Path $registryPath | Select-Object -ExpandProperty $registryName
    
    # Check the current value and set the new value accordingly
    if ($currentValue -eq 0) {
        $newValue = 1
    }
    elseif ($currentValue -eq 1) {
        $newValue = 0
    }
    else {
        Write-Host "Invalid value detected: $currentValue"
        exit
    }

    # Set the registry value
    Set-ItemProperty -Path $registryPath -Name $registryName -Value $newValue -Type DWORD -Force
    Write-Host "Registry key '$registryName' set to $newValue successfully."
} else {
    Write-Host "Registry path '$registryPath' does not exist."
}

Save the file somewhere with the filename as tablet_mode.ps1 (Hint: Change "Save as type" to All Files). After saving, right-click on the file and click "Copy as Path". Right-click on any empty space on your desktop and create a new shortcut. For the location of the shortcut, enter the below:

powershell.exe -Command "& {$wd = Get-Location; Start-Process powershell.exe -Verb RunAs -ArgumentList \"-ExecutionPolicy ByPass -Command Set-Location $wd; path_to_file\tablet_mode.ps1\"}"

Replace "path_to_file\tablet_mode.ps1" with the actual file path copied above. E.g. C:\users\dummyuser\desktop\tablet.mode.ps1. Click on next, give the shortcut a name, and save. Now you can double-click on that shortcut anytime to switch from desktop to tablet mode and vice-versa.

Cadwell answered 24/3 at 16:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.