键盘检测指令:cat /dev/input/event1 | hexdump
鼠标检测指令:cat /dev/input/event2 | hexdump
当键盘/鼠标有输入时,会有对应的一堆16进制输出。它其实对应着input_event结构体【24字节】。
struct input_event
{
struct timeval time;
__u16 type;
__u16 code;
__s32 value;
};
//==================获取键盘数据====================
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/input.h>
#include <string.h>
int main(void)
{
#define KEY_PATH "/dev/input/event1"
int fd = -1, ret = -1;
struct input_event ev;
// 第1步:打开设备文件
fd = open(KEY_PATH, O_RDONLY);
if (fd < 0)
{
perror("open,error");
return -1;
}
printf("welcome size=%d.\n",sizeof(struct input_event));
while (1)
{
// 第2步:读取event事件包
memset(&ev, 0, sizeof(struct input_event));
ret = read(fd, &ev, sizeof(struct input_event));
if (ret != sizeof(struct input_event))
{
perror("read,error");
close(fd);
return -1;
}
// 第3步:解析event包.
printf("========================================================\n");
printf("[%11u] type: %3d, code: %3d, value: %3d \n",ev.time.tv_sec,ev.type,ev.code,ev.value);
//type: 1:按键同步
//code: 键码['a'=30]
//value:0:按键释放,1:按键按下,2:长按下
}
// 第4步:关闭设备
close(fd);
return 0;
}
//=======获取鼠标数据=========
#include <X11/Xlib.h>
//LDFLAGS := -lX11
int GetDisplayInfo(int *screen_width,int *screen_height)
{
Display *display = XOpenDisplay(NULL);
if (display == NULL)
{
printf("Error: cannot open display\n");
return 1;
}
int screen_num = DefaultScreen(display);
Screen *screen = ScreenOfDisplay(display, screen_num);
*screen_width = WidthOfScreen(screen);
*screen_height = HeightOfScreen(screen);
printf("Screen size: %dx%d pixels\n", WidthOfScreen(screen), HeightOfScreen(screen));
printf("Screen resolution: %dx%d dpi\n", (int) (WidthOfScreen(screen) * 25.4 / DisplayWidthMM(display, screen_num)),
(int) (HeightOfScreen(screen) * 25.4 / DisplayHeightMM(display, screen_num)));
XCloseDisplay(display);
return 0;
}
int get_xy(int fd,struct input_event ts,int *x,int *y)
{
static int nCnt = 0;
read(fd,&ts,sizeof(ts));
if(ts.type == EV_ABS && ts.code == ABS_X)
{
*x = ts.value;
nCnt = (nCnt+1)%3;
return nCnt;
}
if(ts.type == EV_ABS && ts.code == ABS_Y)
{
*y = ts.value;
nCnt = (nCnt+1)%3;
return nCnt;
}
return 0;
}
int main(void)
{
#define MOUSE_PATH "/dev/input/event2"
int fd = -1, ret = -1;
struct input_event ev;
int data_size = sizeof(struct input_event);
// 第1步:打开设备文件[需要权限运行]
fd = open(MOUSE_PATH, O_RDONLY);
if (fd < 0)
{
perror("open,error");
return -1;
}
printf("mouse test [%s],data size=%d.\n",MOUSE_PATH,sizeof(struct input_event));
int screen_width = 0;
int screen_height = 0;
if( GetDisplayInfo(&screen_width,&screen_height)>0)
{
perror("get display info,error");
return -2;
}
while (1)
{
static int raw_x=0;
static int raw_y=0;
int tmp =0;
tmp = get_xy(fd,ev,&raw_x,&raw_y);
if(tmp==2)
{
int curr_x = 0;
int curr_y = 0;
curr_x = raw_x*screen_width/0xFFFF;
curr_y = raw_y*screen_height/0xFFFF;
printf("mousePos: x=%d,y=%d.\n",curr_x,curr_y);
}
}
close(fd);
return 0;
}
//============linux中获取键盘按下的值=========================
#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>
// 保存原始终端设置的结构
struct termios original_termios;
// 设置终端为非阻塞模式
void set_nonblocking_mode()
{
struct termios newt;
// 获取当前终端设置
tcgetattr(STDIN_FILENO, &original_termios);
tcgetattr(STDIN_FILENO, &newt);
newt.c_lflag &= ~(ICANON | ECHO); // 禁用规范模式和回显
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
}
// 恢复终端设置为原始状态
void reset_terminal_mode() {
tcsetattr(STDIN_FILENO, TCSANOW, &original_termios);
}
// 检查是否有字符可读
int kbhit() {
struct termios oldt, newt;
int oldf;
tcgetattr(STDIN_FILENO, &oldt); // 获取当前终端设置
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO); // 禁用规范模式和回显
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
oldf = fcntl(STDIN_FILENO, F_GETFL, 0); // 获取文件状态标志
fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); // 设置为非阻塞模式
int ch = getchar(); // 尝试读取输入
tcsetattr(STDIN_FILENO, TCSANOW, &oldt); // 恢复原设置
fcntl(STDIN_FILENO, F_SETFL, oldf); // 恢复文件状态标志
if(ch != EOF) {
ungetc(ch, stdin); // 如果有输入,把字符放回标准输入
return 1; // 有输入
}
return 0; // 没有输入
}
int main() {
set_nonblocking_mode();
printf("Press any key to get its value...\n");
// 循环检查键盘输入
while (1) {
if (kbhit()) {
int c = getchar(); // 获取键盘值
printf("Key pressed: %c (ASCII: %d)\n", c, c);
if(c==27)
{
break; // 按下Esc键后退出
}
usleep(50*1000); // 等待50毫秒
}
usleep(20*1000); // 等待20毫秒
}
printf("\n\n====key test exit!====\n");
reset_terminal_mode();//还原终端配置
return 0;
}
方法2:采用SDL2 [simplle directmedia layer] , 此方法用于GUI项目,事件只针对SDL创建的窗口内有效
#include <stdio.h>
#include <SDL2/SDL.h>
#define SDL_HOR_RES (800)
#define SDL_VER_RES (600)
typedef struct TagMonitor
{
int screen_w;
int screen_h;
SDL_Renderer *render;
SDL_Texture *texture;
} tagMonitor;
// 将屏幕设置成指定ARGB颜色
int update_win(tagMonitor *mt, uint32_t argb)
{
uint32_t fb_data[SDL_HOR_RES * SDL_VER_RES]; // frame buffer data[w*h]
for (size_t i = 0; i < SDL_HOR_RES * SDL_VER_RES; i++)
{
fb_data[i] = argb;
}
SDL_UpdateTexture(mt->texture, NULL, fb_data, mt->screen_w * 4);
SDL_RenderClear(mt->render);
// 设定渲染的目标区域
SDL_Rect destRect;
destRect.x = 0;
destRect.y = 0;
destRect.w = mt->screen_w;
destRect.h = mt->screen_h;
// 复制材质到渲染器对象
if (SDL_RenderCopy(mt->render, mt->texture, NULL, &destRect))
{
printf("Error,%s \n", SDL_GetError());
return -1;
}
// 执行渲染操作
SDL_RenderPresent(mt->render);
return 0;
}
static void thread_read_key()
{
SDL_Event e;
int quit = 0;
while (!quit) {
usleep(5000);
while (SDL_PollEvent(&e) != 0) {
if (e.type == SDL_QUIT) {
quit = 1;
} else if (e.type == SDL_KEYDOWN) { // 检查是否按下了某个键
SDL_Keycode key = e.key.keysym.sym; // 获取按下的键的代码
if (key == SDLK_ESCAPE) { // 检查是否是退出键(例如ESC)
quit = 1;
} else {
printf("Key pressed: %d\n", key); // 打印按键代码或名称等(根据你的需求)
}
} else if (e.type == SDL_KEYUP) { // 检查是否释放了某个键(可选)
SDL_Keycode key = e.key.keysym.sym; // 获取释放的键的代码
// 可以添加处理释放键的代码,但不是必须的。
}
}
// 这里可以添加渲染代码,例如:SDL_RenderClear(renderer); 和 SDL_RenderPresent(renderer); 等。
}
}
文章介绍了如何在Linux系统中通过C语言获取键盘和鼠标输入事件,包括使用`cat/dev/input/eventX`命令查看16进制输出,以及通过设备文件读取`input_event`结构体来解析按键、坐标等信息。还提到了使用SDL2库在GUI项目中处理事件的方法。

642

被折叠的 条评论
为什么被折叠?



