うーん、私はそれを解決することができましたが、私は解決策に満足していません. 少なくとも謎はなく、機能します:)。
ホットキー Ctrl+Alt+F11 と Ctrl+Alt+F12 を受け取らなかった理由
それらはグローバルホットキーとして登録されました。私はこれを、スタックオーバーフローのメンバーである気分の仲間のActiveHotkeysプログラムを使用して見つけることができました (どうもありがとう!)。どのプログラムが特定のホットキーを登録したかを調べる文書化された方法はないようです (そして、私のシステムでは何もしませんでした)。この問題については、moodforaday のスレッドを参照してください。
ソリューション
前述のスレッドの回答の 1 つから、別の質問にたどり着きました。Efotinis の答えは、私にとって完璧でした。低レベルのキーボード フックを設定した経験はありませんでしたが、思ったほど難しくはありませんでした。将来のために、Qtアプリケーションでどのように行ったかを次に示します。
私のmainwindow.hで:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
// ... code
private:
void tryLogin();
friend LRESULT CALLBACK LowLevelKeyboardProc(int code, WPARAM wparam, LPARAM lparam);
};
LRESULT CALLBACK LowLevelKeyboardProc(int code, WPARAM wparam, LPARAM lparam);
私のmainwindow.cppで:
// setting up the hook in the constructor
SetWindowsHookEx(WH_KEYBOARD_LL,
LowLevelKeyboardProc,
NULL,
0);
フックコード(主にefotinisの回答から):
LRESULT CALLBACK LowLevelKeyboardProc(int code, WPARAM wparam, LPARAM lparam)
{
KBDLLHOOKSTRUCT* kllhs = reinterpret_cast<KBDLLHOOKSTRUCT*>(lparam);
if (code == HC_ACTION)
{
if (wparam == WM_KEYDOWN && kllhs->vkCode == VK_F12 &&
(GetAsyncKeyState(VK_MENU) < 0 && GetAsyncKeyState(VK_CONTROL) < 0))
{
MainWindow* w = dynamic_cast<MainWindow*>(qApp->activeWindow());
if (NULL != w)
{
w->tryLogin(); // this should not be blocking!
return 1;
}
}
}
return CallNextHookEx(0, code, wparam, lparam);
}
ご覧のとおり、グローバル QApplication オブジェクトからアプリケーション ウィンドウへのポインターを取得します。dynamic_cast を使用しているため、アクティブなウィンドウがたまたま MainWindow インスタンスではないため、NULL ポインターが取得されます。
なぜ GetAsyncKeyState 呼び出しが < 0 であるかどうかがチェックされるのは、キーが押されている場合にこの関数が MSB を設定して戻るためです。また、MSB が設定されている場合、SHORT 番号は負になります (x86/x64 および互換プラットフォーム上)。符号付き整数の表現が異なるプラットフォームに Windows が移植されると、このコードが壊れる可能性があります。絶対に適切な方法は、16 ビット マスクを作成し、それを使用して MSB をチェックすることですが、私はそれを行うのが面倒です。:)
注意すべきことの 1 つは、フックから関数を呼び出すと、Qt イベント ループが処理を開始したばかりであるということです。つまり、関数から戻らない限り、UI がブロックされます (数秒間フリーズします)。私のようにダイアログを表示したい場合は、 の代わりにandexec()
を呼び出し、ダイアログのウィンドウ モダリティをモーダルに設定します (コンストラクターで)。raise, activateWindow
show
必要に応じてUnHookWindowsHookExでフックの登録を解除できます (これは、フックを含むモジュールがアンロードされたときに発生します)。これを行うには、SetWindowsHookEx 呼び出しの戻り値を保存します。