Skip to content

Commit 241fde9

Browse files
committed
Added option to choose language switcher flyout style; fixed #283
1 parent ae11b73 commit 241fde9

File tree

5 files changed

+138
-5
lines changed

5 files changed

+138
-5
lines changed

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,18 @@
22

33
This document includes the same release notes as in the [Releases](https://github.com/valinet/ExplorerPatcher/releases) section on GitHub.
44

5+
## 22000.282.33
6+
7+
Tested on build 22000.282.
8+
9+
#### New features
10+
11+
* Ability to choose language switcher flyout style (option available in the "Properties" - "System tray" section)
12+
13+
#### Fixes
14+
15+
* The key above the `Tab` key is now correctly identified for all keyboard layouts, so the per-application Windows 10 window switcher mode works correctly (#283)
16+
517
## 22000.282.32
618

719
Tested on build 22000.282.

ExplorerPatcher/ExplorerPatcher.rc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ END
5151
//
5252

5353
VS_VERSION_INFO VERSIONINFO
54-
FILEVERSION 22000,282,32,7
55-
PRODUCTVERSION 22000,282,32,7
54+
FILEVERSION 22000,282,33,0
55+
PRODUCTVERSION 22000,282,33,0
5656
FILEFLAGSMASK 0x3fL
5757
#ifdef _DEBUG
5858
FILEFLAGS 0x1L
@@ -69,12 +69,12 @@ BEGIN
6969
BEGIN
7070
VALUE "CompanyName", "VALINET Solutions SRL"
7171
VALUE "FileDescription", "ExplorerPatcher"
72-
VALUE "FileVersion", "22000.282.32.7"
72+
VALUE "FileVersion", "22000.282.33.0"
7373
VALUE "InternalName", "ExplorerPatcher.dll"
7474
VALUE "LegalCopyright", "Copyright (C) 2006-2021 VALINET Solutions SRL. All rights reserved."
7575
VALUE "OriginalFilename", "ExplorerPatcher.dll"
7676
VALUE "ProductName", "ExplorerPatcher"
77-
VALUE "ProductVersion", "22000.282.32.7"
77+
VALUE "ProductVersion", "22000.282.33.0"
7878
END
7979
END
8080
BLOCK "VarFileInfo"

ExplorerPatcher/dllmain.c

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#define _LIBVALINET_DEBUG_HOOKING_IATPATCH
3030
#endif
3131
#include <valinet/hooking/iatpatch.h>
32+
#include <valinet/utility/memmem.h>
3233

3334
#define EP_CLSID "{D17F1E1A-5919-4427-8F89-A1A8503CA3EB}"
3435

@@ -66,6 +67,7 @@ DWORD bClassicThemeMitigations = FALSE;
6667
DWORD bHookStartMenu = TRUE;
6768
DWORD bNoMenuAccelerator = FALSE;
6869
DWORD bTaskbarMonitorOverride = 0;
70+
DWORD dwIMEStyle = 0;
6971
HMODULE hModule = NULL;
7072
HANDLE hSettingsMonitorThread = NULL;
7173
HANDLE hDelayedInjectionThread = NULL;
@@ -2941,6 +2943,15 @@ void WINAPI LoadSettings(BOOL bIsExplorer)
29412943
&bTaskbarMonitorOverride,
29422944
&dwSize
29432945
);
2946+
dwSize = sizeof(DWORD);
2947+
RegQueryValueExW(
2948+
hKey,
2949+
TEXT("IMEStyle"),
2950+
0,
2951+
NULL,
2952+
&dwIMEStyle,
2953+
&dwSize
2954+
);
29442955
RegCloseKey(hKey);
29452956
}
29462957

