Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/61.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C Linux中的鼠标事件处理?_C_Linux_Event Handling_Mouseevent - Fatal编程技术网

C Linux中的鼠标事件处理?

C Linux中的鼠标事件处理?,c,linux,event-handling,mouseevent,C,Linux,Event Handling,Mouseevent,我有一个事件处理代码,它为我的触摸板读取Linux的/dev/input/,并根据按下/释放的按钮打印结果 虽然。到目前为止,我的代码正在等待在终端上运行时按下按钮。我的下一步是运行这个事件处理线程和另一个线程(不是基于事件的)。如果我继续通过读取终端的输入来处理事件,我将无法作为main()的一部分执行其他线程,因为main()一直在等待按下按钮: int main(int argc, char** argv) { *Mouse event handling code here*

我有一个事件处理代码,它为我的触摸板读取Linux的/dev/input/,并根据按下/释放的按钮打印结果

虽然。到目前为止,我的代码正在等待在终端上运行时按下按钮。我的下一步是运行这个事件处理线程和另一个线程(不是基于事件的)。如果我继续通过读取终端的输入来处理事件,我将无法作为main()的一部分执行其他线程,因为main()一直在等待按下按钮:

int main(int argc, char** argv)
{
    *Mouse event handling code here*
    return 0; 
}

有没有一种不同的方法,比如读中断?或者我仍然可以采用这种方法并在代码中进行修改,使其作为线程的一部分工作(比如我可以让线程等待这些输入作为参数吗)?

如果您使事件设备描述符非阻塞(通过使用
O_NONBLOCK
标志打开它们),您可以很容易地使用等待,直到其中一个具有您可以读取的事件

考虑以下示例程序,example.c

#define  _POSIX_C_SOURCE  200809L
#define  _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/input.h>
#include <termios.h>
#include <poll.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>

/* Maximum number of input sources, including the terminal. */
#ifndef   MAX_INPUTS
#define   MAX_INPUTS  32
#endif

/* Maximum wait for events, in milliseconds (1000 ms = 1 second). */
#ifndef   INTERVAL_MS
#define   INTERVAL_MS  100
#endif

int main(int argc, char *argv[])
{
    unsigned char       keys[16];
    struct input_event  event;
    struct termios      config, oldconfig;
    struct pollfd       src[MAX_INPUTS];
    size_t              srcs, i, done;
    ssize_t             n;
    int                 arg, nsrcs;

    if (!isatty(STDIN_FILENO)) {
        fprintf(stderr, "Standard input is not a terminal.\n");
        return EXIT_FAILURE;
    }

    /* Save old terminal configuration. */
    if (tcgetattr(STDIN_FILENO, &oldconfig) == -1 ||
        tcgetattr(STDIN_FILENO, &config) == -1) {
        fprintf(stderr, "Cannot get terminal settings: %s.\n", strerror(errno));
        return EXIT_FAILURE;
    }

    /* Set new terminal configuration. */
    config.c_iflag &= ~(IGNBRK | BRKINT | PARMRK);
    config.c_lflag &= ~(ICANON | ISIG | ECHO | IEXTEN | TOSTOP);
    config.c_cc[VMIN] = 0;
    config.c_cc[VTIME] = 0;
    config.c_cc[VSTART] = 0;
    config.c_cc[VSTOP] = 0;
    if (tcsetattr(STDIN_FILENO, TCSANOW, &config) == -1) {
        const int  saved_errno = errno;
        tcsetattr(STDIN_FILENO, TCSANOW, &oldconfig);
        fprintf(stderr, "Cannot set terminal settings: %s.\n", strerror(saved_errno));
        return EXIT_FAILURE;
    }

    /* The very first input source is the terminal. */
    src[0].fd = STDIN_FILENO;
    src[0].events = POLLIN;
    src[0].revents = 0;
    srcs = 1;

    /* Add input devices from command line. */
    for (arg = 1; arg < argc; arg++) {
        int  fd;

        fd = open(argv[arg], O_RDONLY | O_NOCTTY | O_NONBLOCK);
        if (fd == -1) {
            fprintf(stderr, "Skipping input device %s: %s.\n", argv[arg], strerror(errno));
            continue;
        }

        if (srcs >= MAX_INPUTS) {
            fprintf(stderr, "Too many event sources.\n");
            return EXIT_FAILURE;
        }

        /* Optional: Grab input device, so only we receive its events. */
        ioctl(fd, EVIOCGRAB, 1);

        src[srcs].fd = fd;
        src[srcs].events = POLLIN;
        src[srcs].revents = 0;
        srcs++;
    }

    printf("Ready. Press Q to exit.\n");
    fflush(stdout);

    done = 0;
    while (!done) {

        nsrcs = poll(src, srcs, INTERVAL_MS);
        if (nsrcs == -1) {
            if (errno == EINTR)
                continue;
            fprintf(stderr, "poll(): %s.\n", strerror(errno));
            break;
        }

        /* Terminal is not an input source. */
        if (src[0].revents & POLLIN) {
            n = read(src[0].fd, keys, sizeof keys);
            if (n > 0) {
                for (i = 0; i < n; i++) {
                    if (keys[i] == 'q' || keys[i] == 'Q')
                        done = 1;
                    if (keys[i] >= 32 && keys[i] <= 126)
                        printf("Key '%c' = 0x%02x = %u pressed\n", keys[i], keys[i], keys[i]);
                    else
                    if (keys[i])
                        printf("Key '\\%03o' = 0x%02x = %u pressed\n", keys[i], keys[i], keys[i]);
                    else
                        printf("NUL key (0) pressed\n");
                }
                fflush(stdout);
            }
            src[0].revents = 0;
        }

        /* Check the other input sources. */
        for (i = 1; i < srcs; i++) {
            if (src[i].revents & POLLIN) {
                while (1) {
                    n = read(src[i].fd, &event, sizeof event);
                    if (n != sizeof event)
                        break;

                    if (event.type == EV_KEY && event.code == BTN_LEFT) {
                        if (event.value > 0)
                            printf("Left mouse button pressed\n");
                        else
                            printf("Left mouse button released\n");
                    }

                    if (event.type == EV_KEY && event.code == BTN_RIGHT) {
                        if (event.value > 0)
                            printf("Right mouse button pressed\n");
                        else
                            printf("Right mouse button released\n");
                    }
                }
                fflush(stdout);
            }
            src[i].revents = 0;             
        }
    }

    /* Close input devices. */
    for (i = 1; i < srcs; i++)
        close(src[i].fd);

    /* Restore terminal settings. */
    tcsetattr(src[0].fd, TCSAFLUSH, &oldconfig);

    printf("All done.\n");
    return EXIT_SUCCESS;
}
并使用例如

gcc -Wall -O2 example.c -o example
sudo ./example /dev/input/event5
其中
/dev/input/event5
是鼠标事件设备。请注意,您可以阅读
/sys/class/input/event5/device/name
以查找设备的名称(据内核所知;当以root用户身份运行时,这些名称与
evtest
显示的名称相同)

如果你不确定,你可以一直跑

for N in /sys/class/input/event*/device/name ; do 
    DEV="${N%%/device/name}" ; DEV="/dev/${DEV##/sys/class/}" ;
    NAME="$(cat "$N" 2>/dev/null)" ;
    printf "%s: %s\n" "$DEV" "$NAME" ;
done
在Bash、Dash或posixshell中,查看可以尝试哪些事件设备

上面的示例程序必须从终端或控制台运行,因为它也从终端获取输入。它将终端设置为非阻塞非规范模式,在该模式下,它可以接收单个按键。请注意,一些按键,如光标和功能键,实际上有几个字符长,以ESC开头(
\033



将输入事件循环拆分为单独的线程也是很常见的。只需要十几行,但“问题”就变成了独立线程如何通知主(或其他)线程新的输入事件/命令已经到达。上述非阻塞poll()方法通常更容易以非常健壮、直接的方式实现

如果您使事件设备描述符非阻塞(通过使用
O_NONBLOCK
标志打开它们),您可以很容易地使用等待,直到其中一个具有您可以读取的事件

考虑以下示例程序,example.c

#define  _POSIX_C_SOURCE  200809L
#define  _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/input.h>
#include <termios.h>
#include <poll.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>

/* Maximum number of input sources, including the terminal. */
#ifndef   MAX_INPUTS
#define   MAX_INPUTS  32
#endif

/* Maximum wait for events, in milliseconds (1000 ms = 1 second). */
#ifndef   INTERVAL_MS
#define   INTERVAL_MS  100
#endif

int main(int argc, char *argv[])
{
    unsigned char       keys[16];
    struct input_event  event;
    struct termios      config, oldconfig;
    struct pollfd       src[MAX_INPUTS];
    size_t              srcs, i, done;
    ssize_t             n;
    int                 arg, nsrcs;

    if (!isatty(STDIN_FILENO)) {
        fprintf(stderr, "Standard input is not a terminal.\n");
        return EXIT_FAILURE;
    }

    /* Save old terminal configuration. */
    if (tcgetattr(STDIN_FILENO, &oldconfig) == -1 ||
        tcgetattr(STDIN_FILENO, &config) == -1) {
        fprintf(stderr, "Cannot get terminal settings: %s.\n", strerror(errno));
        return EXIT_FAILURE;
    }

    /* Set new terminal configuration. */
    config.c_iflag &= ~(IGNBRK | BRKINT | PARMRK);
    config.c_lflag &= ~(ICANON | ISIG | ECHO | IEXTEN | TOSTOP);
    config.c_cc[VMIN] = 0;
    config.c_cc[VTIME] = 0;
    config.c_cc[VSTART] = 0;
    config.c_cc[VSTOP] = 0;
    if (tcsetattr(STDIN_FILENO, TCSANOW, &config) == -1) {
        const int  saved_errno = errno;
        tcsetattr(STDIN_FILENO, TCSANOW, &oldconfig);
        fprintf(stderr, "Cannot set terminal settings: %s.\n", strerror(saved_errno));
        return EXIT_FAILURE;
    }

    /* The very first input source is the terminal. */
    src[0].fd = STDIN_FILENO;
    src[0].events = POLLIN;
    src[0].revents = 0;
    srcs = 1;

    /* Add input devices from command line. */
    for (arg = 1; arg < argc; arg++) {
        int  fd;

        fd = open(argv[arg], O_RDONLY | O_NOCTTY | O_NONBLOCK);
        if (fd == -1) {
            fprintf(stderr, "Skipping input device %s: %s.\n", argv[arg], strerror(errno));
            continue;
        }

        if (srcs >= MAX_INPUTS) {
            fprintf(stderr, "Too many event sources.\n");
            return EXIT_FAILURE;
        }

        /* Optional: Grab input device, so only we receive its events. */
        ioctl(fd, EVIOCGRAB, 1);

        src[srcs].fd = fd;
        src[srcs].events = POLLIN;
        src[srcs].revents = 0;
        srcs++;
    }

    printf("Ready. Press Q to exit.\n");
    fflush(stdout);

    done = 0;
    while (!done) {

        nsrcs = poll(src, srcs, INTERVAL_MS);
        if (nsrcs == -1) {
            if (errno == EINTR)
                continue;
            fprintf(stderr, "poll(): %s.\n", strerror(errno));
            break;
        }

        /* Terminal is not an input source. */
        if (src[0].revents & POLLIN) {
            n = read(src[0].fd, keys, sizeof keys);
            if (n > 0) {
                for (i = 0; i < n; i++) {
                    if (keys[i] == 'q' || keys[i] == 'Q')
                        done = 1;
                    if (keys[i] >= 32 && keys[i] <= 126)
                        printf("Key '%c' = 0x%02x = %u pressed\n", keys[i], keys[i], keys[i]);
                    else
                    if (keys[i])
                        printf("Key '\\%03o' = 0x%02x = %u pressed\n", keys[i], keys[i], keys[i]);
                    else
                        printf("NUL key (0) pressed\n");
                }
                fflush(stdout);
            }
            src[0].revents = 0;
        }

        /* Check the other input sources. */
        for (i = 1; i < srcs; i++) {
            if (src[i].revents & POLLIN) {
                while (1) {
                    n = read(src[i].fd, &event, sizeof event);
                    if (n != sizeof event)
                        break;

                    if (event.type == EV_KEY && event.code == BTN_LEFT) {
                        if (event.value > 0)
                            printf("Left mouse button pressed\n");
                        else
                            printf("Left mouse button released\n");
                    }

                    if (event.type == EV_KEY && event.code == BTN_RIGHT) {
                        if (event.value > 0)
                            printf("Right mouse button pressed\n");
                        else
                            printf("Right mouse button released\n");
                    }
                }
                fflush(stdout);
            }
            src[i].revents = 0;             
        }
    }

    /* Close input devices. */
    for (i = 1; i < srcs; i++)
        close(src[i].fd);

    /* Restore terminal settings. */
    tcsetattr(src[0].fd, TCSAFLUSH, &oldconfig);

    printf("All done.\n");
    return EXIT_SUCCESS;
}
并使用例如

gcc -Wall -O2 example.c -o example
sudo ./example /dev/input/event5
其中
/dev/input/event5
是鼠标事件设备。请注意,您可以阅读
/sys/class/input/event5/device/name
以查找设备的名称(据内核所知;当以root用户身份运行时,这些名称与
evtest
显示的名称相同)

如果你不确定,你可以一直跑

for N in /sys/class/input/event*/device/name ; do 
    DEV="${N%%/device/name}" ; DEV="/dev/${DEV##/sys/class/}" ;
    NAME="$(cat "$N" 2>/dev/null)" ;
    printf "%s: %s\n" "$DEV" "$NAME" ;
done
在Bash、Dash或posixshell中,查看可以尝试哪些事件设备

上面的示例程序必须从终端或控制台运行,因为它也从终端获取输入。它将终端设置为非阻塞非规范模式,在该模式下,它可以接收单个按键。请注意,一些按键,如光标和功能键,实际上有几个字符长,以ESC开头(
\033



将输入事件循环拆分为单独的线程也是很常见的。只需要十几行,但“问题”就变成了独立线程如何通知主(或其他)线程新的输入事件/命令已经到达。上述非阻塞poll()方法通常更容易以非常健壮、直接的方式实现

我的简单投票。事件例程尝试从两个非阻塞FD获取数据,一个用于鼠标,一个用于键盘。事件例程在未准备就绪时返回-1或设备忙,任何低于该值的错误都会被事件捕获。这里的if语句首先尝试fmd、mouse,然后尝试fkd next。返回值小于1或零表示数据未就绪,线程休眠

if( ( ( imd = event(fmd,&ie) ) <=0)&& ( (  ikd = event(fkd,&ie)) <= 0)) 
    {
        usleep(TIMEOUT);
        continue;
    }

if((imd=事件(fmd和ie))My simple poll。事件例程尝试从两个非阻塞FD获取数据,一个用于鼠标,一个用于键盘。事件例程返回-1或设备忙(未准备就绪时),下面的任何错误都会被事件捕获。此处的if语句先尝试fmd、鼠标,然后尝试fkd next。返回值小于1或零表示数据未准备就绪,t他睡着了

if( ( ( imd = event(fmd,&ie) ) <=0)&& ( (  ikd = event(fkd,&ie)) <= 0)) 
    {
        usleep(TIMEOUT);
        continue;
    }

如果((imd=event(fmd,&ie))在linux上,所有内容都是一个文件,那么只需查看使用epoll处理鼠标的文件上的事件即可。在linux上,所有内容都是一个文件,例如,只需查看使用epoll处理鼠标的文件上的事件即可。