Skip to content

Commit

Permalink
feat(tsf): get IME keyboard identifier by searching registry (#272)
Browse files Browse the repository at this point in the history
This commit makes TSF search for Weasel IME from registry, within the
user IME device ID range from 0xE020 to 0xE0FF. The search finishes on
first match. By doing so TSF can be registered through regsvr32 again.
  • Loading branch information
Prcuvu authored and nameoverflow committed Sep 17, 2018
1 parent 343f27b commit b60b5b1
Show file tree
Hide file tree
Showing 13 changed files with 135 additions and 116 deletions.
10 changes: 0 additions & 10 deletions WeaselSetup/TSFRegister.h

This file was deleted.

2 changes: 0 additions & 2 deletions WeaselSetup/WeaselSetup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
#include "stdafx.h"
#include "WeaselSetup.h"
#include "InstallOptionsDialog.h"
#include <VersionHelpers.hpp>

CAppModule _Module;

Expand All @@ -15,7 +14,6 @@ int APIENTRY _tWinMain(HINSTANCE hInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
InitVersion();
UNREFERENCED_PARAMETER(hPrevInstance);

HRESULT hRes = ::CoInitialize(NULL);
Expand Down
2 changes: 0 additions & 2 deletions WeaselSetup/WeaselSetup.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@
<ClInclude Include="Resource.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
<ClInclude Include="TSFRegister.h" />
<ClInclude Include="WeaselSetup.h" />
</ItemGroup>
<ItemGroup>
Expand All @@ -107,7 +106,6 @@
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="TSFRegister.cpp" />
<ClCompile Include="WeaselSetup.cpp" />
</ItemGroup>
<ItemGroup>
Expand Down
6 changes: 0 additions & 6 deletions WeaselSetup/WeaselSetup.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,6 @@
<ClInclude Include="InstallOptionsDialog.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="TSFRegister.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
Expand All @@ -56,9 +53,6 @@
<ClCompile Include="InstallOptionsDialog.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="TSFRegister.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="WeaselSetup.rc">
Expand Down
65 changes: 40 additions & 25 deletions WeaselSetup/imesetup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,18 @@
#include <vector>
#include <StringAlgorithm.hpp>
#include <WeaselCommon.h>

#include "TSFRegister.h"
#include <msctf.h>
#include <strsafe.h>


// {A3F4CDED-B1E9-41EE-9CA6-7B4D0DE6CB0A}
const GUID c_clsidTextService =
static const GUID c_clsidTextService =
{ 0xa3f4cded, 0xb1e9, 0x41ee, { 0x9c, 0xa6, 0x7b, 0x4d, 0xd, 0xe6, 0xcb, 0xa } };

// {3D02CAB6-2B8E-4781-BA20-1C9267529467}
const GUID c_guidProfile =
static const GUID c_guidProfile =
{ 0x3d02cab6, 0x2b8e, 0x4781, { 0xba, 0x20, 0x1c, 0x92, 0x67, 0x52, 0x94, 0x67 } };

HKL ImeHKL = 0;

BOOL copy_file(const std::wstring& src, const std::wstring& dest)
{
Expand Down Expand Up @@ -109,12 +108,12 @@ int install_ime_file(std::wstring& srcPath, const std::wstring& ext, bool hant,
if (!silent) MessageBoxW(NULL, destPath.c_str(), L"安裝失敗", MB_ICONERROR | MB_OK);
return 1;
}
retval += func(destPath, true, true, hant, silent);
if (fnWow64RevertWow64FsRedirection == NULL || fnWow64RevertWow64FsRedirection(OldValue) == FALSE)
{
if (!silent) MessageBoxW(NULL, L"無法恢復文件系統重定向", L"安裝失敗", MB_ICONERROR | MB_OK);
return 1;
}
retval += func(destPath, true, true, hant, silent);
}
return retval;
}
Expand Down Expand Up @@ -179,9 +178,9 @@ int register_ime(const std::wstring& ime_path, bool register_ime, bool is_wow64,
LSTATUS ret = RegOpenKey(HKEY_LOCAL_MACHINE, KEYBOARD_LAYOUTS_KEY, &hKey);
if (ret == ERROR_SUCCESS)
{
for (DWORD k = 0xE0200000 + (hant ? 0x0404 : 0x0804); true; k += 0x10000)
for (DWORD k = 0xE0200000 + (hant ? 0x0404 : 0x0804); k <= 0xE0FF0804; k += 0x10000)
{
wsprintf(hkl_str, L"%08X", k);
StringCchPrintfW(hkl_str, _countof(hkl_str), L"%08X", k);
HKEY hSubKey;
ret = RegOpenKey(hKey, hkl_str, &hSubKey);
if (ret == ERROR_SUCCESS)
Expand Down Expand Up @@ -248,11 +247,10 @@ int register_ime(const std::wstring& ime_path, bool register_ime, bool is_wow64,
{
DWORD dwErr = GetLastError();
WCHAR msg[100];
wsprintf(msg, L"註冊輸入法錯誤 ImmInstallIME: HKL=%x Err=%x", hKL, dwErr);
StringCchPrintfW(msg, _countof(msg), L"註冊輸入法錯誤 ImmInstallIME: HKL=%x Err=%x", hKL, dwErr);
if (!silent) MessageBox(NULL, msg, L"安裝失敗", MB_ICONERROR | MB_OK);
return 1;
}
ImeHKL = hKL;
return 0;
}

Expand Down Expand Up @@ -366,28 +364,45 @@ void enable_profile(BOOL fEnable, bool hant) {
pProfiles->Release();
}
}
void unregister_text_service()
{
UnregisterProfiles();
UnregisterCategories();
UnregisterServer();
}

// 注册TSF输入法
int register_text_service(const std::wstring& tsf_path, bool register_ime, bool is_wow64, bool hant, bool silent)
{
using RegisterServerFunction = HRESULT (STDAPICALLTYPE *)();

if (!register_ime)
enable_profile(FALSE, hant);

if (register_ime) {
if (!RegisterServer(tsf_path, is_wow64) || !RegisterProfiles(tsf_path, ImeHKL) || !RegisterCategories())
{
unregister_text_service();
MessageBox(NULL, L"註冊輸入法錯誤", L"安装/卸載失败", MB_ICONERROR | MB_OK);
return 1;
}
std::wstring params = L" \"" + tsf_path + L"\"";
if (!register_ime)
{
params = L" /u " + params; // unregister
}
else {
unregister_text_service();
//if (silent) // always silent
{
params = L" /s " + params;
}
SHELLEXECUTEINFOW shExInfo = { 0 };
shExInfo.cbSize = sizeof(shExInfo);
shExInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
shExInfo.hwnd = 0;
shExInfo.lpVerb = L"open"; // Operation to perform
shExInfo.lpFile = L"regsvr32.exe"; // Application to start
shExInfo.lpParameters = params.c_str(); // Additional parameters
shExInfo.lpDirectory = 0;
shExInfo.nShow = SW_SHOW;
shExInfo.hInstApp = 0;
if (ShellExecuteExW(&shExInfo))
{
WaitForSingleObject(shExInfo.hProcess, INFINITE);
CloseHandle(shExInfo.hProcess);
}
else
{
WCHAR msg[100];
StringCchPrintfW(msg, _countof(msg), L"註冊輸入法錯誤 regsvr32.exe %s", params.c_str());
if (!silent) MessageBoxW(NULL, msg, L"安装/卸載失败", MB_ICONERROR | MB_OK);
return 1;
}

if (register_ime)
Expand Down
21 changes: 0 additions & 21 deletions WeaselSetup/stdafx.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
#include <windows.h>
#include <ShellAPI.h>
#include <Imm.h>
#include <msctf.h>

#include <atlbase.h>
#include <atlwin.h>
Expand All @@ -24,26 +23,6 @@
#include <wtl/atlmisc.h>
#include <wtl/atldlgs.h>

// {A3F4CDED-B1E9-41EE-9CA6-7B4D0DE6CB0A}
extern const GUID c_clsidTextService;

// {3D02CAB6-2B8E-4781-BA20-1C9267529467}
extern const GUID c_guidProfile;

#ifndef TF_IPP_CAPS_IMMERSIVESUPPORT

#define WEASEL_USING_OLDER_TSF_SDK

/* for Windows 8 */
#define TF_TMF_IMMERSIVEMODE 0x40000000
#define TF_IPP_CAPS_IMMERSIVESUPPORT 0x00010000
#define TF_IPP_CAPS_SYSTRAYSUPPORT 0x00020000

extern const GUID GUID_TFCAT_TIPCAP_IMMERSIVESUPPORT;
extern const GUID GUID_TFCAT_TIPCAP_SYSTRAYSUPPORT;

#endif

// TODO: reference additional headers your program requires here

#include <string>
11 changes: 11 additions & 0 deletions WeaselTSF/Globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,17 @@
#include "stdafx.h"
#include <WeaselCommon.h>

#ifdef WEASEL_HANT
#define TEXTSERVICE_LANGID MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL)
#else
#define TEXTSERVICE_LANGID MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED)
#endif

#define TEXTSERVICE_DESC WEASEL_IME_NAME
#define TEXTSERVICE_DESC_A "Weasel"
#define TEXTSERVICE_MODEL "Apartment"

#define TEXTSERVICE_ICON_INDEX 0

void DllAddRef();
void DllRelease();
Expand Down
93 changes: 55 additions & 38 deletions WeaselSetup/TSFRegister.cpp → WeaselTSF/Register.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include "stdafx.h"
#include "TSFRegister.h"
#include <WeaselCommon.h>
#include "Register.h"
#include <strsafe.h>
#include <VersionHelpers.hpp>

#define CLSID_STRLEN 38 // strlen("{xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx}")
Expand All @@ -10,22 +10,43 @@ static const char c_szTipKeyPrefix[] = "Software\\Microsft\\CTF\\TIP\\";
static const char c_szInProcSvr32[] = "InprocServer32";
static const char c_szModelName[] = "ThreadingModel";

#ifdef WEASEL_USING_OLDER_TSF_SDK

/* For Windows 8 */
const GUID GUID_TFCAT_TIPCAP_IMMERSIVESUPPORT =
{ 0x13A016DF, 0x560B, 0x46CD,{ 0x94, 0x7A, 0x4C, 0x3A, 0xF1, 0xE0, 0xE3, 0x5D } };

const GUID GUID_TFCAT_TIPCAP_SYSTRAYSUPPORT =
{ 0x25504FB4, 0x7BAB, 0x4BC1,{ 0x9C, 0x69, 0xCF, 0x81, 0x89, 0x0F, 0x0E, 0xF5 } };

#endif
HKL FindIME()
{
HKL hKL = NULL;
WCHAR key[9];
HKEY hKey;
LSTATUS ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts", 0, KEY_READ, &hKey);
if (ret == ERROR_SUCCESS)
{
for (DWORD id = (0xE0200000 | TEXTSERVICE_LANGID); hKL == NULL && id <= (0xE0FF0000 | TEXTSERVICE_LANGID); id += 0x10000)
{
StringCchPrintfW(key, _countof(key), L"%08X", id);
HKEY hSubKey;
ret = RegOpenKeyExW(hKey, key, 0, KEY_READ, &hSubKey);
if (ret == ERROR_SUCCESS)
{
WCHAR data[32];
DWORD type;
DWORD size = sizeof data;
ret = RegQueryValueExW(hSubKey, L"Ime File", NULL, &type, (LPBYTE)data, &size);
if (ret == ERROR_SUCCESS && type == REG_SZ && _wcsicmp(data, L"weasel.ime") == 0)
hKL = (HKL)id;
}
RegCloseKey(hSubKey);
}
}
RegCloseKey(hKey);
return hKL;
}

BOOL RegisterProfiles(std::wstring filename, HKL hkl)
BOOL RegisterProfiles()
{
WCHAR achIconFile[MAX_PATH];
ULONG cchIconFile = GetModuleFileNameW(g_hInst, achIconFile, ARRAYSIZE(achIconFile));
HRESULT hr;

if (IsWindows8OrGreater()) {
if (IsWindows8OrGreater())
{
CComPtr<ITfInputProcessorProfileMgr> pInputProcessorProfileMgr;
hr = pInputProcessorProfileMgr.CoCreateInstance(CLSID_TF_InputProcessorProfiles, NULL, CLSCTX_ALL);
if (FAILED(hr))
Expand All @@ -37,15 +58,16 @@ BOOL RegisterProfiles(std::wstring filename, HKL hkl)
c_guidProfile,
TEXTSERVICE_DESC,
(ULONG)wcslen(TEXTSERVICE_DESC),
filename.c_str(),
filename.size(),
achIconFile,
cchIconFile,
TEXTSERVICE_ICON_INDEX,
hkl,
FindIME(),
0,
TRUE,
0);
}
else {
else
{
CComPtr<ITfInputProcessorProfiles> pInputProcessorProfiles;
hr = pInputProcessorProfiles.CoCreateInstance(CLSID_TF_InputProcessorProfiles, NULL, CLSCTX_INPROC_SERVER);
if (FAILED(hr))
Expand All @@ -61,16 +83,16 @@ BOOL RegisterProfiles(std::wstring filename, HKL hkl)
c_guidProfile,
TEXTSERVICE_DESC,
(ULONG)wcslen(TEXTSERVICE_DESC),
filename.c_str(),
filename.size(),
achIconFile,
cchIconFile,
TEXTSERVICE_ICON_INDEX);
if (FAILED(hr))
return FALSE;
if (hkl) {
hr = pInputProcessorProfiles->SubstituteKeyboardLayout(
c_clsidTextService, TEXTSERVICE_LANGID, c_guidProfile, hkl);
if (FAILED(hr)) return FALSE;
}

hr = pInputProcessorProfiles->SubstituteKeyboardLayout(
c_clsidTextService, TEXTSERVICE_LANGID, c_guidProfile, FindIME());
if (FAILED(hr))
return FALSE;
}
return TRUE;
}
Expand Down Expand Up @@ -108,7 +130,6 @@ BOOL RegisterCategories()
if (hr != S_OK)
goto Exit;

InitVersion();
if (IsWindows8OrGreater())
{
hr = pCategoryMgr->RegisterCategory(c_clsidTextService, GUID_TFCAT_TIPCAP_IMMERSIVESUPPORT, c_clsidTextService);
Expand Down Expand Up @@ -189,32 +210,28 @@ static LONG RecurseDeleteKeyA(HKEY hParentKey, LPCSTR lpszKey)
return lRes == ERROR_SUCCESS ? RegDeleteKeyA(hParentKey, lpszKey) : lRes;
}

BOOL RegisterServer(std::wstring filename, bool wow64)
BOOL RegisterServer()
{
DWORD dw;
HKEY hKey;
HKEY hSubKey;
BOOL fRet;
char achIMEKey[ARRAYSIZE(c_szInfoKeyPrefix) + CLSID_STRLEN];
DWORD flags = KEY_WRITE;
if (wow64) {
flags |= KEY_WOW64_64KEY;
}
//TCHAR achFileName[MAX_PATH];
char achFileName[MAX_PATH];

if (!CLSIDToStringA(c_clsidTextService, achIMEKey + ARRAYSIZE(c_szInfoKeyPrefix) - 1))
return FALSE;
memcpy(achIMEKey, c_szInfoKeyPrefix, sizeof(c_szInfoKeyPrefix) - 1);

if (fRet = RegCreateKeyExA(HKEY_CLASSES_ROOT, achIMEKey, 0, NULL, REG_OPTION_NON_VOLATILE, flags, NULL, &hKey, &dw) == ERROR_SUCCESS)
if (fRet = RegCreateKeyExA(HKEY_CLASSES_ROOT, achIMEKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, &dw) == ERROR_SUCCESS)
{
fRet &= RegSetValueExA(hKey, NULL, 0, REG_SZ, (BYTE *)TEXTSERVICE_DESC_A, (strlen(TEXTSERVICE_DESC_A) + 1) * sizeof(TCHAR)) == ERROR_SUCCESS;
if (fRet &= RegCreateKeyExA(hKey, c_szInProcSvr32, 0, NULL, REG_OPTION_NON_VOLATILE, flags, NULL, &hSubKey, &dw) == ERROR_SUCCESS)
fRet &= RegSetValueExA(hKey, NULL, 0, REG_SZ, (BYTE *)TEXTSERVICE_DESC_A, sizeof TEXTSERVICE_DESC_A) == ERROR_SUCCESS;
if (fRet &= RegCreateKeyExA(hKey, c_szInProcSvr32, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hSubKey, &dw) == ERROR_SUCCESS)
{
//dw = GetModuleFileName(g_hInst, achFileName, ARRAYSIZE(achFileName));
dw = GetModuleFileNameA(g_hInst, achFileName, ARRAYSIZE(achFileName));

fRet &= RegSetValueEx(hSubKey, NULL, 0, REG_SZ, (BYTE *)filename.c_str(), (filename.size() + 1) * sizeof(TCHAR)) == ERROR_SUCCESS;
fRet &= RegSetValueExA(hSubKey, c_szModelName, 0, REG_SZ, (BYTE *)TEXTSERVICE_MODEL, (strlen(TEXTSERVICE_MODEL) + 1)) == ERROR_SUCCESS;
fRet &= RegSetValueExA(hSubKey, NULL, 0, REG_SZ, (BYTE *)achFileName, (strlen(achFileName) + 1) * sizeof(char)) == ERROR_SUCCESS;
fRet &= RegSetValueExA(hSubKey, c_szModelName, 0, REG_SZ, (BYTE *)TEXTSERVICE_MODEL, sizeof TEXTSERVICE_MODEL) == ERROR_SUCCESS;
RegCloseKey(hSubKey);
}
RegCloseKey(hKey);
Expand Down
Loading

0 comments on commit b60b5b1

Please sign in to comment.