Open15

Windows TerminalでのIMEエラー

KantaKanta

環境

  • Windows 11 22H2
  • Windows Terminal 1.16.10262.0
  • PowerShell 7.3.2
KantaKanta

現状の対応策

  • Microsoft IMEを使用する

でもGoogle IME使いたい...

KantaKanta

pwsh起動時の構成でIMEを変更する

基本的にpwshしか使用しないため ,pwshのスクリプトでIMEを変更できれば対処はできそう.

IMEの状態を取得し,OFFならばONに変更するpwshスクリプトを以下に示す.

ime_toggle.ps1
set-variable -name WM_IME_CONTROL -value 0x0283 -option constant

set-variable -name IMC_GETOPENSTATUS   -value 0x05 -option constant
set-variable -name IMC_SETOPENSTATUS   -value 0x06 -option constant

$ime_code = @"
    [DllImport("user32.dll")]
    public static extern IntPtr GetForegroundWindow();
    [DllImport("user32.dll")]
    public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
    [DllImport("imm32.dll")]
    public static extern IntPtr ImmGetDefaultIMEWnd(IntPtr hWnd);
"@

if(!('Win32.Ime' -as [type])) {
    Add-Type $ime_code -Name Ime -Namespace Win32
}

$window_handle = [Win32.Ime]::GetForegroundWindow()
echo $window_handle

$ime_handle = [Win32.Ime]::ImmGetDefaultIMEWnd($window_handle)
echo $ime_handle

$enableIME = ([Win32.Ime]::SendMessage($ime_handle, $WM_IME_CONTROL, $IMC_GETOPENSTATUS, 0) -ne 0)

if (!$enableIME) {
    echo "IME turn to ON"
    $null = [Win32.Ime]::SendMessage($ime_handle, $WM_IME_CONTROL, $IMC_SETOPENSTATUS, 1)
}

Win32APIをPowershellから呼び出せるようにし,GetForegroundWindow()でアクティブウィンドウのウィンドウハンドルを取得し,ImmGetDefaultIMEWnd()でIMEのウィンドウハンドルを取得する.
そのウィンドウハンドルに対して,IMEの状態を取得・変更する命令を送っている.

参考文献

PowerShellでコマンド実行したらIMEをオフにする
C#でIMEの変換モードを監視・変更する
WM_IME_CONTROL メッセージ

KantaKanta

同様に以下のようにIMEの変換モードの情報を取得できる.

get_conversion_mode.ps1
set-variable -name IMC_GETCONVERSIONMODE -value 0x01 -option constant
[Win32.Ime]::SendMessage($ime_handle, $WM_IME_CONTROL, $IMC_GETCONVERSIONMODE, 0);
KantaKanta

Google IMEとMicrosoft IMEでget_conversion_mode.ps1を動かしたときの各変換モードとの対応表

変換モード Google IME Microsoft IME
ひらがな 25(0x19) 9(0x09)
全角カタカナ 27(0x1B) 11(0x0B)
全角英数 24(0x18) 8(0x08)
半角カタカナ 19(0x13) 3(0x03)
半角英数 16(0x10) 0(0x00)

うーん...Google IMEとMicrosoft IMEで値が変わってもいいのか?共通じゃないと色々不具合が出てきそうではあるが...

16進表記にすると上位4bitが0b0001なのがGoogle IMEだな...

KantaKanta

imm.hを覗いてみるとと以下のように定義されていた.

imm.h
#define IME_CMODE_ALPHANUMERIC          0x0000
#define IME_CMODE_NATIVE                0x0001
#define IME_CMODE_CHINESE               IME_CMODE_NATIVE
#define IME_CMODE_HANGEUL               IME_CMODE_NATIVE
#define IME_CMODE_JAPANESE              IME_CMODE_NATIVE
#define IME_CMODE_KATAKANA              0x0002  // only effect under IME_CMODE_NATIVE
#define IME_CMODE_LANGUAGE              0x0003
#define IME_CMODE_FULLSHAPE             0x0008
#define IME_CMODE_ROMAN                 0x0010
KantaKanta

Google IMEなら以下のような対応になりそう.

変換モード 2進表記 対応
ひらがな 0b0001_1001 IME_CMODE_ROMAN or IME_CMODE_FULLSHAPE or IME_CMODE_JAPANESE
全角カタカナ 0b0001_1011 IME_CMODE_ROMAN or IME_CMODE_FULLSHAPE or IME_CMODE_KATAKANA or IME_CMODE_JAPANESE
全角英数 0b0001_1000 IME_CMODE_ROMAN or IME_CMODE_FULLSHAPE
半角カタカナ 0b0001_0011 IME_CMODE_ROMAN or IME_CMODE_KATAKANA or IME_CMODE_JAPANESE
半角英数 0b0001_0000 IME_CMODE_ROMAN
KantaKanta

