2014年3月12日水曜日

WinFormsのTextBox ControlでのIME制御

WinFormsのTextBox Controlの話題です。とても基本的なControlですが落とし穴がありました。IMEで漢字変換中にフォーカスを失うと未確定文字はそのままIMEが持って行ってしまいます。 WinFormsがこのような挙動をすることを知らず何も制御していなかったために、自作のアプリケーションがクソ呼ばわりされる事態に陥ってしまいました。 とても悲しかったのでTextBoxを派生して挙動を改良してみました。 IMEが開いているかどうかはImeContext.IsOpen()で調べることができますが、そのあと同じハンドルを使用して処理することになるため、IsOpenは使いませんでした。

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace Sayuri.Windows.Forms {
class TextBox2 : TextBox {
[DllImport("Imm32.dll")]
static extern IntPtr ImmGetContext(IntPtr hWnd);
[DllImport("Imm32.dll")]
static extern bool ImmGetOpenStatus(IntPtr hIMC);
[DllImport("Imm32.dll")]
static extern bool ImmNotifyIME(IntPtr hIMC, int dwAction, int dwIndex, int dwValue);
[DllImport("Imm32.dll")]
static extern bool ImmReleaseContext(IntPtr hWnd, IntPtr hIMC);
const int NI_SELECTCANDIDATESTR = 0x0015;
const int CPS_COMPLETE = 0x0001;
protected override void OnLostFocus(EventArgs e) {
var context = ImmGetContext(Handle);
if (context != IntPtr.Zero) {
if (ImmGetOpenStatus(context))
ImmNotifyIME(context, NI_SELECTCANDIDATESTR, CPS_COMPLETE, 0);
ImmReleaseContext(Handle, context);
}
base.OnLostFocus(e);
}
}
}
view raw TextBox2.cs hosted with ❤ by GitHub
namespace Sayuri.Windows.Forms
open System.Runtime.InteropServices
open System.Windows.Forms
type TextBox2 () =
inherit TextBox ()
[<DllImport "Imm32.dll">]
static extern nativeint ImmGetContext(nativeint hWnd)
[<DllImport "Imm32.dll">]
static extern bool ImmGetOpenStatus(nativeint hIMC)
[<DllImport "Imm32.dll">]
static extern bool ImmNotifyIME(nativeint hIMC, uint32 dwAction, uint32 dwIndex, uint32 dwValue)
[<DllImport "Imm32.dll">]
static extern bool ImmReleaseContext(nativeint hWnd, nativeint hIMC)
[<Literal>]
static let NI_SELECTCANDIDATESTR = 0x0015u
[<Literal>]
static let CPS_COMPLETE = 0x0001u
override this.OnLostFocus e =
let context = ImmGetContext this.Handle
if context <> 0n then
if ImmGetOpenStatus context then
ImmNotifyIME(context, NI_SELECTCANDIDATESTR, CPS_COMPLETE, 0u) |> ignore
ImmReleaseContext(this.Handle, context) |> ignore
base.OnLostFocus e
view raw TextBox2.fs hosted with ❤ by GitHub

0 件のコメント: