在物联网产品中经常需要检测按键的长按和短按,并由此触发相应事件。
在Linux/openwrt系统中可以通过ioctrl的方式读取设备节点/dev/input/eventX,
并且轮询读取input_event信息便可以检测到按键的触发情况,
再结合多线程延时计数消抖来区分长短按事件。
input_key.c
/**
create by iversondeng168
*/
#include <stdio.h>
#include <linux/input.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <syslog.h>
#include <string.h>
#include <ctype.h>
#include <memory.h>
#include <pthread.h>
#include <signal.h>
typedef enum{FALSE,TRUE=!FALSE} BOOLEAN;
#define UI8 unsigned char
#define I8 char
#define UI32 unsigned int
#define I32 int
//输入事件设备节点
#define DEV_PATH "/dev/input/event0"
//wps按键code
#define WPS (115)
//reset按键code
#define ENTER (28)
//100ms时间基准
#define LOOP_TIME (100 * 1000)
//长按3S
#define LONG_PRESSED_3S (30)
//长按5S
#define LONG_PRESSED_5S (50)
static int is_wps_pressed = 0;
static int is_reset_pressed = 0;
//长短按检测线程
void* wps_check_thread(void*param)
{
int wps_tim_cnt = 0;
while(TRUE)
{
//wps按键触发检测并开始计时
if(is_wps_pressed){
wps_tim_cnt++;
}
//捕获长按
if(wps_tim_cnt >= LONG_PRESSED_3S)
{
wps_tim_cnt = 0;
printf("wps long pressed\n");
//等候松手
while(is_wps_pressed == 1)
{
usleep(LOOP_TIME);
}
}
//捕获短按
else if(wps_tim_cnt > 0 &&
wps_tim_cnt < LONG_PRESSED_3S &&
!is_wps_pressed)
{
wps_tim_cnt = 0;
printf("wps short pressed\n");
}
usleep(LOOP_TIME);
}
pthread_detach(pthread_self());
}
//长短按检测线程
void* reset_check_thread(void*param)
{
int reset_tim_cnt = 0;
while(TRUE)
{
//reset按键触发检测并开始计时
if(is_reset_pressed){
reset_tim_cnt++;
}
//捕获长按
if(reset_tim_cnt >= LONG_PRESSED_5S)
{
reset_tim_cnt = 0;
printf("reset long pressed\n");
//等候松手
while(is_reset_pressed == 1)
{
usleep(LOOP_TIME);
}
}
//捕获短按
else if(reset_tim_cnt > 0 &&
reset_tim_cnt < LONG_PRESSED_5S &&
!is_reset_pressed)
{
reset_tim_cnt = 0;
printf("reset short pressed\n");
}
usleep(LOOP_TIME);
}
pthread_detach(pthread_self());
}
//eg. input_key &
int main(int argc, char *argv[])
{
pthread_t wps_check_t;
pthread_t reset_check_t;
int keys_fd;
struct input_event evt;
keys_fd = open(DEV_PATH, O_RDONLY);
if(keys_fd <= 0)
{
printf("open %s device error!\n",DEV_PATH);
return -1;
}
if(pthread_create(&wps_check_t, NULL, wps_check_thread, NULL) != 0)
{
printf("wps_check_thread create failed...\n");
return -2;
}
pthread_detach(wps_check_t);
if(pthread_create(&reset_check_t, NULL, reset_check_thread, NULL) != 0)
{
printf("reset_check_thread create failed...\n");
return -3;
}
pthread_detach(reset_check_t);
while(TRUE)
{
if(read(keys_fd, &evt, sizeof(evt)) == sizeof(evt))
{
if(evt.type == EV_KEY)
{
//1代表按下,0代表抬起
if(evt.value == 1)
{
switch(evt.code)
{
case WPS:
is_wps_pressed = 1;
break;
case ENTER:
is_reset_pressed = 1;
break;
}
}
else if(evt.value == 0)
{
switch(evt.code)
{
case WPS:
is_wps_pressed = 0;
break;
case ENTER:
is_reset_pressed = 0;
break;
}
}
}
}
}
close(keys_fd);
return 0;
}
执行交叉编译
/home/source/prebuilt/gcc/linux-x86/arm/toolchain-sunxi-musl/toolchain/bin/arm-openwrt-linux-gcc input_key.c -o input_key -lpthread -O2 -w