127 lines
4.8 KiB
C
127 lines
4.8 KiB
C
/* mp_key.c — 远程控制域:按键注入(写 /dev/input/event* EV_KEY,物理键红线内)。 */
|
||
#include "mp.h"
|
||
|
||
#define PWR_KEYDEV "/dev/input/event0"
|
||
#define ADC_KEYDEV "/dev/input/event2"
|
||
|
||
|
||
int keycode_to_device(int code, const char **dev)
|
||
{
|
||
switch (code) {
|
||
case KEY_POWER: *dev = PWR_KEYDEV; return KEY_POWER;
|
||
case KEY_PREVIOUSSONG: *dev = PWR_KEYDEV; return KEY_PREVIOUSSONG;
|
||
case KEY_VOLUMEUP: *dev = ADC_KEYDEV; return KEY_VOLUMEUP;
|
||
case KEY_VOLUMEDOWN: *dev = ADC_KEYDEV; return KEY_VOLUMEDOWN;
|
||
case KEY_NEXTSONG: *dev = ADC_KEYDEV; return KEY_NEXTSONG;
|
||
case KEY_PLAYPAUSE: *dev = ADC_KEYDEV; return KEY_PLAYPAUSE;
|
||
default: return -1;
|
||
}
|
||
}
|
||
|
||
int inject_key_event(const char *dev, int code, int down)
|
||
{
|
||
int fd = open(dev, O_WRONLY | O_NONBLOCK);
|
||
if (fd < 0) return -1;
|
||
struct input_event ev;
|
||
memset(&ev, 0, sizeof ev);
|
||
ev.type = EV_KEY;
|
||
ev.code = code;
|
||
ev.value = down ? 1 : 0;
|
||
int ok = (write(fd, &ev, sizeof ev) == (ssize_t)sizeof ev);
|
||
if (ok) {
|
||
memset(&ev, 0, sizeof ev);
|
||
ev.type = EV_SYN;
|
||
ev.code = SYN_REPORT;
|
||
ev.value = 0;
|
||
ok = (write(fd, &ev, sizeof ev) == (ssize_t)sizeof ev);
|
||
}
|
||
close(fd);
|
||
return ok ? 0 : -1;
|
||
}
|
||
|
||
int inject_key_release(int code, int press_ms)
|
||
{
|
||
const char *dev = NULL;
|
||
int kc = keycode_to_device(code, &dev);
|
||
if (kc < 0) return -1;
|
||
int release_ms = press_ms > 0 ? press_ms : 0;
|
||
if (inject_key_event(dev, code, 1) < 0) return -1;
|
||
if (release_ms > 0) usleep((useconds_t)release_ms * 1000);
|
||
else usleep(80 * 1000);
|
||
if (inject_key_event(dev, code, 0) < 0) return -1;
|
||
return 0;
|
||
}
|
||
|
||
int api_key_single(int sock, int code, const req_t *r)
|
||
{
|
||
int press_ms = 0;
|
||
char pressbuf[16] = "tap";
|
||
const char *press = pressbuf;
|
||
if (r->body && r->body[0]) {
|
||
jv_t *root = jv_parse(r->body, (int)r->body_len);
|
||
if (root) {
|
||
jv_t *p = jv_obj_get(root, "press");
|
||
if (p && p->type == J_STR) snprintf(pressbuf, sizeof pressbuf, "%s", p->str);
|
||
jv_t *m = jv_obj_get(root, "ms");
|
||
if (m && m->type == J_NUM) press_ms = (int)m->inum;
|
||
jv_free(root);
|
||
}
|
||
}
|
||
if (!strcmp(press, "hold"))
|
||
return send_err(sock, 501, "NOT_IMPLEMENTED", "hold 持续注入需常驻通道(阶段 D),后端未实现");
|
||
if (strcmp(press, "tap") && strcmp(press, "long"))
|
||
return send_err(sock, 400, "BAD_REQUEST", "press 非法");
|
||
if (press_ms <= 0) {
|
||
if (!strcmp(press, "long")) press_ms = 3000;
|
||
}
|
||
/* 物理键红线:禁止映射 返回(158)/主页(172)/确认/exit(APPS.md)。 */
|
||
if (code == 158 || code == 172 || code == 32 || code == 28 || code == 96)
|
||
return send_err(sock, 403, "FORBIDDEN", "该键码(返回/主页/确认)按物理键红线禁止映射");
|
||
const char *tmpdev = NULL;
|
||
int dispatchable = (keycode_to_device(code, &tmpdev) >= 0);
|
||
if (!dispatchable)
|
||
return send_err(sock, 422, "UNSUPPORTED", "不支持的键码(仅音量/电源/播放/上下曲)");
|
||
if (inject_key_release(code, press_ms) < 0)
|
||
return send_err(sock, 500, "INTERNAL", "按键注入失败(无法打开输入设备)");
|
||
sbuf_t s = {0};
|
||
sA(&s, "{\"code\":%d,\"press\":\"%s\",\"dispatched\":true}", code, press);
|
||
int ret = send_json(sock, 200, s.b ? s.b : "");
|
||
sbuf_free(&s);
|
||
return ret;
|
||
}
|
||
|
||
int api_key_batch(int sock, const req_t *r)
|
||
{
|
||
if (!r->body || !r->body[0]) return send_err(sock, 400, "BAD_REQUEST", "缺少 body");
|
||
jv_t *root = jv_parse(r->body, (int)r->body_len);
|
||
if (!root) return send_err(sock, 400, "BAD_REQUEST", "body 非合法 JSON");
|
||
jv_t *keys = jv_obj_get(root, "keys");
|
||
if (!keys || keys->type != J_ARR) { jv_free(root); return send_err(sock, 400, "BAD_REQUEST", "缺 keys 数组"); }
|
||
sbuf_t s = {0};
|
||
int first = 1;
|
||
for (const jv_t *k = keys->child; k; k = k->next) {
|
||
if (k->type != J_OBJ) continue;
|
||
jv_t *c = jv_obj_get(k, "code");
|
||
jv_t *p = jv_obj_get(k, "press");
|
||
jv_t *m = jv_obj_get(k, "ms");
|
||
if (!c || c->type != J_NUM) continue;
|
||
int code = (int)c->inum;
|
||
if (code == 158 || code == 172) continue; /* 红线跳过 */
|
||
int press_ms = (m && m->type == J_NUM) ? (int)m->inum : 0;
|
||
if (p && p->type == J_STR && !strcmp(p->str, "long") && press_ms <= 0) press_ms = 3000;
|
||
const char *tmpdev = NULL;
|
||
if (keycode_to_device(code, &tmpdev) < 0) continue;
|
||
if (inject_key_release(code, press_ms) < 0) continue;
|
||
if (!first) sA(&s, ",");
|
||
first = 0;
|
||
sA(&s, "%d", code);
|
||
}
|
||
jv_free(root);
|
||
sbuf_t o = {0};
|
||
if (first) sA(&o, "{\"dispatched\":[]}");
|
||
else sA(&o, "{\"dispatched\":[%s]}", s.b);
|
||
int ret = send_json(sock, 200, o.b ? o.b : "");
|
||
sbuf_free(&s); sbuf_free(&o);
|
||
return ret;
|
||
}
|