2014年4月30日水曜日

IME と Windows8

こんにちは。yu1rowです。

Windows 8 や Windows 8.1 が登場してしばらくが経ちましたが、アプリケーションによってはIMEの制御に問題が出ることがあり、調査を行いましたのでメモを残します。

デスクトップなアプリケーションでは、テキストボックスにカーソルが移動した場合、日本語入力を自動的に切り替えたりするなんてことをする場合があります。
Windows 8 より以前では、他のウィンドウに切り替えて入力方法を切り替えても、元のウィンドウには何の影響もありませんでした。
Windows 8 以降では、インストールした直後の設定では、日本語入力モードはユーザ(セッション)毎に共通で、一つのウィンドウでの変更が他のウィンドウに影響してしまうという現象が起こる可能性があります。
※ちなみに Windows Server 2012 でも Windows 8 と同じことが起こります。

Windows 7 までの動作と同じにしたい場合、コントロールパネルから切り替えることが出来ます。
  • (jp) - [言語] - [詳細設定] - [アプリ ウィンドウごとに異なる入力方式を設定する]
  • (en) - [language] - [advanced settings] - [Let me set a different input method for each app window]

この操作をわざわざ顧客にさせるようなベンダーはあまり居ないと思いますけどね。

アプリケーションの開発者が現在の設定を確認するには SystemParametersInfo という API を使用します。
IDE 立ち上げるのも面倒だったので Excel VBA の標準モジュールで関数を書いてみました。
Option Explicit
#If VBA7 Then
Declare PtrSafe Function SystemParametersInfo Lib "user32" Alias "SystemParametersInfoA" (ByVal uAction As Long, ByVal uparam As Long, ByRef lpvParam As Any, ByVal fuWinIni As Long) As Long
#Else
Declare Function SystemParametersInfo Lib "user32" Alias "SystemParametersInfoA" (ByVal uAction As Long, ByVal uparam As Long, ByRef lpvParam As Any, ByVal fuWinIni As Long) As Long
#End If
Const SPI_GETTHREADLOCALINPUTSETTINGS As Long = &H104E

' ------------------------------------------------------------
' [Description]
'  IMEの入力モードがセッション毎/スレッド毎どちらで
'  保持されるかの設定状況を返します。
' ------------------------------------------------------------
' [Returns]
'  0 : セッション毎(Windows 8以降のみ)
'  1 : スレッド毎
' ------------------------------------------------------------
' [Author]
'  yu1row
' ------------------------------------------------------------
Public Function GetThreadLocalInputSettings() As Integer
    Dim ret As Long
    Dim data As Long
    ret = SystemParametersInfo(SPI_GETTHREADLOCALINPUTSETTINGS, 0, data, 0)
    If ret <> 0 Then
        GetThreadLocalInputSettings = IIf(data = 0, 0, 1)
    Else
        GetThreadLocalInputSettings = 1
    End If
End Function

SPI_GETTHREADLOCALINPUTSETTINGS(0x104E) は Windows 8 から追加されています。また、SPI_SETTHREADLOCALINPUTSETTINGS(0x104F) も追加されており、これでアプリケーションから設定の変更も可能です。

さて、「コントロールパネルの設定を変えずに、他のウィンドウに影響させずに入力モードを切り替えたい」というワガママソリューションは存在するのでしょうか?
未検証ですが、以下の手順でうまくいくかもしれません。保証できませんけど。

  1. Windows 8 で、かつ入力モードがアプリ毎保持ではない場合、アプリ毎保持に変更する(SPI_GETTHREADLOCALINPUTSETTINGS / SPI_SETTHREADLOCALINPUTSETTINGS)
  2. IME の制御を行う (ImmSetConversionStatus とか)
  3. 1 でアプリ毎保持に変更を行っていた場合、設定を元に戻す(SPI_SETTHREADLOCALINPUTSETTINGS)
どうなんでしょうかね。やってみた人、結果教えてくれると嬉しいですw

それでは。