gpt4 book ai didi

c - 如何优雅地异步停止 X11 事件循环

转载 作者:太空狗 更新时间:2023-10-29 16:11:53 25 4
gpt4 key购买 nike

我有一个有两个线程的小型 X11 应用程序。在一个线程中,我使用 XGrabKey() 监听 X11 事件,然后在一个循环中 XNextEvent()。另一个线程正在做其他事情,与 X11 无关。

这是相关线程的代码:

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/XF86keysym.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>

volatile bool loop = true;

void keyGrab(void)
{
Display *display = XOpenDisplay(0);
Window root = DefaultRootWindow(display);
int keycode = XKeysymToKeycode(display, XF86XK_AudioPlay);

XGrabKey(display, keycode, AnyModifier, root, False, GrabModeAsync, GrabModeAsync);
XSelectInput(display, root, KeyPressMask);

while (loop) {
XEvent event;
XNextEvent(display, &event);
switch (event.type) {
case KeyPress: puts("Play key pressed"); break;
}
}

XUngrabKey(display, keycode, AnyModifier, root);

XCloseDisplay(display);
}

目标是另一个线程可以告诉这个线程停止。

现在的问题是,在另一个线程中设置loop = false当然不会终止这个线程,至少不会立即终止。此线程卡在 XNextEvent() 中,因为这是一个阻塞调用。所以这是我的问题:如何让 XNextEvent() 返回的标准模式是什么?

我想我需要另一个线程来使用 XSendEvent(),但我找不到关于如何执行此操作的任何提示。我什至不知道哪种消息类型是合适的。会是 ClientMessage 吗?还有别的吗?我实际上尝试从另一个线程发送 ClientMessage,但我收到以下错误消息:

X Error of failed request:  BadValue (integer parameter out of range for operation)
Major opcode of failed request: 25 (X_SendEvent)
Value in failed request: 0x0
Serial number of failed request: 12
Current serial number in output stream: 12

这是我尝试并触发错误的另一个线程的相关代码片段(displayroot 由第一个线程初始化):

XEvent event;
memset(&event, 0, sizeof(event));
event.type = ClientMessage;
XSendEvent(display, root, False, 0, &event);

请注意,另一个线程本身不需要任何 X11 代码。另一个线程使用 X11 的唯一目的是告诉该线程终止。

请记住上下文中没有窗口。根窗口当然不算数,因为这仅用于全局捕获键。因此,销毁窗口不是解决方案。

最佳答案

根据这些页面

最好的解决方案是在 X 事件队列套接字上执行选择获取套接字是通过

实现的
#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

Display *dis;
Window win;
int x11_fd;
fd_set in_fds;

struct timeval tv;
XEvent ev;

int main() {
dis = XOpenDisplay(NULL);
win = XCreateSimpleWindow(dis, RootWindow(dis, 0), 1, 1, 256, 256,\
0, BlackPixel (dis, 0), BlackPixel(dis, 0));

// You don't need all of these. Make the mask as you normally would.
XSelectInput(dis, win,
ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask |
ButtonPressMask | ButtonReleaseMask | StructureNotifyMask
);

XMapWindow(dis, win);
XFlush(dis);

// This returns the FD of the X11 display (or something like that)
x11_fd = ConnectionNumber(dis);

// Main loop
while(1) {
// Create a File Description Set containing x11_fd
FD_ZERO(&in_fds);
FD_SET(x11_fd, &in_fds);

// Set our timer. One second sounds good.
tv.tv_usec = 0;
tv.tv_sec = 1;

// Wait for X Event or a Timer
if (select(x11_fd+1, &in_fds, 0, 0, &tv))
printf("Event Received!\n");
else
// Handle timer here
printf("Timer Fired!\n");

// Handle XEvents and flush the input
while(XPending(dis))
XNextEvent(dis, &ev);
}
return(0);
}

关于c - 如何优雅地异步停止 X11 事件循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29001189/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com