忽略 X11 应用程序中的自动重复
如果您在启用 AutoRepeat 的情况下按住 X11 中的某个键,您将持续收到 KeyPress 和 KeyRelease 事件。我知道可以使用函数XAutoRepeatOff()禁用AutoRepeat,但这会更改整个X服务器的设置。有没有办法为单个应用程序禁用“自动重复”或忽略重复的击键?
我正在寻找的是按下按键时的单个 KeyPress 事件和释放按键时的单个 KeyRelease 事件,而不干扰 X 服务器的自动重复设置。
下面是一个帮助您入门的最小示例(主要来自初学者 Xlib 教程):
#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>
Display *dis;
Window win;
XEvent report;
int main ()
{
dis = XOpenDisplay (NULL);
// XAutoRepeatOn(dis);
win = XCreateSimpleWindow (dis, RootWindow (dis, 0), 1, 1, 500, 500,
0, BlackPixel (dis, 0), BlackPixel (dis, 0));
XSelectInput (dis, win, KeyPressMask | KeyReleaseMask);
XMapWindow (dis, win);
XFlush (dis);
while (1)
{
XNextEvent (dis, &report);
switch (report.type)
{
case KeyPress:
fprintf (stdout, "key #%ld was pressed.\n",
(long) XLookupKeysym (&report.xkey, 0));
break;
case KeyRelease:
fprintf (stdout, "key #%ld was released.\n",
(long) XLookupKeysym (&report.xkey, 0));
break;
}
}
return (0);
}
If you press and hold a key in X11 while AutoRepeat is enabled, you continuously receive KeyPress and KeyRelease events. I know that AutoRepeat can be disabled using the function XAutoRepeatOff(), but this changes the setting for the whole X server. Is there a way to either disable AutoRepeat for a single application or to ignore repeated keystrokes?
What I'm looking for is a single KeyPress event when a key is pressed and a single KeyRelease event when a key is released, without interfering with the X server's AutoRepeat setting.
Here's a minimal example to get you going (mostly from the Beginner Xlib Tutorial):
#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>
Display *dis;
Window win;
XEvent report;
int main ()
{
dis = XOpenDisplay (NULL);
// XAutoRepeatOn(dis);
win = XCreateSimpleWindow (dis, RootWindow (dis, 0), 1, 1, 500, 500,
0, BlackPixel (dis, 0), BlackPixel (dis, 0));
XSelectInput (dis, win, KeyPressMask | KeyReleaseMask);
XMapWindow (dis, win);
XFlush (dis);
while (1)
{
XNextEvent (dis, &report);
switch (report.type)
{
case KeyPress:
fprintf (stdout, "key #%ld was pressed.\n",
(long) XLookupKeysym (&report.xkey, 0));
break;
case KeyRelease:
fprintf (stdout, "key #%ld was released.\n",
(long) XLookupKeysym (&report.xkey, 0));
break;
}
}
return (0);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
当您收到按键释放并且下一个事件是按下相同组合键的按键时,则会自动重复并且该按键并未实际释放。您可以使用这样的代码来查看下一个事件
When you receive a key release and the next event is a key press of the same key combination, then it's auto-repeat and the key wasn't acutally released. You can use code like this to peek next event
您可以使用 XkbSetDetectableAutorepeat 函数告诉 X 服务器仅在用户访问时发送 KeyRelease 事件实际上释放按键 - 当您不想要自动重复事件时,您将丢弃任何不匹配 KeyRelease 的 KeyPress。
You can use the XkbSetDetectableAutorepeat function to tell the X server to only send KeyRelease events when the user actually releases the key - when you don't want autorepeat events, then you discard any KeyPress without matching KeyRelease.
供您参考,这是一个删除自动重复的 KeyPress 事件的最小工作示例。 谢谢你,kralyk!
For your reference, here's a working minimal example that deletes auto-repeated KeyPress events. Thank you, kralyk!
您可以在按下或释放按键时设置计时器,并忽略重复间隔内发生的 KeyPress 和 KeyRelease 事件。
You could set a timer when a key is pressed or released and ignore KeyPress and KeyRelease events that occur within the repetition interval.
另一种方法。它对我有用。
another approach. it works for me.
这是我想出的解决方案。
因此,每次收到 KeyRelease 事件时,我都会使用
XQueryKeymap
它将按下的键的位复制到keys
(8 个不同的键由char
组成) 。对于那些不习惯使用按位运算符和移位运算符的人,这里有一个简单的解释:
keys[event.xkey.keycode>>3]
搜索索引event.xkey。 keycode / 8
使用“右移运算符”(允许“整数除”2、4、8、16 等,无需类型转换为 float 或 double 并返回整数)。<代码>0x1 << (event.xkey.keycode % 8) 则相反。它将
0x1
(== 1
) 的值乘以 2,得到(event.xkey.keycode % 8)
& ;
keys[event.xkey.keycode>>3] 和0x1 << 之间的按位运算符(event.xkey.keycode % 8)
将比较右侧操作数中设置的 only 位是否在此数组索引内设置为 1。如果是这样,则该键被按下。最后,您只需将其括在
()
中,前面加上一个!
,如果结果为 true,则不再按该键。最后一个注意:要使用此方法,您需要不断向 XServer 提供事件。如果没有,XQueryKeymap 将冻结直到它完成(最好与线程一起使用)。
Here's the solution I came up with.
So, everytime I get a KeyRelease event, I use
XQueryKeymap
which will copy tokeys
the bits of pressed keys (8 different keys bychar
).For the ones who are not used to work with bitwise operatos and shift operator, here's a simple explanation:
keys[event.xkey.keycode>>3]
search for indexevent.xkey.keycode / 8
using "right shift operator" (that allows for "integer division" by 2, 4, 8, 16 and so on, without type cast to float or double and back to integer).0x1 << (event.xkey.keycode % 8)
does the oposite. It multiplies the value of0x1
(== 1
) by 2 raised to(event.xkey.keycode % 8)
The
&
bitwise operator betweenkeys[event.xkey.keycode>>3]
and0x1 << (event.xkey.keycode % 8)
will compare if the only bit set in the right side operand is set to 1 inside this array index. If so, the key is being pressed.Finally you just enclose it in
()
, with a!
right before and if the result becomes true, you're not pressing that key anymore.One final Note: To use this method, you need to keep feeding the XServer with events. If not, XQueryKeymap will freze until it does (better use with threads).