2014年8月2日土曜日

縦書きテキストボックスコントロールの作成(その6)



方向キーでフォーカスが移動するのは、キーが特殊キー扱いになっているため、これを是正してやらなければならないだろう。

また、ウインドウのWndProcには特殊キーのメッセージが送信されていないため、処理ができません。
しかし、フォーカスを移動させているため、フォーカスを失った後のメッセージは送信されます。

フォーカス移動処理はどこでやられているか? 
おそらく、親フォームであろうと予測を立てます。となると、親フォームのイベントを見てやれば、どう処理されているのか見えてくるのでは?
とおもって、ユーザーコントロールを格納しているコントロールのイベントを見てみることにします。

なお、「SetParent」でオーナーを変更しているので、この場合は変更後のコントロールか、変更後のコントロールが格納されている親ウインドウなのか? という疑問もあるので両方見る必要がありそうです。
また、どのタイミングなのか? というのも含めて確認は必要でしょう。
まずは、ユーザーコントロールを張り付けている大元の親フォームに下記のコードを記載して確認。
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
    Debug.Print(m.ToString)
    MyBase.WndProc(m)
End Sub
結果は、残念ながら縦書きコントロールのイベント自体を取得していないのを確認しました。
次はこれ
Protected Overrides Function ProcessDialogKey(keyData As System.Windows.Forms.Keys) As Boolean
    Debug.Print(keyData.ToString)
    Return MyBase.ProcessDialogKey(keyData)
End Function

この通り、きちんと取得しているようです。
次はこれ
Protected Overrides Function ProcessKeyMessage(ByRef m As System.Windows.Forms.Message) As Boolean
    Debug.Print(m.ToString)
    Return MyBase.ProcessKeyMessage(m)
End Function
残念ながら、何も吐き出していない。
次はこれ
Public Overrides Function PreProcessMessage(ByRef msg As System.Windows.Forms.Message) As Boolean
    Debug.Print(msg.ToString)
    Return MyBase.PreProcessMessage(msg)
End Function
何も取得しなーい。

親フォームにはイベントが送信されていることは確認できました。
とりあえず、取得できたプロセスでグリグリコードを書いてやればよさそうなので、以下のようなコードを記載します。
Protected Overrides Function ProcessDialogKey(keyData As System.Windows.Forms.Keys) As Boolean
    Dim n As IntPtr = Class_API.GetFocus()
    Select Case n
        Case TateTextBox_Test51.ControlHandle, TateTextBox_Test52.ControlHandle
            Select Case keyData
               Case Keys.Up, Keys.Down, Keys.Left, Keys.Right
                    Return MyBase.IsInputKey(keyData)
               Case Else
                    Return MyBase.ProcessDialogKey(keyData)
            End Select
        Case Else
            Return MyBase.ProcessDialogKey(keyData)
    End Select
    Return True
End Function

そしてテスト動作させてやると、方向キーでフォーカスが移動せず、中のカーソルが移動するだけにとどまりました。
ここまで調べるのに実に一週間とか(涙)



しかし、ユーザーコントロールを張り付けるウインドウにこのようなコードを記載するのは実用的ではありません。

ユーザーコントロールで作成した縦型指定のリッチテキストコントロールのハンドルを取得するプロパティを実装してイベントのハンドルを識別させていますが、配置するコントロールが複数になればなるほど複雑になります。
ユーザーコントロール単体で何とかやりたいわけで、さて、どうしたものか?
また、タブで縦書きコントロールから次のコントロールにフォーカスを移動させることはできますが、タブでフォーカスを受け取ることができないという問題も発生していたりします(苦笑)

いっそ、タブ文字有効固定にしてしまおうか……いや、それでは受け取れないという問題の解決にはならないし……

とりあえず、親コントロールのメッセージを処理しなければならないことがわかりましたので、まずは親コントロールのメッセージを取得する為、オーナー変更時に下記のコードに合わせて処理用の関数を宣言します。
mlpord = Class_API.SetWindowLong(_NowParent, Class_API.GWL_WNDPROC, AddressOf MainFormProc)
メッセージ処理するとき、ダイアログメッセージを用は親ウインドウ宛じゃなくしてしまえばいいと思って、ハンドルを親オーナーから縦書きコントロールのものに差し替えてみました。
''' <summary>
''' 縦書きコントロールの親オーナーメッセージ処理用
''' </summary>
''' <param name="hWnd">ウインドウハンドル</param>
''' <param name="uMsg">メッセージ</param>
''' <param name="wParam">最初のパラメータ</param>
''' <param name="lParam">二番目のパラメータ</param>
''' <returns></returns>
''' <remarks></remarks>
Public Function MainFormProc(ByVal hWnd As IntPtr, ByVal uMsg As IntPtr, wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
    Static calling As Boolean
    Dim m As Message
    m.HWnd = hWnd
    m.Msg = uMsg
    m.LParam = lParam
    m.WParam = wParam
    If calling = False Then
        calling = True
        If hWnd = _NowParent AndAlso uMsg = WM_GETDLGCODE Then
            hWnd = _Handle
        End If
        calling = False
    End If
    MainFormProc = Class_API.CallWindowProc(lpord, hWnd, uMsg, wParam, lParam)
End Function

これがビンゴ。矢印キーでフォーカスが移動することがなくなりました。
まぁ、なんというか、正しいやり方じゃない気がしますので、
hWnd = _Handle
この部分を
Dim nF As IntPtr = Class_API.GetFocus
If nF = _Handle Then hWnd = _Handle
という風に書き換えてやりました。要は、縦書コントロールがフォーカスを持っているときのみ、書き換えを実施するようにしたというわけです。

タブでフォーカスを受け取ることができない、という問題はとりあえずおいておきます。

 てか、上のコードを実装してやると、Tabで移動せず、タブ文字が入力されるようになりましたし、これをきちんと処理させてやろうとした場合、縦書きコントロールのメッセージ処理時に、タブ設定の識別を行い、タブ文字か次のコントロールにタブを移動させてやるという実装がひつようになります。 
この辺りは、Tabプロパティ関連で実装すればいいかなぁと。

 タブでフォーカスを受け取れない問題は、ユーザーコントロール内で、前の順序を持つコントロール取得できれば、あとはPreviewKeyDownイベントをAddHandler で関連付けてやり、タブキーが押されたらSetFoucs関数でフォーカスを取得してやればいけるんじゃないかなぁと。
もしくは、Tabの順序を取得したりすればいけそうですけど、その辺全部後回しに(いっそ無視するかな)。
せいぜい、フォーカスを受け取るための「SetFoucs」プロシージャくらいをコントロールに設定するくらいで次に……にしたいなぁ(苦笑)

0 件のコメント:

コメントを投稿