フリガナを取得する

IMEの入力を読み取りフリガナを取得するテクニックです。

※VB6から追加されたAddressOfを指定しているので下記サンプルは旧VBでは動作しません。

サンプル(32bit) ダウンロード

標準モジュール側

'Ime制御
Public Declare Function ImmGetContext Lib "imm32.dll" (ByVal hWnd As Long) As Long
Public Declare Function ImmGetCompositionString Lib "imm32.dll" Alias "ImmGetCompositionStringA" (ByVal himc As Long, ByVal dw As Long, ByVal lpv As String, ByVal dw2 As Long) As Long
Public Declare Function ImmReleaseContext Lib "imm32.dll" (ByVal hWnd As Long, ByVal himc As Long) As Long

Public Const GCS_COMPREADSTR = &H1
Public Const GCS_COMPREADATTR = &H2
Public Const GCS_COMPREADCLAUSE = &H4
Public Const GCS_COMPSTR = &H8
Public Const GCS_COMPATTR = &H10
Public Const GCS_COMPCLAUSE = &H20
Public Const GCS_CURSORPOS = &H80
Public Const GCS_DELTASTART = &H100
Public Const GCS_RESULTREADSTR = &H200
Public Const GCS_RESULTREADCLAUSE = &H400
Public Const GCS_RESULTSTR = &H800
Public Const GCS_RESULTCLAUSE = &H1000

'イベント処理関連
Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long

Public Const GWL_WNDPROC = (-4)
Public Const WM_IME_COMPOSITION = &H10F

'保存用変数
Public FURIGANA_STR As String
Public Save_WindowLong As Long
Public Save_hWnd As Long

