私の目標は、バックグラウンドでスリープするが、ユーザーが「ホットキー」を介してアクティブ化できるプログラムを作成することです。 XlibマニュアルとXlibO'reillyマニュアルを掘り下げてみると、これを行う正しい方法はXGrabKeyを使用することであることがわかりました。ただし、単純な概念実証が機能しないため、プロセスの私の理解は正しくありません。
私の理解では、ルートウィンドウをgrab_windowとしてXGrabKeyを呼び出し、owner_eventsをfalseにすると、ホットキーが押されるたびに、イベントがルートウィンドウに送信されますのみ。次に、ルートウィンドウからKeyPressイベントを選択し、Xイベントをリッスンすると、ホットキーが押されたときにキープレスイベントを取得する必要があります。以下に最小限の例を貼り付けました。
私が期待しているのは、プログラムの実行時に、フォーカスのあるウィンドウに関係なく、Ctrl + Shift + Kを押すと、プログラムは「ホットキーが押されました!」と出力するはずです。コンソールで、を終了します。
さらに、XGrabKeyが失敗した場合、デフォルトのエラーハンドラーがメッセージを表示することを理解していますが、そうではないため、呼び出しは成功したと想定しています。
明らかに、私の理解はどういうわけか欠陥があります。誰かが私を正しい方向に向けることができますか?
#include <iostream>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
using namespace std;
int main()
{
Display* dpy = XOpenDisplay(0);
Window root = DefaultRootWindow(dpy);
XEvent ev;
unsigned int modifiers = ControlMask | ShiftMask;
int keycode = XKeysymToKeycode(dpy,XK_Y);
Window grab_window = root;
Bool owner_events = False;
int pointer_mode = GrabModeAsync;
int keyboard_mode = GrabModeAsync;
XGrabKey(dpy, keycode, modifiers, grab_window, owner_events, pointer_mode,
keyboard_mode);
XSelectInput(dpy, root, KeyPressMask );
while(true)
{
bool shouldQuit = false;
XNextEvent(dpy, &ev);
switch(ev.type)
{
case KeyPress:
cout << "Hot key pressed!" << endl;
XUngrabKey(dpy,keycode,modifiers,grab_window);
shouldQuit = true;
default:
break;
}
if(shouldQuit)
break;
}
XCloseDisplay(dpy);
return 0;
}
あなたのプログラムはここで機能します。私の推測では、NumLockなどの別の修飾子がアクティブになっています。 GrabKeyは、exact修飾子マスクでのみ機能します。
たとえば、ここにmetacityウィンドウマネージャーからのいくつかの(GPL)コードがあります
/* Grab/ungrab, ignoring all annoying modifiers like NumLock etc. */
static void
meta_change_keygrab (MetaDisplay *display,
Window xwindow,
gboolean grab,
int keysym,
unsigned int keycode,
int modmask)
{
unsigned int ignored_mask;
/* Grab keycode/modmask, together with
* all combinations of ignored modifiers.
* X provides no better way to do this.
*/
meta_topic (META_DEBUG_KEYBINDINGS,
"%s keybinding %s keycode %d mask 0x%x on 0x%lx\n",
grab ? "Grabbing" : "Ungrabbing",
keysym_name (keysym), keycode,
modmask, xwindow);
/* efficiency, avoid so many XSync() */
meta_error_trap_Push (display);
ignored_mask = 0;
while (ignored_mask <= display->ignored_modifier_mask)
{
if (ignored_mask & ~(display->ignored_modifier_mask))
{
/* Not a combination of ignored modifiers
* (it contains some non-ignored modifiers)
*/
++ignored_mask;
continue;
}
if (meta_is_debugging ())
meta_error_trap_Push_with_return (display);
if (grab)
XGrabKey (display->xdisplay, keycode,
modmask | ignored_mask,
xwindow,
True,
GrabModeAsync, GrabModeSync);
else
XUngrabKey (display->xdisplay, keycode,
modmask | ignored_mask,
xwindow);
if (meta_is_debugging ())
{
int result;
result = meta_error_trap_pop_with_return (display, FALSE);
if (grab && result != Success)
{
if (result == BadAccess)
meta_warning (_("Some other program is already using the key %s with modifiers %x as a binding\n"), keysym_name (keysym), modmask | ignored_mask);
else
meta_topic (META_DEBUG_KEYBINDINGS,
"Failed to grab key %s with modifiers %x\n",
keysym_name (keysym), modmask | ignored_mask);
}
}
++ignored_mask;
}
meta_error_trap_pop (display, FALSE);
}
マスク_ControlMask | ShiftMask
_を使用すると、別の修飾キーが保持されている場合、キーを取得できません。そもそもこれは問題ないように聞こえますが、落とし穴があります:NumLock、CapsLockおよび同様に、すべても修飾子として扱われます。
2つのオプションがあります。
XGrabKey()
を複数回呼び出します。関心のある明示的な組み合わせごとに、1回ずつ呼び出します。AnyModifier
を指定してXGrabKey()
を呼び出し、_event.xkey.state
_を使用して、修飾子が期待どおりかどうかを確認します。ヘッダーファイル_<X.h>
_は、ShiftMask
、LockMask
、ControlMask
、_Mod1Mask
_、_Mod2Mask
_、_Mod3Mask
_、_Mod4Mask
_、_Mod5Mask
_およびAnyModifier
。
キーは次のとおりです。
_Mask | Value | Key
------------+-------+------------
ShiftMask | 1 | Shift
LockMask | 2 | Caps Lock
ControlMask | 4 | Ctrl
Mod1Mask | 8 | Alt
Mod2Mask | 16 | Num Lock
Mod3Mask | 32 | Scroll Lock
Mod4Mask | 64 | Windows
Mod5Mask | 128 | ???
_
警告試してみてModNMask
キーについて知りましたが、これがすべてのマシン/構成/バージョン/オペレーティングシステムで有効かどうかわかりません。
あなたの場合、おそらく_ShiftMask | CtrlMask
_が設定されていること、_Mod1Mask | Mod4Mask
_がクリアされていること、その他は無視されていることを確認する必要があります。
キーグラブを設定するためにこれを行います。
_XGrabKey(dpy, keycode, AnyModifier, grab_window, owner_events, pointer_mode, keyboard_mode);
_
そして、これは正しい修飾子が設定されているかどうかを確認します。
_switch (ev.type) {
case KeyPress:
if ((ev.xkey.state & (ShiftMask | CtrlMask | Mod1Mask | Mod4Mask)) == (ShiftMask | CtrlMask))
// ...
}
_
X11でgtkを使用/ターゲティングしている場合は、はるかに単純なインターフェイスを備えたCライブラリがあります。
https://github.com/engla/keybinder
Python、Lua、Valaのバインディングが含まれています。 (また言及 ここ 。)