読者です 読者をやめる 読者になる 読者になる

IME変換中の取得がうまくいかない

EbIRCで、変換操作中は上下キーとかのイベントが発生しないようにするため、こんなクラス書いた。

サブクラス化して、接続しなかったらちゃんと動いた。しかしネットワークに接続後、縦横入れ替え時に画面のレイアウトが正しく行われなくなってしまった。なんか、テキストボックスのあるところだけ透き通っちゃったりもしてた。

メッセージが詰まったんだろうか。

using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace EbiSoft.EbIRC
{
    class ImeInputFilter : IDisposable
    {
        #region P/Invoke 宣言

        [DllImport("coredll.dll")]
        private extern static IntPtr SetWindowLong(IntPtr hwnd, int nIndex, IntPtr dwNewLong);
        private const int GWL_WNDPROC = -4;

        [DllImport("coredll.dll")]
        private extern static int CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hwnd, uint msg, uint wParam, int lParam);

        // IME変換のウィンドウメッセージ
        private const uint WM_IME_STARTCOMPOSITION = 0x10D; // IME変換開始
        private const uint WM_IME_ENDCOMPOSITION = 0x10E;   // IME変換終了

        #endregion

        /// <summary>
        /// サブクラス化するウィンドウプロシージャのデリゲート
        /// </summary>
        public delegate int WndProcDelegate(IntPtr hwnd, uint msg, uint wParam, int lParam);

        private bool disposed = false;    // Dispose が呼ばれたか
        private IntPtr oldWndProc;        // 前のハンドル
        private IntPtr handle;            // 処理中のウィンドウハンドル
        
        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="targetTextBox">処理対象のテキストボックス</param>
        public ImeInputFilter(TextBox targetTextBox)
        {
            handle = targetTextBox.Handle;

            // サブクラス化する
            oldWndProc = SetWindowLong(handle, GWL_WNDPROC, Marshal.GetFunctionPointerForDelegate(new WndProcDelegate(WndProc)));
        }

        /// <summary>
        /// 破棄
        /// </summary>
        public void Dispose()
        {
            if (!disposed)
            {
                // サブクラス化解除する
                SetWindowLong(handle, GWL_WNDPROC, oldWndProc);
                disposed = true;
            }
        }

        /// <summary>
        /// ウィンドウプロシージャ
        /// </summary>
        private int WndProc(IntPtr hwnd, uint msg, uint wParam, int lParam)
        {
            switch (msg)
            {
                case WM_IME_STARTCOMPOSITION:  // IME 変換開始
                    m_compositioning = true;
                    return 1;

                case WM_IME_ENDCOMPOSITION:    // IME 変換終了
                    m_compositioning = false;
                    return 1;

                default:
                    // デフォルトのプロシージャへ
                    return CallWindowProc(oldWndProc, hwnd, msg, wParam, lParam);
            }
        }

        #region プロパティ

        /// <summary>
        /// 処理対象になっているテキストボックス
        /// </summary>
        public TextBox TextBox
        {
            get { return m_textBox; }
        }
        private TextBox m_textBox = null;

        /// <summary>
        /// 変換中かどうか
        /// </summary>
        public bool Conpositioning
        {
            get { return m_compositioning = false; }
        }
        private bool m_compositioning = false;

        #endregion
    }
}

普通なら WndProc メソッドのオーバーライドでいけるけど、Compact Framework にはそれがないので SetWindowLong せざるをえない。何でVB6時代に逆戻りしちゃったんだか。