Public Function GetFurigana(ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    
    Dim himc As Long
    Dim nLEN As Long
    Dim WorkStr As String
    
    'IME文字確定後で文字が入力された場合
    If (uMsg = WM_IME_COMPOSITION) And ((lParam And GCS_RESULTREADSTR) <> 0) Then
        'フリガナを取得
        'コンテキスト取得
        himc = ImmGetContext(hWnd)
        'バッフア確保のため入力した文字数を取得
        nLEN = ImmGetCompositionString(himc, GCS_RESULTREADSTR, vbNullChar, 0)
        '入力文字数分バッファ確保
        WorkStr = Space(nLEN + 1)
        '入力文字列取得
        Call ImmGetCompositionString(himc, GCS_RESULTREADSTR, WorkStr, nLEN + 1)
        'コンテキスト開放
        Call ImmReleaseContext(hWnd, himc)
        
        FURIGANA_STR = FURIGANA_STR & RTrim(WorkStr)
    End If

    GetFurigana = CallWindowProc(Save_WindowLong, hWnd, uMsg, wParam, lParam)
    
End Function

Public Sub Furigana_Start(KANJI_Control As Control)

    'フリガナ監視スタート
    
    'GetFuriganaイベントをバインドしてます。
    Save_WindowLong = SetWindowLong(KANJI_Control.hWnd, GWL_WNDPROC, AddressOf GetFurigana)
    
    'ハンドル保存
    Save_hWnd = KANJI_Control.hWnd
    
    'ふりがな文字列初期化
    FURIGANA_STR = ""
    
End Sub

Public Sub Furigana_End()

    'フリガナ監視終了
    
    'イベントのバンドルを解除
    Call SetWindowLong(Save_hWnd, GWL_WNDPROC, Save_WindowLong)
    
End Sub

フォーム側

Private Sub Text1_GotFocus()
    
    Dim himc As Long
    Dim hWnd As Long
    
    hWnd = Text1.hWnd
    
    'IMEをOn
    himc = ImmGetContext(hWnd)
    Call ImmSetOpenStatus(himc, 1)
    Call ImmReleaseContext(hWnd, himc)
    
    '文字列を反転させる
    Text1.SelStart = 0
    Text1.SelLength = Len(Text1.Text)
    
    'フリガナ監視スタート
    Call Furigana_Start(Text1)

End Sub

Private Sub Text1_LostFocus()
    
    Dim himc As Long
    Dim nLEN As Long
    Dim hWnd As Long
    
    hWnd = Text1.hWnd
    
    'IMEをOff
    himc = ImmGetContext(hWnd)
    Call ImmSetOpenStatus(himc, 0)
    Call ImmReleaseContext(hWnd, himc)
        
    'フリガナ監視終了
    Call Furigana_End
        
    '取得したフリガナをセット
    Text2.Text = Text2.Text & FURIGANA_STR
    
End Sub

サンプル解説

以下の手順でフリガナを取得します。

  1. テキストボックスのGotFocusイベント時にFurigana_Startプロシージャを呼び出し、フリガナ取得を開始します。(同時にPublic変数FURIGANA_STRが初期化されます)
  2. テキストボックスのLostFocusイベント時にFurigana_Endプロシージャを呼び出し、フリガナ取得を終了します。
  3. Public変数FURIGANA_STRには取得したフリガナが入っています、

ます、Furigana_StartプロシージャのSetWindowLong関数を使用してIMEのイベント用にGetFurigana関数をテキストボックスのイベントにバインドしています。

引数の内容は次の通りです。
(引数の名前は、Declare Functionで指定したものです)

メンバー I/O 説明
hWnd In イベントをバンドルするコントロールのハンドル
サンプルではテキストボックスのハンドルを渡しています。
nIndex In オフセット
サンプルではGWL_WNDPROCを渡し、ウィンドプロシージャを書き換えることを指定しています。
dwNewLong In バンドルする関数のポインタ
サンプルではAddressOfを使用してGetFurigana関数のポインタを渡しています。

↑によってテキストボックスのイベント処理がGetFurigana関数に切り替わります。
(SetWindowLong関数の戻り値は元のイベントプロシージャを返します。これは後で必要となるのでPublic変数に保存して置きます)

そして、GetFurigana関数では「IME文字確定がされ and 文字が入力されている」と言うメッセージを受け取ったら、ImmGetCompositionString関数で入力文字列を取得します。

引数の内容は次の通りです。
(引数の名前は、Declare Functionで指定したものです)

メンバー I/O 説明
himc In IMEのコンテキスト
dw In 取得する情報を表すフラグ
サンプルではGCS_RESULTREADSTRをセットして入力された文字列を1バイトカタカナで返すように指定しています。
lpv Out 取得した情報のバッファ
dw2 In lpvのサイズ

ただし、文字列の取得するには2段階の手順が必要です。(入力された文字の長さが分からないのでバッファが用意できないためです)

  1. 入力文字のサイズの取得。

    引数lpvにNull、引数dw2に0をセットして、ImmGetCompositionString関数を呼び出します。
    ImmGetCompositionString関数は文字のサイズを返します。

    文字のサイズを取得したらバッファを確保します。
    末尾にNullが入るので1文字分多くバッファを確保します。

  2. 入力文字の取得。

    確保したバッファとそのサイズを引数lpv、引数dw2にセットして入力文字列を取得します。

そして、取得した入力文字列をPublic変数FURIGANA_STRに追加しています。
なぜ追加しているかというと、1つのコントロールで複数回確定が起こるためです。

最後に、テキストボックスの通常イベントをWindowsに処理させるためにCallWindowProc関数でWindowsにイベント処理を渡しています。
(コレをしないと、テキストボックスのLostFocusイベントやChangeイベントが発生しないなどの問題が発生します)

引数の内容は次の通りです。
(引数の名前は、Declare Functionで指定したものです)

メンバー I/O 説明
lpPrevWndFunc In コントロールの元のイベントプロシージャ
サンプルではSetWindowLong関数が返して保存してた古いイベントプロシージャを渡しています。
hWnd In イベントをバンドルするコントロールのハンドル
サンプルではテキストボックスのハンドルを渡しています。
Msg In メッセージ
サンプルではGetFurigana関数に入ってきたメッセージをそのまま渡しています。
wParam In パラメータ1
サンプルではGetFurigana関数に入ってきたのを、そのまま渡しています。
lParam In パラメータ2
サンプルではGetFurigana関数に入ってきたのを、そのまま渡しています。

この処理をまとめると以下のイメージになります。

SetWindowLong関数でイベントプロシージャが書き換えられると・・・

テキストボックスのイベント発生
GetFurigana関数の実行
(入力文字列の取得)
CallWindowProc関数で
元のイベントプロシージャを呼び出す
元のイベントプロシージャの実行
(テキストボックス本来の動き)

と、つまり、このフリガナ取得処理は、テキストボックスの通常のイベントプロシージャの前に割り込んで独自のイベント処理を実装して実現している訳です。

ちなみに、テキストボックスのLostFocusイベントで行っているFurigana_Endプロシージャはイベントプロシージャを念のため元に戻しています。


[ Window Close ]