VC++(Win32)メモ:動的にアクセラレータキーを設定

アクセラレータキーはリソースから登録するのが一般的かとは思います。



この場合、リソースに登録し、LoadAccelerators()でリソースを読み込み、
TranslateAccelerator()でキーを監視するだけで使えて簡単なのですが、
ほとんど静的な操作になってしまい、ユーザーにキー設定をさせたい場合、ちょっと不便だったので、
アクセラレータキーの動的操作について調べてみました。

今後の為に、メモしておきたいと思います。
試してはいませんが、VB6とかでも上手く使えば便利かなと思ってます。(私の職場は未だVB6とVBAメインなので)



[アクセラレータテーブル作成]

アクセラレータをリソースを使わずに作成する場合には、CreateAcceleratorTable()を使用します。
//アクセラレータテーブル作成関数
HACCEL CreateAcceleratorTable(
  LPACCEL lpaccl,	// アクセラレータデータを持つ構造体配列へのポインタ
  int cEntries	// 配列内の構造体の数
);
lpacclにはACCEL構造体の配列、cEntriesにはlpacclに格納されているアクセラレータの数を指定します。

ACCEL構造体のデータが1つのアクセラレータキーの情報に相当することになります。
構造体の内容は以下のようになっています。
//ACCEL構造体
typedef struct tagACCEL {
    BYTE   fVirt;	//補助キーやkeyの設定(複数指定可)
		// FALT   (Altキー)
		// FSHIFT  (Shiftキー)
		// FCONTROL (Ctrlキー)
		// FVIRTKEY (keyを仮想キーとして扱う)
    WORD   key;	//キー
    WORD   cmd;	//アクセラレータキーID
} ACCEL, *LPACCEL
fVirtには、Altキー、Shiftキー、Ctrlキーの補助キー等を指定します。
FVIRTKEYは常に指定しておいて問題はないかと思います。
keyには、アクセラレータキーに設定したい文字や仮想キーコードを指定します。
cmdには、WM_COMMANDメッセージに格納されるアクセラレータのIDを指定します。

//CreateAcceleratorTableの使用例
{
	//ACCEL構造体の配列を準備
	ACCEL  wAccel[1];

	//ID1001のアクセラレータに「A」キーを指定
	wAccel[0].cmd = 1001;
	wAccel[0].key  = 'A';
	wAccel[0].fVirt = FVIRTKEY;

	//ID1002のアクセラレータに「Alt + Ctrl + B」キーを指定
	wAccel[1].cmd = 1002;
	wAccel[1].key  = 'B';
	wAccel[1].fVirt = FALT |  FCONTROL | FVIRTKEY;

	//アクセラレータテーブルを作成
	HACCEL haccel = CreateAcceleratorTable(wAccel, 2);
}
アクセラレータテーブルが作成されれば、後はLoadAccelerators()のときと同じようにTranslateAccelerator()でキーを監視させ、
WM_COMMANDメッセージで処理をするだけです。
//メッセージループ
while (GetMessage(&msg, NULL, 0, 0))
{
	//メッセージループでアクセラレータキーをチェック
	if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
}
//メッセージ処理
switch (message)
{
case WM_COMMAND:
	// 選択されたメニューの解析:
	switch (LOWORD(wParam))
	{
	case 1001:
		//アクセラレータキー1「Aキー」押下時処理
		break;
	case 1002:
		//アクセラレータキー2「Alt + Ctrl + Bキー」押下時処理
		break;
	}
break;
}




以下は私が書いてみたサンプルソースになります。
LoadAccelerators()で読み込んだアクセラレータテーブルの情報を直接変更する方法もあるかとは思いますが、
ここは私の好みでMyAccelというクラスにアクセラレータの情報を全て持たせて処理しています。
また、起動後にアクセラレータキーの変更をできるよう、アクセラレータテーブルはグローバル変数にしてみました。

なお、このソースを利用する場合は自己責任でお願いします。
間違い等があればご報告していただければと有難いです。

[Sample.cpp](メインファイル)
#include "MyAccel.h"
//===============================================================
//==定数定義==
//アクセラレータキーID
#define ACCEL_ID1      1001
#define ACCEL_ID2      1002
#define ACCEL_ID3      1003
//===============================================================
//==グローバル変数定義==
//アクセラレータテーブル
HACCEL gAccelTable;
//アクセラレータクラス
MyAccel* gAccel;
//===============================================================
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR    lpCmdLine, int       nCmdShow)
{
	//※ウィンドウ作成処理については省略
	//---------------------------------------------------------------------
	//アクセラレータクラスをインスタンス作成
	gAccel = new MyAccel();
	//各IDにキーを設定
	gAccel->AddAccel(ACCEL_ID1, 'A', FVIRTKEY);
	gAccel->AddAccel(ACCEL_ID2, 'B', FVIRTKEY | FSHIFT);
	gAccel->AddAccel(ACCEL_ID3, 'C', FVIRTKEY | FCONTROL | FALT);
	//アクセラレータテーブルを作成
	gAccelTable = gAccel->CreateAccelTable();
	//------------------------------
	// メイン メッセージ ループ:
	while (GetMessage(&msg, NULL, 0, 0))
	{
		//メッセージループでアクセラレータキーをチェック
		if (!TranslateAccelerator(msg.hwnd, gAccelTable, &msg))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}
	//------------------------------
	//インスタンス内のアクセラレータキー情報を破棄
	gAccel->DeleteAccelTable();
	//インスタンスを破棄
	delete gAccel;
	//---------------------------------------------------------------------
	return (int) msg.wParam;
}

//ウィンドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_COMMAND:
		// 選択されたメニューの解析:
		switch (LOWORD(wParam))
		{
		case ACCEL_ID1:
			//アクセラレータキー1押下時処理
			MessageBox(NULL, TEXT("ACCEL_ID1"), TEXT(""), NULL);
			break;
		case ACCEL_ID2:
			//アクセラレータキー2押下時処理
			MessageBox(NULL, TEXT("ACCEL_ID2"), TEXT(""), NULL);
			break;
		case ACCEL_ID3:
			//アクセラレータキー3押下時処理
			MessageBox(NULL, TEXT("ACCEL_ID3"), TEXT(""), NULL);
			//-----
			//アクセラレータを変更
			gAccel->ChangeAccel(ACCEL_ID3, 'D', FVIRTKEY);
			//アクセラレータテーブルを再作成
			gAccelTable = gAccel->CreateAccelTable();
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
		}
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

[MyAccel.h]
#include 
//===============================================================
//定数定義
#define MAX_ACCCEL_CNT 5	//登録するアクセラレータキーの最大数
//===============================================================
class MyAccel
{
private:
	//=================================
	//==Private変数定義==
	//アクセラレータテーブル
	HACCEL prAccelTable;
	//アクセラレータ情報配列
	ACCEL  prAccel[MAX_ACCCEL_CNT];
	//アクセラレータ情報数
	int    prAccelCnt;
	//=================================
public:
	//=================================
	//コンストラクタ
	MyAccel(void);
	//デストラクタ
	~MyAccel(void);
	//---------------------------
	//==Public関数定義==
	//アクセラレータ情報を追加
	bool AddAccel(WORD vID, WORD vKey, BYTE vVirt);
	//アクセラレータ情報変更
	bool ChangeAccel(WORD vID, WORD vKey, BYTE vVirt);
	//アクセラレータテーブルを作成
	HACCEL CreateAccelTable(void);
	//アクセラレータテーブルを削除
	bool   DeleteAccelTable(void);
	//=================================
};

[MyAccel.cpp]
#include "MyAccel.h"
//=====================================================================
//コンストラクタ
MyAccel::MyAccel(void)
{
	//初期化
	prAccelCnt   = 0;
	prAccelTable = NULL;
}

//デストラクタ
MyAccel::~MyAccel(void)
{
}

//=====================================================================

//アクセラレータ情報を追加
bool MyAccel::AddAccel(WORD vID, WORD vKey, BYTE vVirt)
{
	bool   wRet = true;
	ACCEL  wAccel;
	BYTE   wVirt = NULL;
	//-----------------------------------
	try
	{
		//追加するアクセラレータ情報を作成
		wAccel.cmd   = vID;		//ID
		wAccel.key   = vKey;	//キー
		wAccel.fVirt = vVirt;	//FALT,FSHIFT,FCONTROL,FVIRTKEY
		//-----------------------------------
		//アクセラレータを配列に格納
		prAccel[prAccelCnt] = wAccel;
		//-----------------------------------
		//アクセラレータ数をカウントアップ
		prAccelCnt++;
	}
	catch(...)
	{
		OutputDebugString(TEXT("エラー:MyAccel.AddAccel"));
		wRet = false;
	}
	//-----------------------------------
	return wRet;
}

//アクセラレータ情報変更
bool MyAccel::ChangeAccel(WORD vID, WORD vKey, BYTE vVirt)
{
	bool   wRet = true;
	ACCEL  wAccel;
	BYTE   wVirt = NULL;
	//-----------------------------------
	try
	{
		//追加するアクセラレータ情報を作成
		wAccel.cmd   = vID;		//ID
		wAccel.key   = vKey;	//キー
		wAccel.fVirt = vVirt;	//FALT,FSHIFT,FCONTROL,FVIRTKEY
		//-----------------------------------
		//変更する情報を探し、変更
		for(int i = 0; i < prAccelCnt; i++)
		{
			if(prAccel[i].cmd == vID)
			{
				prAccel[i] = wAccel;
				break;
			}
		}
	}
	catch(...)
	{
		OutputDebugString(TEXT("エラー:MyAccel.ChangeAccel"));
		wRet = false;
	}
	//-----------------------------------
	return wRet;
}

//アクセラレータテーブルを作成
HACCEL MyAccel::CreateAccelTable(void)
{
	int  wCnt = 0;
	//-----------------------------------
	try
	{
		//アクセラレータテーブルを作成
		prAccelTable = CreateAcceleratorTable(prAccel, prAccelCnt);
	}
	catch(...)
	{
		OutputDebugString(TEXT("エラー:MyAccel.CreateAccelTable"));
		prAccelTable = NULL;
	}
	//-----------------------------------
	return prAccelTable;
}

//アクセラレータテーブルを削除
bool MyAccel::DeleteAccelTable(void)
{
	bool   wRet = true;
	//-----------------------------------
	try
	{
		if(prAccelTable != NULL){
			if(DestroyAcceleratorTable(prAccelTable))
			{
				prAccelCnt   = 0;
				prAccelTable = NULL;
			}
			else
			{
				throw 0;
			}
		}
	}
	catch(...)
	{
		OutputDebugString(TEXT("エラー:MyAccel.DeleteAccelTable"));
		wRet = false;
	}
	//-----------------------------------
	return wRet;
}

コメント
コメントする








    
この記事のトラックバックURL
トラックバック