@@ -3613,6 +3624,7 @@ HRESULT explorer_DrawThemeTextEx(
36133624
#pragma endregion
36143625

36153626

3627+
#pragma region "Change clock links"
36163628
HINSTANCE explorer_ShellExecuteW(
36173629
HWND hwnd,
36183630
LPCWSTR lpOperation,
@@ -3640,6 +3652,102 @@ HINSTANCE explorer_ShellExecuteW(
36403652
}
36413653
return ShellExecuteW(hwnd, lpOperation, lpFile, lpParameters, lpDirectory, nShowCmd);
36423654
}
3655+
#pragma endregion
3656+
3657+
3658+
#pragma region "Change language UI style"
3659+
DEFINE_GUID(CLSID_InputSwitchControl,
3660+
0xB9BC2A50,
3661+
0x43C3, 0x41AA, 0xa0, 0x86,
3662+
0x5D, 0xB1, 0x4e, 0x18, 0x4b, 0xae
3663+
);
3664+
3665+
DEFINE_GUID(IID_InputSwitchControl,
3666+
0xB9BC2A50,
3667+
0x43C3, 0x41AA, 0xa0, 0x82,
3668+
0x5D, 0xB1, 0x4e, 0x18, 0x4b, 0xae
3669+
);
3670+
3671+
#define LANGUAGEUI_STYLE_DESKTOP 0
3672+
#define LANGUAGEUI_STYLE_TOUCHKEYBOARD 1
3673+
#define LANGUAGEUI_STYLE_LOGONUI 2
3674+
#define LANGUAGEUI_STYLE_UAC 3
3675+
#define LANGUAGEUI_STYLE_SETTINGSPANE 4
3676+
#define LANGUAGEUI_STYLE_OOBE 5
3677+
#define LANGUAGEUI_STYLE_OTHER 100
3678+
3679+
char mov_edx_val[6] = { 0xBA, 0x00, 0x00, 0x00, 0x00, 0xC3 };
3680+
char* ep_pf = NULL;
3681+
3682+
HRESULT explorer_CoCreateInstanceHook(
3683+
REFCLSID rclsid,
3684+
LPUNKNOWN pUnkOuter,
3685+
DWORD dwClsContext,
3686+
REFIID riid,
3687+
LPVOID* ppv
3688+
)
3689+
{
3690+
if (IsEqualCLSID(rclsid, &CLSID_InputSwitchControl) && IsEqualIID(riid, &IID_InputSwitchControl))
3691+
{
3692+
HRESULT hr = CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv);
3693+
if (SUCCEEDED(hr))
3694+
{
3695+
// Pff... how this works:
3696+
//
3697+
// * This `CoCreateInstance` call will get a pointer to an IInputSwitchControl interface
3698+
// (the call to here is made from `explorer!CTrayInputIndicator::_RegisterInputSwitch`);
3699+
// the next call on this pointer will be on the `IInputSwitchControl::Init` function.
3700+
//
3701+
// * `IInputSwitchControl::Init`'s second parameter is a number (x) which tells which
3702+
// language switcher UI to prepare (check `IsUtil::MapClientTypeToString` in
3703+
// `InputSwitch.dll`). "explorer" requests the "DESKTOP" UI (x = 0), which is the new
3704+
// Windows 11 UI; if we replace that number with something else, some other UI will
3705+
// be created
3706+
//
3707+
// * We cannot patch the vtable of the COM object because the executable is protected
3708+
// by control flow guard and we would make a jump to an invalid site (maybe there is
3709+
// some clever workaround fpr this as well, somehow telling the compiler to place a certain
3710+
// canary before our trampoline, so it matches with what the runtime support for CFG expects,
3711+
// but we'd have to keep that canary in sync with the one in explorer.exe, so not very
3712+
// future proof).
3713+
//
3714+
// * Taking advantage of the fact that the call to `IInputSwitchControl::Init` is the thing
3715+
// that happens right after we return from here, and looking on the disassembly, we see nothing
3716+
// else changes `rdx` (which is the second argument to a function call), basically x, besides the
3717+
// very `xor edx, edx` instruction before the call. Thus, we patch that out, and we also do
3718+
// `mov edx, whatever` here; afterwards, we do NOTHING else, but just return and hope that
3719+
// edx will stick
3720+
//
3721+
// * Needless to say this is **HIGHLY** amd64
3722+
char pattern[2] = { 0x33, 0xD2 };
3723+
DWORD dwOldProtect;
3724+
char* p_mov_edx_val = mov_edx_val;
3725+
if (!ep_pf)
3726+
{
3727+
ep_pf = memmem(_ReturnAddress(), 200, pattern, 2);
3728+
if (ep_pf)
3729+
{
3730+
// Cancel out `xor edx, edx`
3731+
VirtualProtect(ep_pf, 2, PAGE_EXECUTE_READWRITE, &dwOldProtect);
3732+
memset(ep_pf, 0x90, 2);
3733+
VirtualProtect(ep_pf, 2, dwOldProtect, &dwOldProtect);
3734+
}
3735+
VirtualProtect(p_mov_edx_val, 6, PAGE_EXECUTE_READWRITE, &dwOldProtect);
3736+
}
3737+
if (ep_pf)
3738+
{
3739+
// Craft a "function" which does `mov edx, whatever; ret` and call it
3740+
DWORD* pVal = mov_edx_val + 1;
3741+
*pVal = dwIMEStyle;
3742+
void(*pf_mov_edx_val)() = p_mov_edx_val;
3743+
pf_mov_edx_val();
3744+
}
3745+
}
3746+
return hr;
3747+
}
3748+
return CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv);
3749+
}
3750+
#pragma endregion
36433751

36443752

36453753
DWORD InjectBasicFunctions(BOOL bIsExplorer, BOOL bInstall)
@@ -4161,6 +4269,10 @@ __declspec(dllexport) DWORD WINAPI main(
41614269
VnPatchIAT(hExplorer, "user32.dll", "SetWindowCompositionAttribute", explorer_SetWindowCompositionAttribute);
41624270
}
41634271
//VnPatchDelayIAT(hExplorer, "ext-ms-win-rtcore-ntuser-window-ext-l1-1-0.dll", "CreateWindowExW", explorer_CreateWindowExW);
4272+
if (dwIMEStyle)
4273+
{
4274+
VnPatchIAT(hExplorer, "api-ms-win-core-com-l1-1-0.dll", "CoCreateInstance", explorer_CoCreateInstanceHook);
4275+
}
41644276

41654277

41664278
#ifdef USE_PRIVATE_INTERFACES

ExplorerPatcher/settings.reg

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,15 @@
7575
;x 1 Windows 7
7676
"UseWin32TrayClockExperience"=dword:00000000
7777
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\ExplorerPatcher]
78+
;c 6 Language switcher flyout style *
79+
;x 0 Windows 11 (default)
80+
;x 1 Windows 10
81+
;x 2 "LOGONUI"
82+
;x 3 "UAC"
83+
;x 4 "SETTINGSPANE"
84+
;x 5 "OOBE"
85+
"IMEStyle"=dword:00000000
86+
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\ExplorerPatcher]
7887
;a Choosing 'Open Network && Internet settings' when right clicking the
7988
;c 3 network icon should open:
8089
;x 0 Network section in the Settings app (default)

0 commit comments

Comments
 (0)