トップ回答者
アプリケーションのIME変換モードを取得、設定する方法

質問
-
VB2008、Framework3.5 SP1でWindowsフォームアプリケーションを開発していますが、現在そのアプリケーションのユーザーから
「使用中にIMEの変換モードが勝手に無変換になることがある」との報告を受けています。
ただ同様の現象と思われる情報が見つからず、ユーザー側の使用環境等を調べ開発側でも検証していますが、
なかなか現象が確認できず、原因の特定、対応に苦戦しています。
特定の非標準コントロールを使用したフォームでのみ発生するようなので、その開発元にも問い合わせていますが
いまのところそちらでも原因不明だそうで明確な対処方法は得られていません。
原因がわかればそれに越したことはないのですが、どうも無変換になった時も他のアプリケーションでは
変化はないそうなので、暫定的な対処方法としてアプリケーションのIME変換モードを制御できればと思っています。
アプリケーションのIME変換モードを取得、設定することは可能でしょうか。
宜しくお願いいたします。
回答
-
ひとまずは、APIで変換モードを制御する方法で対処したいと思いますが、根本的な解決にはならないので
引き続き原因の究明に尽力します。
情報ありましたらよろしくお願いします。ちょっと時間あったので、VB.NETで書いてみました。参考にしてください。
' 必要なインポート Imports System.Runtime.InteropServices ' 定数 Private Const IME_CMODE_ALPHANUMERIC As Integer = &H0 Private Const IME_CMODE_NATIVE As Integer = &H1 Private Const IME_CMODE_JAPANESE As Integer = IME_CMODE_NATIVE Private Const IME_CMODE_KATAKANA As Integer = &H2 Private Const IME_CMODE_LANGUAGE As Integer = &H3 Private Const IME_CMODE_FULLSHAPE As Integer = &H8 Private Const IME_CMODE_ROMAN As Integer = &H10 Private Const IME_SMODE_NONE As Integer = &H0 Private Const IME_SMODE_PLAURALCLAUSE As Integer = &H1 Private Const IME_SMODE_SINGLECONVERT As Integer = &H2 Private Const IME_SMODE_AUTOMATIC As Integer = &H4 Private Const IME_SMODE_PHRASEPREDICT As Integer = &H8 ' Declareステートメント Private Declare Function ImmGetContext Lib "imm32.dll" _ (ByVal Handle As IntPtr) _ As IntPtr Private Declare Function ImmSetOpenStatus Lib "imm32.dll" _ (ByVal himc As IntPtr, <MarshalAs(UnmanagedType.Bool)> ByVal fOpen As Boolean) _ As <MarshalAs(UnmanagedType.Bool)> Boolean Private Declare Function ImmGetConversionStatus Lib "imm32.dll" _ (ByVal himc As IntPtr, ByRef lpdw As Integer, ByRef lpdw2 As Integer) _ As <MarshalAs(UnmanagedType.Bool)> Boolean Private Declare Function ImmSetConversionStatus Lib "imm32.dll" _ (ByVal himc As IntPtr, ByVal dw1 As Integer, ByVal dw2 As Integer) _ As <MarshalAs(UnmanagedType.Bool)> Boolean Private Declare Function ImmReleaseContext Lib "imm32.dll" _ (ByVal hWnd As IntPtr, ByVal hIMC As IntPtr) _ As <MarshalAs(UnmanagedType.Bool)> Boolean ' IME切替メソッド Private Sub ChangeImeMode(ByVal handle As IntPtr, ByVal imeMode As ImeMode) Dim lngInputContextHandle As IntPtr Dim lngStatusIMEConversion As Integer Dim lngWin32apiResultCode As Boolean lngInputContextHandle = ImmGetContext(handle) If lngInputContextHandle <> New IntPtr(0) Then lngWin32apiResultCode = ImmSetOpenStatus(lngInputContextHandle, 1) Select Case imeMode Case imeMode.AlphaFull lngStatusIMEConversion = IME_CMODE_FULLSHAPE Case imeMode.Hiragana lngStatusIMEConversion = IME_CMODE_NATIVE Or IME_CMODE_FULLSHAPE Case imeMode.Katakana lngStatusIMEConversion = IME_CMODE_NATIVE Or IME_CMODE_FULLSHAPE Or IME_CMODE_KATAKANA Case imeMode.KatakanaHalf lngStatusIMEConversion = IME_CMODE_NATIVE Or IME_CMODE_KATAKANA Case Else lngWin32apiResultCode = ImmSetOpenStatus(lngInputContextHandle, 0) lngWin32apiResultCode = ImmReleaseContext(handle, lngInputContextHandle) Exit Sub End Select lngWin32apiResultCode = ImmSetConversionStatus(lngInputContextHandle, lngStatusIMEConversion, IME_SMODE_NONE) lngWin32apiResultCode = ImmReleaseContext(handle, lngInputContextHandle) End If End Sub ' 使用例 ChangeImeMode(Me.Handle, ImeMode.NoControl) ChangeImeMode(Me.Handle, ImeMode.Hiragana)
- 回答としてマーク MMTRS 2010年8月9日 13:24
すべての返信
-
APIを利用して設定可能です。
以下、以前C#のサンプルですが、参考にしてみてください。
using System.Runtime.InteropServices; [DllImport("Imm32.dll")] public static extern IntPtr ImmGetContext(IntPtr hWnd); [DllImport("Imm32.dll")] private static extern bool ImmReleaseContext(IntPtr hWnd, IntPtr hIMC); [DllImport("Imm32.dll")] private static extern bool ImmGetConversionStatus(IntPtr hIMC, ref int fdwConversion, ref int fdwSentence); [DllImport("Imm32.dll")] private static extern bool ImmGetOpenStatus(IntPtr hIMC); [DllImport("Imm32.dll")] private static extern bool ImmSetOpenStatus(IntPtr hIMC, long fOpen); [DllImport("Imm32.dll")] private static extern bool ImmSetConversionStatus(IntPtr hIMC, int fdwConversion, int fdwSentence); // 入力モードを示す定数 /// <summary>英数字入力モード</summary> private const int IME_CMODE_ALPHANUMERIC = 0x0; /// <summary>言語依存入力モード</summary> private const int IME_CMODE_NATIVE = 0x1; /// <summary>日本語入力モード</summary> private const int IME_CMODE_JAPANESE = IME_CMODE_NATIVE; /// <summary>カタカナ入力モード</summary> private const int IME_CMODE_KATAKANA = 0x2; /// <summary>言語入力モード</summary> private const int IME_CMODE_LANGUAGE = 0x3; /// <summary>全角入力モード</summary> private const int IME_CMODE_FULLSHAPE = 0x8; /// <summary>ローマ字入力モード</summary> private const int IME_CMODE_ROMAN = 0x10; // 変換モードを示す定数の宣言 /// <summary>無変換モード</summary> private const int IME_SMODE_NONE = 0x0; /// <summary>複数文字変換モード</summary> private const int IME_SMODE_PLAURALCLAUSE = 0x1; /// <summary>単一文字変換モード</summary> private const int IME_SMODE_SINGLECONVERT = 0x2; /// <summary>自動変換モード</summary> private const int IME_SMODE_AUTOMATIC = 0x4; /// <summary>予測変換モード</summary> private const int IME_SMODE_PHRASEPREDICT = 0x8; /// <summary> /// IMEモードを切り替える /// </summary> /// <param name="handle">ウィンドウのハンドル</param> /// <param name="imeMode">IMEモード</param> private static void ChangeImeMode(IntPtr handle, ImeMode imeMode) { IntPtr lngInputContextHandle; int lngStatusIMEConversion = 0; bool lngWin32apiResultCode; // ウィンドウに関連付けされた入力コンテキストを取得 lngInputContextHandle = ImmGetContext(handle); if (lngInputContextHandle != new IntPtr(0)) { // IMEをオープン lngWin32apiResultCode = ImmSetOpenStatus(lngInputContextHandle, 1); // 初期入力モードを指定 switch (imeMode) { case ImeMode.AlphaFull: // 全角英数字 lngStatusIMEConversion = IME_CMODE_FULLSHAPE; break; case ImeMode.Hiragana: // 全角ひらがな lngStatusIMEConversion = IME_CMODE_NATIVE | IME_CMODE_FULLSHAPE; break; case ImeMode.Katakana: // 全角カナ lngStatusIMEConversion = IME_CMODE_NATIVE | IME_CMODE_FULLSHAPE | IME_CMODE_KATAKANA; break; case ImeMode.KatakanaHalf: // 半角カナ lngStatusIMEConversion = IME_CMODE_NATIVE | IME_CMODE_KATAKANA; break; default: // 半角英数字、その他 lngWin32apiResultCode = ImmSetOpenStatus(lngInputContextHandle, 0); lngWin32apiResultCode = ImmReleaseContext(handle, lngInputContextHandle); return; } // IMEの初期方式を設定 lngWin32apiResultCode = ImmSetConversionStatus(lngInputContextHandle, lngStatusIMEConversion, IME_SMODE_NONE); // 入力コンテキストを開放 lngWin32apiResultCode = ImmReleaseContext(handle, lngInputContextHandle); } } // ひらがなにしてみる private void textBox2_Enter(object sender, EventArgs e) { ChangeImeMode(this.Handle, ImeMode.Hiragana); } // IMEをOFFにする private void textBox3_Enter(object sender, EventArgs e) { ChangeImeMode(this.Handle, ImeMode.NoControl); }
- 編集済み honefai 2010年8月2日 9:10 一部修正
-
> 特定の非標準コントロールを使用したフォームでのみ発生するようなので、その開発元にも問い合わせていますが
> いまのところそちらでも原因不明だそうで明確な対処方法は得られていません。.NET 標準ではなく、サードパーティ製のコントロールが原因となるとかなり厳しいですね。
「非標準コントロール」がなんなのか判れば、より有益な情報が集まるかもしれません。
もしかしてG社のコントロールでしょうか?
> 原因がわかればそれに越したことはないのですが、どうも無変換になった時も他のアプリケーションでは変化はないそうなので、暫定的な対処方法としてアプリケーションのIME変換モードを制御できればと思っています。「無変換になった時も他のアプリケーションでは変化はない」 というのが意味不明ですが・・・
ひらぽん http://d.hatena.ne.jp/hilapon/ -
>honefaiさん
親切にサンプルコードまでありがとうございます。早速試してみます。
>ひらぽんさん
>もしかしてG社のコントロールでしょうか?
おそらくそのG社だと思います。そのコントロールが原因かどうか、まだはっきりしていないのですが、
製品名を記述しても良いものなのでしょうか・・・?
>「無変換になった時も他のアプリケーションでは変化はない」 というのが意味不明ですが・・・
わかりにくいですね・・・すみません。
問題のアプリが「無変換」になっていてもExcel等では通常通り「一般」のまま、ということです。
今まで変換モードに関しては特に意識したことはなかったのですが、今回の件でいろいろ調べてみたところ
変換モードはアプリケーションごと(あるいは各入力項目ごと)に持っているようなので、当然かも知れませんが。
(間違っていたら教えてください。)
-
そのコントロールが原因かどうか、まだはっきりしていないのですが、
製品名を記述しても良いものなのでしょうか・・・?「まずい」と思っているのであれば、その頭文字を出す時点でアウトでしょう、どこの会社かほぼ特定できますから。
メーカーに対する名誉毀損などを心配しているのであれば、そもそも特定可能な情報を出すべきではありません。
もし、それらを心配しているのであれば、たとえ、誰かに某社として特定可能な情報を提示されてもノーコメントで通すべきでしょう。私が問題なさそうと思うのは、あくまで疑いであり、真実でない可能性をきちんと明示する、真実が明らかになったときは情報を追記・開示するというように公平なスタンスでの情報共有・交換です。
アウトだと思うのは、真偽不明なのに、あたかも真実のように広めること、真実のように誤解させる恐れのあるものを広めること(メーカーに対する攻撃)です。
※注意:あくまで私見なので、法的なリスクについては責任を負いかねます。
質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。 -
> 「使用中にIMEの変換モードが勝手に無変換になることがある」との報告を受けています。
使用しているOSのバージョンやSP、現象のIMEの種類やバージョンは何でしょう?
漢字変換ソフト(もしくはその漢字変換ソフトとの組み合わせ)が問題である場合もあるかと思います。> どうも無変換になった時も他のアプリケーションでは変化はないそうなので、
今までに何かのアプリケーションと漢字変換ソフトの間で同様の現象を経験したことが何度かあります。
現象が発生したアプリケーションでは何度もチャレンジしても変換できない状態になりますが、
別のアプリケーションは問題なく変換できたりします。
最終的に原因の特定には至っていませんが、漢字変換ソフトのバージョンアップ後に
発生しなくなったような印象でした。そちらの可能性もありえるかと思いますので、
新しいバージョンの漢字変換ソフトなどの場合は、不具合情報のチェックも必要かと思います。 -
>ひらぽんさん
>もしかしてG社のコントロールでしょうか?おそらくそのG社だと思います。そのコントロールが原因かどうか、まだはっきりしていないのですが、
製品名を記述しても良いものなのでしょうか・・・?う~ん、Azulean さんから指摘されてますが、私は 「問題を解決する」 という建設的スタンスである限り、公の場で製品を論じても構わないのではという考えです。
ベンダーさんの公開している情報だけでは掴めない問題が、広く認知されることによって
始めて不具合が浮き彫りにされることもあるでしょうし、またベンダーさん自身も不具合を認識してない場合もあったりするからです。
私はフォーラムで 「某製品を使っている画面だけでおかしな現象が発生する」 という問題を論じることは
ベンダーさんに対する攻撃だとは思いませんし、むしろ不具合修正のお手伝いをさせて頂いているという考えです。
ただし今回のように再現性を立証できない不具合となると、書きようによっては誤解を招く恐れも確かにあるでしょうね。ついでですが、私がG社の名前を挙げたのは、現在G社のコンポーネントを使って開発しているからであり、もしかすると何かしら原因究明のお手伝いができるかも知れないというスタンスです。またIME の問題は 某製品のFAQ で見たような覚えがありますが、こちらはうろ覚えでしかありません。
>「無変換になった時も他のアプリケーションでは変化はない」 というのが意味不明ですが・・・
わかりにくいですね・・・すみません。
問題のアプリが「無変換」になっていてもExcel等では通常通り「一般」のまま、ということです。
今まで変換モードに関しては特に意識したことはなかったのですが、今回の件でいろいろ調べてみたところ
変換モードはアプリケーションごと(あるいは各入力項目ごと)に持っているようなので、当然かも知れませんが。
(間違っていたら教えてください。)
ひらぽん http://d.hatena.ne.jp/hilapon/ -
う~ん、Azulean さんから指摘されてますが、私は 「問題を解決する」 という建設的スタンスである限り、公の場で製品を論じても構わないのではという考えです。
私の先の投稿は、私が引用した部分のような言動ではご自身が困るのではないかということです。
(念のため:指摘した対象は MMTRS さんの投稿です)
不安を感じながらも特定できるような文章を書いてしまっている、曖昧な情報を(明確に)意図せず発信してしまっているなど、本人にとってはよくなさそうなので。きちんと、問題解決を意識した情報交換をする、真実と推測、曖昧な情報は明確に区別するなど、建設的なスタンスや公平なスタンスを意識して投稿されているのであれば構わないと私は思います。
質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。 -
>Azuleanさん、ひらぽんさん
不明確ながら、メーカーに対する攻撃とも取られかねない発言をしてしまい反省です。既に、G社のコントロールを使用したフォームでのみ発生するとは書きましたが、現時点で原因が特定できていないこと、
他のフォームでは絶対に発生しないという確証がないこと、それから追加の新しい情報として、
先のユーザーから 「Excelを使用中にも発生した」 との報告があったことを踏まえて、
原因はG社のコントロールではなく他にあるのでは、という私の考えをここで明記させて頂きます。>よねKENさん
>使用しているOSのバージョンやSP、現象のIMEの種類やバージョンは何でしょう?
現象の発生している環境は、Windows XP SP2 + Microsoft IME Standard 2002 ver. 8.1 と、
Windows XP SP3 + Microsoft Natural Input 2002 ver. 8.1 です。
ただ、OS+IMEが同じ環境でも現時点で発生していないPCもあります。なお、アプリケーションのプロパティで「詳細なテキストサービスを無効にする」も試してもらいましたが
現象は回避できませんでした。
ひとまずは、APIで変換モードを制御する方法で対処したいと思いますが、根本的な解決にはならないので
引き続き原因の究明に尽力します。
情報ありましたらよろしくお願いします。 -
ひとまずは、APIで変換モードを制御する方法で対処したいと思いますが、根本的な解決にはならないので
引き続き原因の究明に尽力します。
情報ありましたらよろしくお願いします。ちょっと時間あったので、VB.NETで書いてみました。参考にしてください。
' 必要なインポート Imports System.Runtime.InteropServices ' 定数 Private Const IME_CMODE_ALPHANUMERIC As Integer = &H0 Private Const IME_CMODE_NATIVE As Integer = &H1 Private Const IME_CMODE_JAPANESE As Integer = IME_CMODE_NATIVE Private Const IME_CMODE_KATAKANA As Integer = &H2 Private Const IME_CMODE_LANGUAGE As Integer = &H3 Private Const IME_CMODE_FULLSHAPE As Integer = &H8 Private Const IME_CMODE_ROMAN As Integer = &H10 Private Const IME_SMODE_NONE As Integer = &H0 Private Const IME_SMODE_PLAURALCLAUSE As Integer = &H1 Private Const IME_SMODE_SINGLECONVERT As Integer = &H2 Private Const IME_SMODE_AUTOMATIC As Integer = &H4 Private Const IME_SMODE_PHRASEPREDICT As Integer = &H8 ' Declareステートメント Private Declare Function ImmGetContext Lib "imm32.dll" _ (ByVal Handle As IntPtr) _ As IntPtr Private Declare Function ImmSetOpenStatus Lib "imm32.dll" _ (ByVal himc As IntPtr, <MarshalAs(UnmanagedType.Bool)> ByVal fOpen As Boolean) _ As <MarshalAs(UnmanagedType.Bool)> Boolean Private Declare Function ImmGetConversionStatus Lib "imm32.dll" _ (ByVal himc As IntPtr, ByRef lpdw As Integer, ByRef lpdw2 As Integer) _ As <MarshalAs(UnmanagedType.Bool)> Boolean Private Declare Function ImmSetConversionStatus Lib "imm32.dll" _ (ByVal himc As IntPtr, ByVal dw1 As Integer, ByVal dw2 As Integer) _ As <MarshalAs(UnmanagedType.Bool)> Boolean Private Declare Function ImmReleaseContext Lib "imm32.dll" _ (ByVal hWnd As IntPtr, ByVal hIMC As IntPtr) _ As <MarshalAs(UnmanagedType.Bool)> Boolean ' IME切替メソッド Private Sub ChangeImeMode(ByVal handle As IntPtr, ByVal imeMode As ImeMode) Dim lngInputContextHandle As IntPtr Dim lngStatusIMEConversion As Integer Dim lngWin32apiResultCode As Boolean lngInputContextHandle = ImmGetContext(handle) If lngInputContextHandle <> New IntPtr(0) Then lngWin32apiResultCode = ImmSetOpenStatus(lngInputContextHandle, 1) Select Case imeMode Case imeMode.AlphaFull lngStatusIMEConversion = IME_CMODE_FULLSHAPE Case imeMode.Hiragana lngStatusIMEConversion = IME_CMODE_NATIVE Or IME_CMODE_FULLSHAPE Case imeMode.Katakana lngStatusIMEConversion = IME_CMODE_NATIVE Or IME_CMODE_FULLSHAPE Or IME_CMODE_KATAKANA Case imeMode.KatakanaHalf lngStatusIMEConversion = IME_CMODE_NATIVE Or IME_CMODE_KATAKANA Case Else lngWin32apiResultCode = ImmSetOpenStatus(lngInputContextHandle, 0) lngWin32apiResultCode = ImmReleaseContext(handle, lngInputContextHandle) Exit Sub End Select lngWin32apiResultCode = ImmSetConversionStatus(lngInputContextHandle, lngStatusIMEConversion, IME_SMODE_NONE) lngWin32apiResultCode = ImmReleaseContext(handle, lngInputContextHandle) End If End Sub ' 使用例 ChangeImeMode(Me.Handle, ImeMode.NoControl) ChangeImeMode(Me.Handle, ImeMode.Hiragana)
- 回答としてマーク MMTRS 2010年8月9日 13:24
-
>honefaiさん
ありがとうございます。とても助かります。PG始めてまだ日が浅いもので、いくつか質問させてください。
API宣言部分の "<MarshalAs(UnmanagedType.Bool)>" というのは、必ずあるべきものでしょうか。
意味としてはおおよそ理解したつもりですが、初めて見るコードでしたので。それから、ChangeImeMode内のImmSetOpenStatusメソッドについてですが、私の環境ではこれを省略しても問題なく
IMEの状態の取得・設定ができているようなのですが、どういった意味合いのものなのでしょうか。
「IMEを開く/閉じる」という概念がまだよく理解できていません。 -
> 現象の発生している環境は、Windows XP SP2 + Microsoft IME Standard 2002 ver. 8.1 と、
> Windows XP SP3 + Microsoft Natural Input 2002 ver. 8.1 です。
> ただ、OS+IMEが同じ環境でも現時点で発生していないPCもあります。どうやら他に原因がありそうですね。
何らかのソフトが競合起こしてたり、もしくは相性の問題やハードの問題(リソース不足やデバイスの問題等)等、
不具合の原因には様々な原因がありますので、OS や IME の種類だけではなく、可能な限り情報を集めた方がいいと思います。例えば問題が発生している環境で .NET Framework のサービスパックがインストールされているか、また IE のバージョン、ウイルスソフト、稼働しているサービス、ハードウェアの構成、配布されたサードパーティー製のコンポーネントが、別アプリをインストールしたことによりバージョンを置き換えられてないか等etc・・・
確かに考えればキリがないのですが、様々な環境に配布する場合、広く考慮することは非常に大事だと思います。広く原因を探っていくうちに、想定外の問題に気が付く場合もあったりします。最近、某社(G社ではない)の ActiveX を使っていて、WindowsForm のみのアプリケーションで使う場合は問題ないが、WPF と WinForm を相互運用した場合のみ、ActiveX で公開する幾つかのメソッドが失敗するという問題が起こりました。
当初「相互運用」に問題があるかとも考えたのですが、幾つかサンプルアプリケーションを作って調べても予想外に正常に動作しており、一週間近くかけ調査しても全く原因がつかめませんでした。
詳細は書けませんが、結局「相互運用」の問題でなくポート絡みの問題であることに気づきました。そこで WebBrowser の Navigate メソッドを使うのを止め、NavigateToString メソッドを使うようにしたら問題を解決したということもあります。
ひらぽん http://d.hatena.ne.jp/hilapon/ -
MarshalAsですが、VB.NETとWindowsAPIの間に型の互換性が無い為、.NETからAPIを利用する
場合には、適切なAPIの型を指定する必要があります。
以下参考に見てみてください。
http://www.atmarkit.co.jp/fdotnet/vb6tonet/vb6tonet28/vb6tonet28_03.html
ImmSetOpenStatus関数は、IMEを閉じたり開いたりします。
http://msdn.microsoft.com/ja-jp/library/cc448037.aspx
>私の環境ではこれを省略しても問題なく
とありますが、コメントアウトするのではなく、以下のようにしてみてください。
おそらくIMEは無効のままになってしまうと思います。
lngWin32apiResultCode = ImmSetOpenStatus(lngInputContextHandle, 1)
↓
lngWin32apiResultCode = ImmSetOpenStatus(lngInputContextHandle, 0)
以下のような認識でよろしいかと思います。
IMEを開く:ひらがな・カタカナなどの日本語入力可能な状態にする
IMEを閉じる:日本語入力を不可にして、キー入力を直接表示する
それとみなさん書いてあるように、ある現象にフタをする場合は、その原因を
特定した上で対処を行う方が心理的にもよろしいと思いますので、
もし原因が特定できる可能性があるならば、がんばってみてくださいね。
- 編集済み honefai 2010年8月3日 7:38 追記
-
>ひらぽんさん
>何らかのソフトが競合起こしてたり、もしくは相性の問題やハードの問題(リソース不足やデバイスの問題等)等、
>不具合の原因には様々な原因がありますので、OS や IME の種類だけではなく、可能な限り情報を集めた方がいいと思います。
そうですね。私にも以前、「思わぬところに」という経験があります。
近いうちにユーザーを訪問する機会がありますので、そのときに情報収集させて頂こうかと思います。
>honefaiさん
ありがとうございます。自分でもいろいろと試してみて、意味・使い方がわかってきました。ImmSetOpenStatusメソッドについてですが、私が今回目標としているのは
変換モードのみの制御ですので、IMEが開いているか閉じているかに関わらず
変換モードを設定する必要があり、一方入力モードについてはAPIでの制御はせずに
各コントロールのImeModeプロパティをそのまま生かしたいと思っています。
(実際には入力モードも現在も内容で再設定するという形になりますが)ですので今回の件では入力モードを保持するために、IMEを開く/閉じるという処理は
省略できればと思うのですが、問題はないでしょうか。それから今回の対処ですが、あくまで今現在当方のアプリケーションで不便をかけてしまっている
ユーザーへの対処ですので、原因の調査や検証には引き続き取り組んでいきます。
励ましの言葉、ありがとうございます。 -
>各コントロールのImeModeプロパティをそのまま生かしたいと思っています
私が提示していた内容は、コントロールにIMEの設定を変更するプロパティ(ImeMode等)が
存在しない場合に有効だったりしますので、プロパティがあるならば、私の提示したコードは
不要かもしれません。
今回の質問は「アプリケーションのIME変換モードを取得、設定することは可能でしょうか。」
ということでサンプルコードを上げましたが、できる限りマネージドコードからアンマネージ
コードを扱わない方が良いと私は考えていますので、各コントロールレベルでのIMEの設定
を行えるプロパティがあるならば、迷わずそちらを使うことをおすすめします。
なお、IMEの設定を行えるプロパティがあるコントロール、ないコントロールが混在する中で
全てのコントロールにおいてIMEを制御したい、という場合は、あえてプロパティを使わずに
統一性を考えてAPIによるIMEの制御を行うことでコードの可読性、保守性が上がると思います。
ちなみにImmSetOpenStatus関数についてですが、
>変換モードのみの制御ですので、IMEが開いているか閉じているかに関わらず
>変換モードを設定する必要があり
変換モードのみの制御とは、ひらがなやカナを切り替えるということですよね。
ひらがなモードであることは、IMEは必ず開いた状態ですので、実際は
開いていなければ開いて変換モードを設定する、という流れになります。
開いていれば、ひらがなからカナの状態にするのには、再度開く必要がないという感じです。
>入力モードを保持するために、IMEを開く/閉じるという処理は
>省略できればと思うのですが
問題ないです。そのかわり、IMEが閉じた状態からひらがなモード等を設定
したい場合は、開く必要があるかと思います。
========================================
※追記
すいません、ImeModeの設定をしてもその内容が反映されないので、
APIを使って、そのImeModeプロパティの値を利用して制御する、ということですか?
であれば、上記のコメントの一部は無視してください。(汗
- 編集済み honefai 2010年8月4日 2:27 追記
-
>変換モードのみの制御とは、ひらがなやカナを切り替えるということですよね。
使用するIMEの種類によるかと思いますが、
入力モード:IMEバーの「あ」「 A」「カ」etc. の部分
変換モード:IMEバーの「般」「無」「名」etc. の部分
と認識しています。
つまり今回私が問題としているのは、各コントロールのImeModeプロパティで制御可能な入力モードについてではなく、
基本的に制御可能なプロパティのない変換モードが、勝手に「無」に変わってしまう、ということです。ですので、IME自体が使用不可([半角/全角]キーでの切り替えができない状態)の場合を除いて、
入力モードが「あ」でも「カ」でも「 A」でも、変換モードの制御をしたいと考えています。この内容でご理解頂けますでしょうか。
-
>基本的に制御可能なプロパティのない変換モードが、勝手に「無」に変わってしまう、ということです。
>ですので、IME自体が使用不可([半角/全角]キーでの切り替えができない状態)の場合を除いて、
>入力モードが「あ」でも「カ」でも「 A」でも、変換モードの制御をしたいと考えています。
>この内容でご理解頂けますでしょうか。
理解いたしました、問題ないと思われます。
他の影響を最小限に抑えつつ発生箇所にフタをするのであれば、
該当箇所のスポット的な対応と思いますが、無にかわってしまう箇所の数が多いならば
制御の分散化を防ぐために画面全体のIME制御をAPIで一元化して保守性を高めるのも手です。
無にかわってしまう箇所のみの対応とするか、画面全体をAPIで制御するのかは、画面のボリューム感や
他画面との仕様の統一性、開発コスト及び納期がからみますのでご自身で判断されてください。
-
>他の影響を最小限に抑えつつ発生箇所にフタをするのであれば、
>該当箇所のスポット的な対応と思いますが、無にかわってしまう箇所の数が多いならば
>制御の分散化を防ぐために画面全体のIME制御をAPIで一元化して保守性を高めるのも手です。変換モードが「無」に変わるのはフォーカスが移った時なのですが、
フォーカス移動前のコントロールも移動後のコントロールも特定のものではなく、
コントロール内の子コントロール同士でのフォーカス移動でも発生します。現時点ではユーザーへの対処が第一の目的ですので、可能性のある箇所全て(=全ての入力コントロール)を対象として
先述の処理を入れたいのですが、honefaiさんの言う通り画面全体でIME制御を一元化する方が安全かつ効率的と考えています。しかし、提供して頂いたAPIでの制御を試してみたのですが、ImmGetContext(Me.Handle)("Me"はフォーム)としても
戻り値が0(ゼロ)となり、入力コンテキストを取得できません。
ImmGetContext(TextBox1.Handle) 等では問題なく取得できます。何かのプロパティ等で取得できるようになるのでしょうか。
それともフォームにはそもそも関連付けされた入力コンテキストがないのでしょうか。 -
>しかし、提供して頂いたAPIでの制御を試してみたのですが、ImmGetContext(Me.Handle)
>("Me"はフォーム)としても
>戻り値が0(ゼロ)となり、入力コンテキストを取得できません。
>ImmGetContext(TextBox1.Handle) 等では問題なく取得できます。
私の環境では問題なくHandleが取得できました。
※確認方法はTextBoxのEnterイベント内で以下を記述
ChangeImeMode(Me.Handle, ImeMode.Hiragana)
コードの全体像が分からないので何とも言えませんが、
Meを使用している箇所に問題はないですか?
Meは、必ずしもFormを指すとは限りません、デバッガ等でとめてオブジェクトの内容を確認
してみてください。
http://msdn.microsoft.com/ja-jp/library/20fy88e0(VS.80).aspx
もし上記理由が当てはまる場合で、各コントロールのハンドルを指定するのが
煩雑になるのでNGである場合は、メンバとしてハンドルを持ち、フォームロードで
そのメンバにフォームハンドルを設定し、そのメンバ値を使ってimm系を呼び出す
ことで回避できるかと思います。
' フォームクラスのメンバ Private FormHandle As IntPtr ' フォームロード Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load FormHandle = Me.Handle End Sub ' immを使う箇所 ChangeImeMode(FormHandle, ImeMode.Hiragana)
※なお、コントロールのハンドル(TextBox1.Handle)を使用しても大丈夫です。
-
>Meを使用している箇所に問題はないですか?
>Meは、必ずしもFormを指すとは限りません、デバッガ等でとめてオブジェクトの内容を確認
>してみてください。Formを継承したクラス内のTextBox.Enterイベントで使用していますので、Meがフォームであることは間違いありません。
デバッグでも確認しました。
メンバFormHandleを設けて、ImmGetContext(FormHandle)としてもダメでした。書いていませんでしたが、そのフォームがMDI子フォームであることは関係しますでしょうか。
ただ、MDI親フォームのハンドルを使用してもやはり入力コンテキストは取得できませんでした。ひとまず今は各入力コントロールのハンドルを使用して制御しています。
-
>Formを継承したクラス内のTextBox.Enterイベントで使用していますので、Meがフォームであることは間違いありません。
>デバッグでも確認しました。デバッガで確認したとき、Me.Handleの値は確認されましたか?
いまMDI子コントロールを作ってHandleを確認してみましたが、問題なく取得できます。
>ひとまず今は各入力コントロールのハンドルを使用して制御しています。' 親フォームのプロパティ IsMDIContainer = True '--------------------------------------------------------------- Public Class Form1 Private Sub Form1_Load(略...) Handles MyBase.Load Dim form2 As New Form2 form2.MdiParent = Me form2.Show() End Sub End Class '--------------------------------------------------------------- Public Class Form2 Private Sub Form2_Load(略...) Handles MyBase.Load MessageBox.Show(Me.Handle.ToString()) End Sub End Class
とりあえず対応として問題ないと思いますので、他の急ぎの対応などあれば
余裕がある時にHandleが取得できない原因を特定する方向でよいのかもしれません。
-
-
念のため。
このスレッドの C# のサンプルは間違っています。[DllImport("Imm32.dll")]
private static extern bool ImmSetOpenStatus(IntPtr hIMC, long fOpen);上記の P/Invoke ですが、第 2 引数が間違っており、正しくは bool 型です。
(後述の VB のサンプルでは正しく修正されているようですが…)もし、参照される方はお間違えのないようにお願いします。
質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。