Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
cmake_minimum_required(VERSION 3.5)

project(EzBtn LANGUAGES C)
add_subdirectory(libscl)
add_executable(EzBtn main.c
ebtn/bit_array.h
ebtn/ebtn.c
ebtn/ebtn.h
example_user.c
)

include_directories(EzBtn PUBLIC
ebtn
)

target_link_libraries(EzBtn LINK_PRIVATE scl pthread)

target_include_directories(EzBtn PRIVATE
$<TARGET_PROPERTY:scl,INTERFACE_INCLUDE_DIRECTORIES>
)

include(GNUInstallDirs)
install(TARGETS EzBtn
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
200 changes: 138 additions & 62 deletions example_user.c → example_user_linux.c
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
#include "windows.h"
#include <stdio.h>
#include <stdlib.h>

#include <time.h>
#include <sys/time.h>
#include <termios.h>
#include "ebtn.h"

static LARGE_INTEGER freq, sys_start_time;
#include <unistd.h>
#include <fcntl.h>
#include <linux/input.h>
#include <pthread.h>
#include <stdatomic.h>
#include <errno.h> // 新增:用于错误处理
#include <string.h> // 新增:用于字符串操作
#include <sys/types.h> // 新增:系统类型定义
#include "libscl/SCL_map.h"
SCL_map_t btn_info_map;
#define KEY_DEVICE "/dev/input/event1" // 按键设备节点
static uint32_t get_tick(void);

typedef enum
{
USER_BUTTON_0 = 0,
Expand All @@ -28,6 +37,103 @@ typedef enum
USER_BUTTON_COMBO_3,
USER_BUTTON_COMBO_MAX,
} user_button_t;
static struct termios old_termios;
typedef struct key_btn_info_t
{
int key_value;
char key_status;
}key_btn_info_t;
user_button_t get_key_input(void) {
static int fd = -1;
struct input_event ev;
ssize_t n;

// 首次调用时打开设备
if (fd < 0) {
printf("Trying to open input device %s\n", KEY_DEVICE);
fd = open(KEY_DEVICE, O_RDONLY);
if (fd < 0) {
perror("Failed to open input device");
return USER_BUTTON_INVALID;
}
printf("Successfully opened input device %s\n", KEY_DEVICE);
}

// 读取输入事件
n = read(fd, &ev, sizeof(ev));
if (n == -1) {
if (errno != EAGAIN) {
perror("Error reading input device");
close(fd);
fd = -1;
}
return USER_BUTTON_INVALID;
}
else if (n != sizeof(ev)) {
fprintf(stderr, "Read incomplete input event (%zd bytes)\n", n);
return USER_BUTTON_INVALID;
}

// printf("Input event: type=%d code=%d value=%d\n", ev.type, ev.code, ev.value);
int key_value = USER_BUTTON_INVALID;
int key_status = 0;
if (ev.type == EV_KEY) {
key_status = ev.value;
switch (ev.code) {
case KEY_0:
key_value = USER_BUTTON_0;
break;
case KEY_1:
key_value = USER_BUTTON_1;
break;
case KEY_2:
key_value = USER_BUTTON_2;
break;
case KEY_3:
key_value = USER_BUTTON_3;
break;
case KEY_4:
key_value = USER_BUTTON_4;
break;
case KEY_5:
key_value = USER_BUTTON_5;
break;
case KEY_6:
key_value = USER_BUTTON_6;
break;
case KEY_7:
key_value = USER_BUTTON_7;
break;
case KEY_8:
key_value = USER_BUTTON_8;
break;
case KEY_9:
key_value = USER_BUTTON_9;
break;
default:
printf("Unmapped key code: %d\n", ev.code);
break;
}
if (key_value != USER_BUTTON_INVALID){
key_btn_info_t *key_btn_info = NULL;
key_btn_info = scl_map_access(btn_info_map, key_value);
if (key_btn_info == NULL){
key_btn_info = malloc(sizeof(key_btn_info_t));
memset(key_btn_info, 0, sizeof(key_btn_info_t));
key_btn_info->key_value = key_value;
key_btn_info->key_status = key_status;
scl_map_insert(btn_info_map, key_value, key_btn_info);
}
key_btn_info->key_value = key_value;
key_btn_info->key_status = key_status;
return key_value;
}
}
return USER_BUTTON_INVALID;
}




/* User defined settings */
static const ebtn_btn_param_t defaul_ebtn_param = EBTN_PARAMS_INIT(20, 0, 20, 300, 200, 500, 10);
Expand Down Expand Up @@ -109,45 +215,7 @@ static ebtn_btn_combo_dyn_t btns_combo_dyn[] = {

uint32_t last_time_keys_combo[USER_BUTTON_COMBO_MAX - USER_BUTTON_COMBO_0] = {0};

static int windows_get_match_key(uint16_t key_id)
{
int key = 0;
switch (key_id)
{
case USER_BUTTON_0:
key = '0';
break;
case USER_BUTTON_1:
key = '1';
break;
case USER_BUTTON_2:
key = '2';
break;
case USER_BUTTON_3:
key = '3';
break;
case USER_BUTTON_4:
key = '4';
break;
case USER_BUTTON_5:
key = '5';
break;
case USER_BUTTON_6:
key = '6';
break;
case USER_BUTTON_7:
key = '7';
break;
case USER_BUTTON_8:
key = '8';
break;
case USER_BUTTON_9:
key = '9';
break;
}

return key;
}

/**
* \brief Get input state callback
Expand All @@ -160,7 +228,11 @@ uint8_t prv_btn_get_state(struct ebtn_btn *btn)
* Function will return negative number if button is pressed,
* or zero if button is releases
*/
return GetAsyncKeyState(windows_get_match_key(btn->key_id)) < 0;
key_btn_info_t *key_btn_info = scl_map_access(btn_info_map, btn->key_id);
if (key_btn_info){
return key_btn_info->key_status;
}
return 0;
}

/**
Expand All @@ -173,7 +245,6 @@ void prv_btn_event(struct ebtn_btn *btn, ebtn_evt_t evt)
{
const char *s;
uint32_t color, keepalive_cnt = 0;
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
uint32_t diff_time = 0;
uint32_t *diff_time_ptr = NULL;
if (btn->key_id < USER_BUTTON_MAX)
Expand All @@ -198,44 +269,53 @@ void prv_btn_event(struct ebtn_btn *btn, ebtn_evt_t evt)
if (evt == EBTN_EVT_KEEPALIVE)
{
s = "KEEPALIVE";
color = FOREGROUND_RED | FOREGROUND_BLUE;
}
else if (evt == EBTN_EVT_ONPRESS)
{
s = "ONPRESS";
color = FOREGROUND_GREEN;
}
else if (evt == EBTN_EVT_ONRELEASE)
{
s = "ONRELEASE";
color = FOREGROUND_BLUE;
}
else if (evt == EBTN_EVT_ONCLICK)
{
s = "ONCLICK";
color = FOREGROUND_RED | FOREGROUND_GREEN;
}
else
{
s = "UNKNOWN";
color = FOREGROUND_RED;
}

SetConsoleTextAttribute(hConsole, color);
printf("[%7u][%6u] ID(hex):%4x, evt: %10s, keep-alive cnt: %3u, click cnt: %3u\r\n", (unsigned)get_tick(), (unsigned)diff_time, btn->key_id, s,
(unsigned)ebtn_keepalive_get_count(btn), (unsigned)ebtn_click_get_count(btn));
SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
}

void* key_listener_thread(void* arg) {
(void)arg;

while (1) {
int key = get_key_input(); // 使用上述任一方法
if (key != USER_BUTTON_INVALID) {
// atomic_store(&key_pressed, key);
}
usleep(10000); // 10ms间隔
}

return NULL;
}
static pthread_t key_thread;

/**
* \brief Example function
*/
int example_user(void)
{
uint32_t time_last;
printf("Application running\r\n");
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&sys_start_time);
btn_info_map = scl_map_new();
pthread_create(&key_thread, NULL, key_listener_thread, NULL);
pthread_detach(key_thread);

/* Define buttons */
ebtn_init(btns, EBTN_ARRAY_SIZE(btns), btns_combo, EBTN_ARRAY_SIZE(btns_combo), prv_btn_get_state, prv_btn_event);
Expand Down Expand Up @@ -269,7 +349,7 @@ int example_user(void)
ebtn_process(get_tick());

/* Artificial sleep to offload win process */
Sleep(5);
usleep(5000);
}
return 0;
}
Expand All @@ -280,11 +360,7 @@ int example_user(void)
*/
static uint32_t get_tick(void)
{
LONGLONG ret;
LARGE_INTEGER now;

QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&now);
ret = now.QuadPart - sys_start_time.QuadPart;
return (uint32_t)((ret * 1000) / freq.QuadPart);
struct timespec ts;
clock_gettime (CLOCK_MONOTONIC_RAW, &ts);
return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
}
27 changes: 27 additions & 0 deletions libscl/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#ignore .metadata
.metadata
#ignore obj and lib file
*.[oa]

#ignore temp files
*.swp
*.temp
*.tmp

#python
*.pyc


#ignore android project files
*.properties
build.xml
proguard-project.txt

#ignore android building directory
/obj/
/gen/
/bin/
/build*/
*/build/
/install/

31 changes: 31 additions & 0 deletions libscl/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12)

project(libscl C)

#include(CMakeCStdOpt)

set(HEADERS
include/libscl/SCL.h
include/libscl/SCL_map.h
)

set(SOURCES
src/map.c
)

add_library(scl ${SOURCES} ${HEADERS})

if (NOT WINDOWS)
target_compile_definitions(scl PUBLIC C99 _unix)
target_compile_options(scl PRIVATE -Wl,-no-undefined)
else()
target_compile_definitions(scl PUBLIC C99)
endif()

target_include_directories(scl
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include/libscl
)

install(TARGETS scl DESTINATION ${CMAKE_INSTALL_PREFIX}/lib)
install(DIRECTORY include/libscl DESTINATION ${CMAKE_INSTALL_PREFIX}/include)
Loading