第8回 アドレスバーで[BackSpace]キーが使えない問題を修正する (タブブラウザーを作る)

tabbrowser30.gif
前回までにWTLのタブビューをひな形にアドレスバーや「戻る」「進む」ボタンなどを実装してきた。タブブラウザーとしてそれなりに動くようになってきたが、アドレスバーに致命的な不具合があった。[BackSpace]や[←]キーなどが使えない点だ。今回はその点を修正する。


前回までに作成したプロジェクトのソリューションウインドウにある「MainFrm.h」をダブルクリックして編集画面を開く。

今まではアドレスバーはCComboBoxExをそのまま利用していたが、新しくアドレスバー用のクラスを追加する。このクラスでは中にあるコントロールをサブクラス化することにより、マウスによるフォーカス取得(WM_MOUSEACTIVATE)を受け取って、メインフレームへWM_DNP_CHANGEFOCUSへ送るだけの処理をしている。

アドレスバーへのフォーカス取得はWM_COMMANDのEN_SETFOCUSやEN_KILLFOCUSでも行える。しかし今回はEN_SETFOCUSによるタイミングで処理するとキーカーソル(キャレット)が消えてしまうためWM_MOUSEACTIVATEとした。 本当はEN_SETFOCUSLタイミングで処理した方がいいのだが、、、何時間かテストをしたが結局解決方法が見つからず今回は諦めた。
#define	WM_DNP_CHANGEFOCUS	(WM_APP + 1)		//■追加

//■追加
//アドレスバー用クラス
class	CAddressBarCtrl	: public CWindowImpl<CAddressBarCtrl,CComboBoxEx>
{
	class	CInnerComboBox	: public CWindowImpl<CInnerComboBox>
	{
	public:
		BEGIN_MSG_MAP(CInnerComboBox)
			MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate)
		END_MSG_MAP()


		//マウスによるフォーカス取得時の処理
		LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
		{
			GetTopLevelParent().SendMessage(WM_DNP_CHANGEFOCUS,(WPARAM)TRUE);		//メインウインドウへフォーカスを受け取ったことを通知
			bHandled = FALSE;
			return	0;
		}
	};

	CInnerComboBox	_wndInnerComboBox;

public:

	BEGIN_MSG_MAP(CAddressBarCtrl)
	END_MSG_MAP()


	HWND Create(HWND hWndParent, _U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
			DWORD dwStyle = 0, DWORD dwExStyle = 0,
			_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
	{
		HWND	hWnd;

		hWnd = __super::Create(hWndParent,rect,szWindowName,dwStyle,dwExStyle,MenuOrID,lpCreateParam);
		if(hWnd == NULL)
			return	NULL;

		_wndInnerComboBox.SubclassWindow(GetComboCtrl());	//サブクラス化

		return	hWnd;
	}
};

class CMainFrame : public CFrameWindowImpl<CMainFrame>, public CUpdateUI<CMainFrame>,
		public CMessageFilter, public CIdleHandler
{
	CAddressBarCtrl	_wndAddressBar;			//■変更 アドレスバー用コンボボックス

tabbrowser31.gif 次にアドレスバーから送られてきたWM_DNP_CHANGEFOCUSメッセージを処理して、IEコントロールからフォーカスを外す処理を実装する。ここではIOleInPlaceObject::UIDeactivate()を利用した。 ちなみにIDeskBand(IEツールバー)で同様の[BackSpace]キーが使えない問題を解消したいときは、IInputObjectSite::OnFocusChangeISを呼んでIInputObject::TranslateAcceleratorIOで処理する流れが一般的だ。
	BEGIN_MSG_MAP(CMainFrame)
		MESSAGE_HANDLER(WM_DNP_CHANGEFOCUS, OnDnpChangeFocus)		//■追加
		NOTIFY_CODE_HANDLER(CBEN_ENDEDIT, OnAddressbarEnter)
		MESSAGE_HANDLER(WM_CREATE, OnCreate)
		MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
		COMMAND_ID_HANDLER(ID_APP_EXIT, OnFileExit)
		COMMAND_ID_HANDLER(ID_FILE_NEW, OnFileNew)
		COMMAND_ID_HANDLER(ID_VIEW_TOOLBAR, OnViewToolBar)
		COMMAND_ID_HANDLER(ID_VIEW_STATUS_BAR, OnViewStatusBar)
		COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout)
		COMMAND_ID_HANDLER(ID_WINDOW_CLOSE, OnWindowClose)
		COMMAND_ID_HANDLER(ID_WINDOW_CLOSE_ALL, OnWindowCloseAll)
		COMMAND_RANGE_HANDLER(ID_WINDOW_TABFIRST, ID_WINDOW_TABLAST, OnWindowActivate)
		COMMAND_ID_HANDLER(ID_IE_BACK, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_NEXT, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_STOP, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_REFRESH, OnIECommand)
		CHAIN_MSG_MAP(CUpdateUI<CMainFrame>)
		CHAIN_MSG_MAP(CFrameWindowImpl<CMainFrame>)
	END_MSG_MAP()


	//■追加
	//フォーカス変更時処理
	LRESULT OnDnpChangeFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		BOOL	bHasFocus = (BOOL)wParam;		//アドレスバーなどがフォーカスを受け取っていたらTRUE

		int		nPage;
		CTabBrowser100View*	pView;

		nPage = m_view.GetActivePage();
		if(nPage < 0)
			return	0;		//アクティブなタブがない
		pView = (CTabBrowser100View*)m_view.GetPageData(nPage);
		if(pView == NULL)
			return	0;		//ビューが取得できなかった
		if(pView->_pIWebBrowser2 == NULL)
			return	0;

		if(bHasFocus)
		{
			//アドレスバーなどIE以外がフォーカスを受け取った

			CComPtr<IOleInPlaceObject> pIOleInPlaceObject;

			pView->_pIWebBrowser2->QueryInterface(&pIOleInPlaceObject);
			if(pIOleInPlaceObject)
				pIOleInPlaceObject->UIDeactivate();		//IEのUIを無効化
		}

		return	0;
	}

tabbrowser32.gif
これでビルド/実行するとアドレスバー内で[BackSpace]キーが普通に使えるようになった。

計画性なくタブブラウザーを作っているのと、画像をキャプチャーするためにソースコードを撮りやすく配置しているためなどなどの要因でだんだんソースコードがごちゃごちゃしてきた。ちょっと整理したい気もするのだがとりあえず保留して、次回はタブの右クリックメニューを実装する。

プロジェクトファイルをダウンロード


カテゴリー「タブブラウザーを作る」 のエントリー