あれ?Microsoft IMEでかな入力でもローマ字入力でもIME_CMODE_ROMANが変化しないのはなんでだろ?

KantaKanta

変換モードの変更は以下のように記述できる.

set_conversion_mode.ps1
set-variable -name IMC_SETCONVERSIONMODE -value 0x02 -option constant
$mode = 0x19
$null = [Win32.Ime]::SendMessage($ime_handle, $WM_IME_CONTROL, $IMC_SETCONVERSIONMODE, $mode);

変換先はひらがな(0x19)に設定している.

KantaKanta

うーん...半角英数→スクリプト実行→変換モード変化なし...
ただし,内部的には変更されてるんだよな...

ime.ps1
set-variable -name WM_IME_CONTROL -value 0x0283 -option constant

set-variable -name IMC_GETCONVERSIONMODE -value 0x01 -option constant
set-variable -name IMC_SETCONVERSIONMODE -value 0x02 -option constant
set-variable -name IMC_GETOPENSTATUS   -value 0x05 -option constant
set-variable -name IMC_SETOPENSTATUS   -value 0x06 -option constant

$ime_code = @"
    [DllImport("user32.dll")]
    public static extern IntPtr GetForegroundWindow();
    [DllImport("user32.dll")]
    public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
    [DllImport("imm32.dll")]
    public static extern IntPtr ImmGetDefaultIMEWnd(IntPtr hWnd);
"@

if(!('Win32.Ime' -as [type])) {
    Add-Type $ime_code -Name Ime -Namespace Win32
}

$window_handle = [Win32.Ime]::GetForegroundWindow()
$ime_handle = [Win32.Ime]::ImmGetDefaultIMEWnd($window_handle)

$mode = [Win32.Ime]::SendMessage($ime_handle, $WM_IME_CONTROL, $IMC_GETCONVERSIONMODE, 0);
Write-Output "変更前:$mode"

$null = [Win32.Ime]::SendMessage($ime_handle, $WM_IME_CONTROL, $IMC_SETCONVERSIONMODE, $Args[0]);
$mode2 = [Win32.Ime]::SendMessage($ime_handle, $WM_IME_CONTROL, $IMC_GETCONVERSIONMODE, 0);
Write-Output "変更後:$mode2"
KantaKanta

MicrosoftIMEに変えて実行したらうまく行った.
ひらがな→スクリプト実行→半角カタカナ
半角カタカナ→スクリプト実行→ひらがな

KantaKanta

GoogleIMEのオープンソース版であるMozcでも試してみる.

https://github.com/google/mozc

書いてある手順に従って進める.

Build

> git clone https://github.com/google/mozc.git -b master --single-branch --recursive
> cd mozc/src/third_party
> git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
> python3 -m pip install six

x64_x86 Cross Tools Command Prompt for VS 2019を立ち上げ,以降はその中で作業する.

> cd **/mozc/src
> python3 build_mozc.py gyp --noqt --msvs_version=2019
> python3 build_mozc.py build -c Release package

いくつかエラーが出るので場当たり的に対処(詳細は後々追記します).

> python3 build_mozc.py clean
> python3 build_mozc.py gyp --noqt --msvs_version=2019
> python3 build_mozc.py build -c Release package

無事ビルドできた.

Install

生成された以下のファイルをC:\Program Files (x86)\Mozcに入れる.

  • mozc\src\out_win\Release\mozc_broker32.exe
  • mozc\src\out_win\Release_x64\mozc_broker64.exe
  • mozc\src\out_win\Release\mozc_cache_service.exe
  • mozc\src\out_win\Release\mozc_renderer.exe
  • mozc\src\out_win\Release\mozc_server.exe
  • mozc\src\out_win\Release\mozc_tool.exe
  • mozc\src\out_win\Release\mozc_ja_tip32.dll
  • mozc\src\out_win\Release_x64\mozc_ja_tip64.dll

その後,管理者権限でターミナルを開き,以下の内容を実行する.

$ regsvr32 "C:\Program Files (x86)\Mozc\mozc_ja_tip32.dll"
$ regsvr32 "C:\Program Files (x86)\Mozc\mozc_ja_tip64.dll"

何事も無ければ無事にMozcがIMEの欄に追加されているはず

KantaKanta

MozcでもIMC_SETCONVERSIONMODEが効かない...