blob: 9d6c7df935829b8b5d436a5c418b8fdddc81047d [file] [log] [blame]
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <linux/input.h>
#include <pthread.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <ctype.h>
#include "events.h"
#include "events_process.h"
#define WAIT_KEY_TIMEOUT_SEC 120
#define nullptr NULL
#define KEY_EVENT_TIME_INTERVAL 20
EventsProcess:: KeyMapItem_t g_default_keymap[] = {
{ "power", KEY_POWER },
{ "down", KEY_DOWN },
{ "up", KEY_UP },
};
EventsProcess::EventsProcess()
: key_queue_len(0),
key_last_down(-1),
last_key(-1),
key_down_count(0),
report_longpress_flag(false),
num_keys(0),
keys_map(NULL) {
pthread_mutex_init(&key_queue_mutex, nullptr);
pthread_cond_init(&key_queue_cond, nullptr);
memset(key_pressed, 0, sizeof(key_pressed));
memset(&last_queue_time, 0, sizeof(last_queue_time));
load_key_map();
}
int EventsProcess::InputCallback(int fd, uint32_t epevents, void* data) {
return reinterpret_cast<EventsProcess*>(data)->OnInputEvent(fd, epevents);
}
static void* InputThreadLoop(void*) {
while (true) {
if (!ev_wait(-1)) {
ev_dispatch();
}
}
return nullptr;
}
void EventsProcess::Init() {
ev_init(InputCallback, this);
pthread_create(&input_thread_, nullptr, InputThreadLoop, nullptr);
}
int EventsProcess::OnInputEvent(int fd, uint32_t epevents) {
struct input_event ev;
if (ev_get_input(fd, epevents, &ev) == -1) {
return -1;
}
if (ev.type == EV_SYN) {
return 0;
}
if (ev.type == EV_KEY && ev.code <= KEY_MAX) {
int code = getMapKey(ev.code);
if (code > 0) {
ProcessKey(code, ev.value);
} else {
ProcessKey(ev.code, ev.value);
}
}
return 0;
}
/* use CLOCK_MONOTONIC clock, gettimeofday will overlap if ntp changes */
uint64_t EventsProcess::getSystemTimeUs() {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (ts.tv_sec)*1000000LL + ts.tv_nsec/1000LL;
}
void EventsProcess::ProcessKey(int key_code, int value) {
bool register_key = false;
bool flag = false;
pthread_mutex_lock(&key_queue_mutex);
key_pressed[key_code] = value;
if (value == 1) {/*1:key down*/
KeyEvent *ke = new KeyEvent;
ke->down_ts_us = getSystemTimeUs();
ke->keyCode = key_code;
ke->keyState = value; /*key down*/
ke->longPress = false;
ke->curlongPress = false;
mKeyEventVec.push_back(ke);
++key_down_count;
key_last_down = key_code;
key_timer_t* info = new key_timer_t;
info->ep = this;
info->key_code = key_code;
info->count = key_down_count;
info->ke = ke;
pthread_t thread;
pthread_create(&thread, nullptr, &EventsProcess::time_key_helper, info);
pthread_detach(thread);
} else if(value == 2){/*2:key repeat*/
} else {/*0:key down*/
for (std::vector<KeyEvent *>::iterator iter = mKeyEventVec.begin();
iter != mKeyEventVec.end(); ++iter) {
if ((*iter)->keyCode == key_code && (*iter)->keyState == 1) {
(*iter)->up_ts_us = getSystemTimeUs();
(*iter)->keyState = value; /*key up*/
if ((*iter)->longPress || (*iter)->curlongPress) {
(*iter)->curlongPress = false;
flag = true;
}
break;
}
}
if (key_last_down == key_code) {
register_key = true;
}
key_last_down = -1;
}
pthread_mutex_unlock(&key_queue_mutex);
last_key = key_code;
if (register_key) {
EnqueueKey(key_code, flag);
}
}
void* EventsProcess::time_key_helper(void* cookie) {
key_timer_t* info = (key_timer_t*) cookie;
info->ep->time_key(info);
delete info;
return nullptr;
}
void EventsProcess::time_key(key_timer_t *info) {
int key_code = info->key_code;
int count = info->count;
int keymode = getKeyMode(key_code);
usleep(750000); // 750 ms == "long"
pthread_mutex_lock(&key_queue_mutex);
if (key_last_down == key_code && key_down_count == count) {
if (info->ke) {
info->ke->longPress = true;
if (keymode != 0)
info->ke->curlongPress = true;
}
else {
printf("##recive key but no events##\n");
pthread_mutex_unlock(&key_queue_mutex);
return;
}
}
if (info->ke->longPress && info->ke->curlongPress) {
pthread_mutex_unlock(&key_queue_mutex);
while (key_last_down == key_code && key_down_count == count) {
EnqueueKey(key_code, false);
}
} else {
pthread_mutex_unlock(&key_queue_mutex);
}
}
const char* EventsProcess::getKeyType(int key) {
int i;
for (i = 0; i < num_keys; i++) {
KeyMapItem_t* v = &keys_map[i];
if (v->value == key)
return v->type;
}
return NULL;
}
int EventsProcess::getKeyMode(int key) {
int i;
for (i = 0; i < num_keys; i++) {
KeyMapItem_t* v = &keys_map[i];
if (v->value == key)
return v->mode;
}
return 0;
}
void EventsProcess::load_key_map() {
FILE* fstab = fopen("/etc/gpio_key.kl", "r");
if (fstab != NULL) {
printf("loaded /etc/gpio_key.kl\n");
int alloc = 2;
keys_map = (KeyMapItem_t*)malloc(alloc * sizeof(KeyMapItem_t));
num_keys = 0;
char buffer[1024];
int i;
int value = -1;
while (fgets(buffer, sizeof(buffer)-1, fstab)) {
for (i = 0; buffer[i] && isspace(buffer[i]); ++i);
if (buffer[i] == '\0' || buffer[i] == '#') continue;
char* original = strdup(buffer);
char* type = strtok(original+i, " \t\n");
char* key = strtok(NULL, " \t\n");
char* mode = strtok(NULL, " \t\n");
value = atoi (key);
if (type && (value > 0)) {
while (num_keys >= alloc) {
alloc *= 2;
keys_map = (KeyMapItem_t*)realloc(keys_map, alloc*sizeof(KeyMapItem_t));
}
keys_map[num_keys].type = strdup(type);
keys_map[num_keys].value = value;
if (!mode)
keys_map[num_keys].mode = 0;
else
keys_map[num_keys].mode = atoi (mode);
++num_keys;
} else {
printf("error: skipping malformed keyboard.lk line: %s\n", original);
}
free(original);
}
fclose(fstab);
printf("keyboard key map table:\n");
int j;
for (j = 0; j < num_keys; ++j) {
KeyMapItem_t* v = &keys_map[j];
printf(" %d type:%s value:%d mode:%d\n", j, v->type, v->value, v->mode);
}
free(keys_map);
} else {
printf("error: failed to open /etc/gpio_key.kl, use default map\n");
num_keys = DEFAULT_KEY_NUM;
keys_map = g_default_keymap;
printf("keyboard key map table:\n");
int i;
for (i = 0; i < num_keys; ++i) {
KeyMapItem_t* v = &keys_map[i];
printf(" %d type:%s value:%d mode:%d\n", i, v->type, v->value, v->mode);
}
}
}
int EventsProcess::getMapKey(int key) {
int i;
for (i = 0; i < num_keys; i++) {
KeyMapItem_t* v = &keys_map[i];
if (v->value == key)
return v->value;
}
return -1;
}
long checkEventTime(struct timeval *before, struct timeval *later) {
time_t before_sec = before->tv_sec;
suseconds_t before_usec = before->tv_usec;
time_t later_sec = later->tv_sec;
suseconds_t later_usec = later->tv_usec;
long sec_diff = (later_sec - before_sec) * 1000;
if (sec_diff < 0)
return true;
long ret = sec_diff + (later_usec - before_usec) / 1000;
if (ret >= KEY_EVENT_TIME_INTERVAL)
return true;
return false;
}
void EventsProcess::EnqueueKey(int key_code, bool flag) {
struct timeval now;
gettimeofday(&now, nullptr);
pthread_mutex_lock(&key_queue_mutex);
const int queue_max = sizeof(key_queue) / sizeof(key_queue[0]);
if (key_queue_len < queue_max) {
if (last_key != key_code || checkEventTime(&last_queue_time, &now) || flag) {
key_queue[key_queue_len++] = key_code;
last_queue_time = now;
}
pthread_cond_signal(&key_queue_cond);
}
pthread_mutex_unlock(&key_queue_mutex);
}
#ifdef FILTER_POWERKEY
bool filter_power_key(const char* key_type)
{
#define FILTER_KEY_TIME 150 //ms
static long last_time_ms = -1;
if (!strcmp(key_type, "power")) {
struct timeval now_time;
gettimeofday(&now_time, nullptr);
long now_time_ms = now_time.tv_sec*1000 + now_time.tv_usec/1000;
if (last_time_ms == -1 || (now_time_ms - last_time_ms) >= FILTER_KEY_TIME) {
last_time_ms = now_time_ms;
return true;
} else {
return false;
}
} else {
return true;
}
#undef FILTER_KEY_TIME
}
#endif
void EventsProcess::WaitKey() {
bool cur_longpress = false;
bool execute = false;
pthread_mutex_lock(&key_queue_mutex);
do {
struct timeval now;
struct timespec timeout;
gettimeofday(&now, nullptr);
timeout.tv_sec = now.tv_sec;
timeout.tv_nsec = now.tv_usec * 1000;
timeout.tv_sec += WAIT_KEY_TIMEOUT_SEC;
int rc = 0;
while (key_queue_len == 0 && rc != ETIMEDOUT) {
rc = pthread_cond_timedwait(&key_queue_cond, &key_queue_mutex, &timeout);
}
} while (key_queue_len == 0);
int key = -1;
KeyEvent *keyEvent = nullptr;
char* event_str;
char buf[100];
if (key_queue_len > 0) {
key = key_queue[0];
memmove(&key_queue[0], &key_queue[1], sizeof(int) * --key_queue_len);
}
std::vector<KeyEvent *>::iterator iter = mKeyEventVec.begin();
//should remove zombie key down long long time?
for (; iter != mKeyEventVec.end();) {
if ((*iter)->keyCode == key && ((*iter)->keyState == 0 || (*iter)->curlongPress)) {
keyEvent = *iter;
if (keyEvent->curlongPress)
cur_longpress = true;
else
iter = mKeyEventVec.erase(iter);
break;
} else {
++iter;
}
}
pthread_mutex_unlock(&key_queue_mutex);
const char* keyType=getKeyType(key);
int keymode=getKeyMode(key);
int res;
memset(buf,'\0',sizeof(buf));
if (keyType != NULL) {
if (keyEvent && cur_longpress && keyEvent->longPress && keymode != 0) {
sprintf(buf,"%s %s%s","/etc/adckey/adckey_function.sh","curlongpress",keyType);
execute = true;
} else if (keyEvent && !cur_longpress && keyEvent->longPress && keymode != 1) {
uint64_t duration = 0;
if (keyEvent->up_ts_us < keyEvent->down_ts_us) {
duration = UINT64_MAX - keyEvent->down_ts_us + keyEvent->up_ts_us;
duration /= 1000LL;
} else {
duration = (keyEvent->up_ts_us - keyEvent->down_ts_us)/1000LL;
}
sprintf(buf,"%s %s%s %llu","/etc/adckey/adckey_function.sh","longpress",keyType, duration);
execute = true;
} else if (!(keyEvent && keyEvent->longPress)) {
sprintf(buf,"%s %s","/etc/adckey/adckey_function.sh",keyType);
#ifdef FILTER_POWERKEY
execute = filter_power_key(keyType);
#else
execute = true;
#endif
}
if (execute) {
//printf("input_eventd: run %s\n", buf);
res=system(buf);
if (res != 0) printf("run %s exception!!!\n",buf);
}
}
//release
if (!cur_longpress)
delete keyEvent;
}