« 新年明けましておめでとうございます | メイン | 猛獣使いの体力と経験値 »

2008/01/03(木)

●キーカスタマイズ


管理者IDとパスワードを忘れない為に、早速日記を書く。

年末から更新してきた聞々ハヤえもんだが、そろそろキーカスタマイズ機能をつけることにする。以下の流れで開発を行っていく。

(1)動的にアクセラレータテーブルを管理する CAcceleratorTable クラスを作る。
※メンバ関数として、Create, Destroy, Add, Delete 関数を持つ。

(2)キーボードショートカットの選択にホットキーコントロールの使用を考えている為、CHotKeyCtrl クラスを作る。
※デフォルトのホットキーコントロールでは、スペースキー等入力不可なキーがあるのでサブクラス化できるようにしておく事。

(3)キーカスタマイズ用ウィンドウを管理する CKeySettingWnd_MainWnd クラスを作る。
※CFrameWnd クラスを継承する事。

(4)「システム→キー操作」メニューを追加。
※修正対象は、CMenu_MainWnd クラスと CMainWnd クラス。

これが済んだらホットキーに対応して、ウィンドウが非アクティブな場合でも操作ができるようにする。

さーて、作るぞ。

というわけで、まず、「(1)動的にアクセラレータテーブルを管理する CAcceleratorTable クラス」を書いてみた。

//----------------------------------------------------------------------------
// AcceleratorTable.h : アクセラレータテーブルの管理を行う
//----------------------------------------------------------------------------
#ifndef AcceleratorTableH
#define AcceleratorTableH

#include <windows.h>
//----------------------------------------------------------------------------
// アクセラレータテーブルの管理を行うクラス
//----------------------------------------------------------------------------
class CAcceleratorTable
{
public: // 関数

    CAcceleratorTable() : m_hAccel(0) { }
    virtual ~CAcceleratorTable() { Destroy(); }

    virtual BOOL Add(BYTE fVirt, WORD key, WORD cmd)
    {
        // ハンドルが存在しない場合は新たに作成する
        if(!m_hAccel)
        {
            ACCEL accel[1];
            ZeroMemory(&accel, sizeof(ACCEL));
            accel[0].fVirt = fVirt;
            accel[0].key = key;
            accel[0].cmd = cmd;

            Create(accel, 1);
        }
        else
        {
            int nAccel = GetNum();

            ACCEL * pAccel = new ACCEL[nAccel + 1];
            Copy(pAccel, nAccel);
            pAccel[nAccel].fVirt = fVirt;
            pAccel[nAccel].key = key;
            pAccel[nAccel].cmd = cmd;

            Create(pAccel, nAccel + 1);

            delete [] pAccel;
        }

        return m_hAccel ? TRUE : FALSE;
    }

    virtual int Copy(LPACCEL lpAccelDst, int cAccelEntries)
    {
        if(!m_hAccel) return 0;

        return CopyAcceleratorTable(m_hAccel, lpAccelDst, cAccelEntries);
    }

    virtual BOOL Create(LPACCEL pAccel, int nAccel)
    {
        Destroy();
        m_hAccel = CreateAcceleratorTable(pAccel, nAccel);
        return m_hAccel ? TRUE : FALSE;
    }

    virtual BOOL Delete(BYTE fVirt, WORD key, WORD cmd)
    {
        if(!m_hAccel) return FALSE;

        int nAccel = GetNum();

        ACCEL * pAccel = new ACCEL[nAccel];
        Copy(pAccel, nAccel);
        BOOL bFound = FALSE; // 同じエントリが見つかったかどうか
        for(int i = 0; i < nAccel; i++)
        {
            if(pAccel[i].fVirt == fVirt && pAccel[i].key == key && pAccel[i].cmd == cmd)
                bFound = TRUE;

            if(bFound) // 見つかったら、1つずつ前に移動
            {
                pAccel[i].fVirt = pAccel[i + 1].fVirt;
                pAccel[i].key = pAccel[i + 1].key;
                pAccel[i].cmd = pAccel[i + 1].cmd;
            }
        }

        if(bFound) Create(pAccel, nAccel - 1);

        delete [] pAccel;

        return m_hAccel ? TRUE : FALSE;
    }

    virtual BOOL Destroy()
    {
        BOOL bSuccess = FALSE;
        if(m_hAccel)
        {
            bSuccess = DestroyAcceleratorTable(m_hAccel);
            m_hAccel = 0;
        }
        return bSuccess;
    }

    // エントリ数を得る
    virtual int GetNum() { return Copy(NULL, 0); }

private: // メンバ変数

    HACCEL m_hAccel;

public: // メンバ変数の取得

    operator HACCEL() const { return m_hAccel; }
};
//----------------------------------------------------------------------------

#endif

これで、動的にアクセラレータテーブルを管理する事ができる。

次。「(2)キーボードショートカットの選択にホットキーコントロールの使用を考えている為、CHotKeyCtrl クラス」を作る。まあ、今までのコントロールと同じイメージ。

//----------------------------------------------------------------------------
// HotKeyCtrl.h : ホットキーコントロールの管理を行う
//----------------------------------------------------------------------------
#ifndef HotKeyCtrlH
#define HotKeyCtrlH

#include <commctrl.h>
#include "Wnd.h"
//----------------------------------------------------------------------------
// ホットキーコントロールの管理を行うクラス
//----------------------------------------------------------------------------
class CHotKeyCtrl : public CWnd
{
public: // 関数

    CHotKeyCtrl() { }
    virtual ~CHotKeyCtrl() { }

    virtual BOOL Create(HWND hParentWnd)
    {
        Destroy();
    
        INITCOMMONCONTROLSEX ic;
        ic.dwSize = sizeof(INITCOMMONCONTROLSEX);
        ic.dwICC = ICC_HOTKEY_CLASS;
        InitCommonControlsEx(&ic);

        m_hWnd = CreateWindow(HOTKEY_CLASS, "", WS_CHILD, CW_USEDEFAULT,
                                CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
                                hParentWnd, 0, GetModuleHandle(NULL), NULL);
        if(!m_hWnd) return FALSE;
        SetProc();
        return TRUE;
    }
};
//----------------------------------------------------------------------------

#endif

実際に使うホットキーコントロールは、こいつを継承して作る。

次。「(3)キーカスタマイズ用ウィンドウを管理する CKeySettingWnd_MainWnd クラス」を作る。

キーカスタマイズ用ウィンドウには、ショートカット羅列用のリストビューと追加ボタン、変更ボタン、デフォルトの復元ボタン、OKボタン、キャンセルボタンがある。追加ボタン、変更ボタンを押すと、ショートカット入力用の別ウィンドウが表示される。ショートカット入力用ウィンドウには、コマンド選択用コンボボックス、ホットキーコントロール、OKボタン、キャンセルボタンがある。

コマンド名については、キーカスタマイズ用ウィンドウが管理する。GetCommandName関数を持っており、ID→コマンド名、コマンド名→IDの相互変換が可能。

トラックバックURL

このエントリーのトラックバックURL:
http://www.edolfzoku.com/diary/mt-tb.cgi/167

コメントする