【お知らせ】プログラミング記事の投稿はQiitaに移行しました。

IMEの状態を検出

Silverlight 3でIMEの制御は、TextBoxでの有効・無効の設定しかできません。TextBox以外からIMEを利用する方法はありません。キーストロークから文字を取得(例: [Shift]+[1]→!)する方法もありません。

このような状況でエディタを作ろうとすると、全部自前で実装するのは論外とすれば、内部でTextBoxを利用するしか方法がありません。TextBoxでTextChangedイベントが発生したら文字を取り出してエディタに取り込むことで、キーストロークから文字を取得することができます。しかし変換中の文字もTextプロパティに反映されてTextChangedイベントを発生させるため、未確定の文字を取り出す結果になってまともに変換が出来なくなってしまいます。

そのため変換中かどうかを判定して、確定するまで取り出さないようにする必要があります。APIには判定する方法が用意されていませんが、WriteableBitmapを利用して強引に判定する方法を見付けました。
TextBoxをWriteableBitmapにRenderすると、なぜか二回目にIME変換中を示す下線が取り込まれます。TextBox本体の方では下線が上の行の中央にずれてしまいます。

int w = (int)Math.Ceiling(textBox1.ActualWidth);
int h = (int)Math.Ceiling(textBox1.ActualHeight);
var wb1 = new WriteableBitmap(w, h);
var wb2 = new WriteableBitmap(w, h);
wb1.Render(textBox1, null);
wb2.Render(textBox1, null);
wb1.Invalidate();
wb2.Invalidate();

このようにして取り込んだ2つのWriteableBitmapのピクセルを比較することで、変換中かどうかを判定することができます。

ちなみに最後の部分を以下のようにすると、なぜか両方に下線が現れます。

wb1.Render(textBox1, null);
wb1.Invalidate();
wb2.Render(textBox1, null);
wb2.Invalidate();

サンプル

違いがあった部分(IME変換部分の下線)を赤く強調する処理を施したサンプルを作成しました。 ⇒ 動作確認とソース

エコーは変換中には同期しないため、確定した文字だけを反映します。なぜか環境によっては2番目のボックスがずれますが原因不明です。

たまに下線を取りこぼすことがあるため、サンプルでは非同期で三重にチェックしています。

if (CheckTextBox()) return;
Dispatcher.BeginInvoke(() =>
{
    if (CheckTextBox()) return;
    Dispatcher.BeginInvoke(() =>
    {
        if (CheckTextBox()) return;
        textBlock1.Text = textBox1.Text;
    });
});

挙動に不明な点が多いことや、下線がずれたりすることから考えて、このような利用方法はMicrosoftの想定外だと思われます。バグを利用しているとも言えます。そのためいつ挙動が変わるかも分からないため利用はお勧めしません。自己責任でお願いします。