PPLKB-09:【C/C++】POLでハードボタン1-4をフックする方法 - project-enigma

PPLKB-09:【C/C++】POLでハードボタン1-4をフックする方法

>> Site top >> Misc >> In my palm >> Palm開発情報 >> PPLKB-09:【C/C++】POLでハードボタン1-4をフックする方法

最終更新日付:2014/01/01 00:00:00

POLでハードボタン1-4をフックする方法

概要

CForm 派生クラスのイベントマップマクロでは、vchrHard1 などのハードボタンイベントを処理することができません。このページでは、この問題について説明し、これらのボタンイベントを処理する方法を解説します。

 

問題点

以下のコードで示される CMyForm クラスでは、EVENT_MAP マクロでハードボタン1〜4に対して OnHardButton( ) メソッドを割り当てています。

class CMyForm : public CForm {
public:
    CMyForm( );

public:
    // Form event handlers
    Boolean OnOpen(EventType* pEvent, Boolean& bHandled);
    Boolean OnClose(EventType* pEvent, Boolean& bHandled);
    Boolean OnHardButton(EventType* pEvent, Boolean& bHandled);

private:
    // Event map
    BEGIN_EVENT_MAP(CForm)
        EVENT_MAP_ENTRY(frmOpenEvent, OnOpen)
        EVENT_MAP_ENTRY(frmCloseEvent, OnClose)
        EVENT_MAP_KEY_DOWN_ENTRY(vchrHard1, 0, OnHardButton)
        EVENT_MAP_KEY_DOWN_ENTRY(vchrHard2, 0, OnHardButton)
        EVENT_MAP_KEY_DOWN_ENTRY(vchrHard3, 0, OnHardButton)
        EVENT_MAP_KEY_DOWN_ENTRY(vchrHard4, 0, OnHardButton)
    END_EVENT_MAP()

};

 

しかし、この OnHardButton( ) は決して呼び出されることがありません。なぜなら、POL のイベントハンドリングでは、ハードボタンの押下は CForm 派生クラスまで到達しないからです。ハードボタンの押下イベントは、ユーザー定義アプリケーションクラスの基底クラスである CPalmApp のレベルで処理されてしまいます。そのため、ハードボタン押下をフックしたければアプリケーションクラスで対処する必要があります。

 

CPalmApp::EventLoop( )の実装

アプリケーションクラスで対処するといっても、POL ではイベント処理のほとんどはCPalmApp クラスの内部で行われています。ユーザー定義のメソッドでオーバーライドできる仮想関数は AppHandleEvent( ) と PreSystemEventHook( ) しかありません。これらの仮想関数を呼び出している CPalmApp::EventLoop( ) の実装は以下のようになっています(元のソースから括弧のスタイルなどを整形してあります)。

void CPalmApp::EventLoop( ) {
    if( m_wCommand == sysAppLaunchCmdNormalLaunch ) {
        UInt16 error;
        EventType event;
        do {
            EvtGetEvent( &event, m_dwEventWaitDuration );
            if( !PreSystemEventHook( &event ) )
                if( !SysHandleEvent( &event ) )
                    if( !MenuHandleEvent( 0, &event, &error ) )
                        if( !AppHandleEvent( &event ) )
                            FrmDispatchEvent( &event );
        } while( event.eType != appStopEvent );
    }
}

 

ハードボタンの処理は SysHandleEvent( ) で行われてしまうため、AppHandleEvent( )をオーバーライドしてもハードボタンの処理をフックすることはできません。そのため、PreSystemEventHook( ) をオーバーライドする必要があります。

PreSystemEventHook( ) をオーバーライドしても、実際に押下されたハードボタンに対してどのような動作をするのは CForm 派生クラス側になります。そのため、アプリケーションクラスがフックしたハードボタンイベントを CForm 派生クラスに伝達する方法が必要になります。

 

PreSystemEventHook( ) から CForm 派生クラスへの伝達

フックしたイベントを他のオブジェクト( 画面クラス )へ伝達するための仕組みについて考えます。通常の(たとえば画面上のボタンなどのタップ)イベントについては POLの正規のルートで処理するという前提で、PreSystemEventHook( ) でフックする必要のあるイベントに限定した仕組みとして、以下の EventReceiver インタフェイスを考えます。

class EventReceiver {
public:
    virtual Boolean HandleEvent( EventType* pEvent ) = 0;
};

 

このインタフェイス(を実装するクラスのオブジェクト)をアプリケーションクラスに登録し、CPalmApp 派生クラスでオーバーライドする PreSystemEventHook( ) から呼び出すようにします。

class EventReceiver;

class CMyApp : public CPalmApp {
public:
    CMyApp( );

public:
    // :
    // :
    virtual Boolean PreSystemEventHook( EventType* pEvent );
    // :
    // :

    // Form map
    BEGIN_FORM_MAP()
        FORM_MAP_ENTRY(MYFORM, CMyForm)
    END_FORM_MAP()

private:
    EventReceiver* m_pEventReceiver;

public:
    static void RegisterEventReceiver( EventReceiver* pReceiver );

};

 

大雑把ですが、CMyApp::PreSystemEventHook( ) の実装は以下のような感じになるでしょう。

Boolean CMyApp::PreSystemEventHook( EventType* pEvent ) {
    if( pEvent->eType != keyDownEvent || !m_pEventHandler )
        return false;
    switch( pEvent->data.keyDown.chr ) {
    case vchrHard1:
    case vchrHard2:
    case vchrHard3:
    case vchrHard4:
        return m_pEventReceiver->HandleEvent( pEvent );
    }
    return false;
}

 

画面クラス側では、CForm( あるいは CModalForm )と同時に EventReceiver も継承します。

class CMyForm : public CForm, public EventReceiver {
    // :
    // :
public:
    // <<EventReceiver>>
    virtual Boolean HandleEvent( EventType* pEvent );
    // :
    // :
};

この CMyForm クラスの frmOpenEvent ハンドラで CMyApp::RegisterEventReceiver( )を呼び出して自身を登録することで、PreSystemEventHook( ) から CMyForm オブジェクトへハードボタン押下イベントを伝達できるようになります。また、frmCloseEvent ハンドラで登録を解除するために NULL を指定して再び CMyApp::RegisterEventReceiver( ) を呼び出す必要があることに注意してください。

 

注意事項

このページで紹介した方法は、筆者がハードボタン押下イベントを処理するために試行錯誤した結果であり、もっと良い(あるいはより正しい)方法が別に存在するかもしれません。より良い情報をお持ちの方はコメントいただけると幸いです。

 

 


Copyright(C) 2005-2017 project-enigma.
Generated by CL-PREFAB.