Sleipnirの検索ボックスのホイール動作を無効化
Sleipnir (2.8.2限定) で、検索ボックスでのホイール動作を無効化するアプリを作ってみました(ホントはプラグインとかで実現できればよかったんですけど、Sleipnirのプラグイン仕様を調べるよりも、Win32で直接アプリ組むほうが楽だったので、ただのEXE式となっています)。
http://clock-up.jp/archives/SleipnirWheel.zip
メカニズム
まず、フック開始部分。ここは定番。
HANDLE hHook=SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, g_hDll, 0);
フックした場所でやること。WM_MOUSEWHEEL メッセージを書き換える。MSG構造体を直接書き換えちゃうのは、ややトリッキーかもしれない。私はフックの定石を知りません。
LRESULT CALLBACK GetMsgProc(int nCode,WPARAM wparam,LPARAM lparam) { if(nCode>=0 && wparam==PM_REMOVE){ MSG* msg=(MSG*)lparam; if(msg->message==WM_MOUSEWHEEL){ //検索ボックスでのホイールイベントを… if(IsSleipnirSearchBox(msg->hwnd)){ HWND hwndFrame = ::GetAncestor(msg->hwnd, GA_ROOT); HWND hwndTab = ::FindWindowEx(hwndFrame, NULL, L"Afx:00400000:0", NULL); HWND hwndPage = ::FindWindowEx(hwndTab, NULL, L"IEBrowserFrame", NULL); //ページウィンドウでのホイールイベントとして差し替える msg->hwnd = hwndPage; } } } return CallNextHookEx(hHook,nCode,wparam,lparam); }
ホイールの発生したウィンドウが検索ボックスであるかどうかの判定。
bool IsSleipnirSearchBox(HWND hwnd) { wchar_t szName[256]; //Sleipnirであることを確認 -> 異なる場合はfalseを返す HWND hwndFrame = ::GetAncestor(hwnd,GA_ROOT); if(!::GetWindowText(hwndFrame, szName, _countof(szName)))return false; if(wcsstr(szName, L"Sleipnir")==NULL)return false; //検索ボックスであることを確認 -> 異なる場合はfalseを返す while(1){ if(!::GetClassName(hwnd, szName, _countof(szName)))break; if(wcsicmp(szName, L"Edit")==0)goto next; else if(wcsicmp(szName, L"FenrirComboBoxCtrl")==0)return true; else if(wcsicmp(szName, L"FenrirSearchWindow")==0)return true; else return false; next: hwnd = ::GetParent(hwnd); } return false; }
メカニズムの前提条件
Sleipnir 2.8.2 のウィンドウ構造が以下のようになっていることを利用しています(これはSpy++で調べました)。
SleipnirMainWindow ├MDIClient │└Afx:00400000:0 │ └IEBrowserFrame (ページ表示部分) └Afx:~ └FenrirSearchWindow └FenrirComboBoxCtrl └Edit (検索ボックス)
展望
ホイールイベントが発生する度に文字列判定その他の処理が発生するので、負荷を考えると、あんまりよろしくない気分。Sleipnirプロセスのみに限定してフックを行えるなら、ちょっとは気が晴れるんですが。
理想としては、こんなフックアプリケーション作らなくてもいいように、Sleipnir自身に、検索ボックスでのホイール無効にできる機能が付いてほしい。
参考:
ここのフックの解説は、なんというか、妥協無く検証している感があって、なんか好き。
Filed under 未分類. Tags:
0 Comments.