Files
MeowOS-For-R3P2/patch_v2/meow_launcherd/keys.c
T
MeowOS e6f0b665e3 refactor(launcher): 拆分 meow_launcherd.c(9778行)→meow_launcherd/ 多文件(agent-149)
- 14 模块 .c + meow_launcher_internal.h(642): util/font_theme/fb_compositor/settings_page/power_menu/notif_center/app_launcher/main_menu/audio/backlight/net/keys/about/statusbar; meow_launcherd.c 已删
- 按行逐字搬移(0-diff), 118函数提升非static+47组extern(内部头), #if0退役区不编入(源码留.pre_split.bak)
- 关于本机小改: 作者 AskaEth/17 + info/item[13]防越界 + s_dd_modal 超高滚动(clamp/触摸滚动/音量键跟随/裁剪, 仅超高启用)
- build_launcher.sh 编译列表→模块; 文档/注释引用 meow_launcherd.c→模块/目录
- 编译0warning/-Wall -Wextra告警集与原文一致(77条无新增)/qemu-mipsel冒烟一致(--scan/--sysdump); launcher=c0799357(505KB; md5因多文件重编译与原文异,非回归依据)
- 备份 meow_launcherd.c.pre_split.bak/meow_launcherd.pre_split.bak; M2.69(0.7.64)已推卡并用户验证OK
2026-08-30 21:38:30 +08:00

205 lines
7.6 KiB
C

/* keys.c — MeowOS launcher 拆分模块(LAUNCHER_SPLIT_PLAN 拆分)。*/
/* 本文件由拆分工具从 meow_launcherd.c 按职责搬移;逻辑与原文 0-diff(仅 static 可见性按跨模块需求调整)。*/
#include "meow_launcher_internal.h"
int kd_tick(struct kd_state *s, int raw)
{
unsigned long long now = now_ms();
int ev = KD_NONE;
if (raw != s->raw) {
if (s->raw == 0 && raw != 0) { /* 任何跳变都重记稳定窗口(含原始 raw 变化) */ }
s->raw = raw; s->since = now;
}
int want = s->raw;
if (want != s->stable) {
if (now - s->since >= KEY_DEBOUNCE_MS) {
s->stable = want;
if (s->stable && !s->down) { s->down = 1; s->down_at = now; s->longpressed = 0; ev = KD_DOWN; }
else if (!s->stable && s->down) { s->down = 0; ev = KD_UP; }
}
}
if (s->down && !s->longpressed && now - s->down_at >= CLICK_MS) s->longpressed = 1;
return ev;
}
/* Unblank the panel AFTER the player is frozen: with the player SIGSTOPped
* it can no longer re-blank, so the menu (drawn on fb0) stays visible even
* when the menu opened while the player's screen timeout had blanked the
* panel. The blank state still belongs to the player's state machine — on
* session end restore_backlight() re-blanks when menu_opened_blank, so the
* player resumes into a consistent (blanked) state. */
void unblank_panel(void)
{
int fbfd = open(FB_DEV, O_RDWR);
if (fbfd >= 0) { ioctl(fbfd, FBIOBLANK, 0); close(fbfd); }
logmsg("panel unblanked (player frozen)");
}
void meow_panel_off(void)
{
meow_saved_brightness = read_brightness();
if (meow_saved_brightness <= 0) meow_saved_brightness = 60;
write_brightness(0);
if (screen_off_mode == 0) {
/* panel:面板下电 + FBIOPBLANK(4)(同时挂起 goodix 触摸,无误触) */
int f = open(FB_DEV, O_RDWR);
if (f >= 0) { ioctl(f, FBIOBLANK, 4); close(f); }
} else {
/* black:仅背光 0 全黑(面板仍上电,触摸可唤醒) */
}
meow_screen_on = 0;
logmsg("meow panel OFF (mode=%s brightness 0%s)",
screen_off_mode ? "black" : "panel",
screen_off_mode ? "" : " + blank 4");
}
void meow_panel_on(void)
{
int f = open(FB_DEV, O_RDWR);
if (f >= 0) { ioctl(f, FBIOBLANK, 0); close(f); }
write_brightness(meow_saved_brightness > 0 ? meow_saved_brightness : 60);
meow_screen_on = 1;
/* M2.8 Bug 3-residual:亮屏必须用 fb_pan_buf0_force 无条件重发 pan。fb_norm_buf0 在
* 缓存 fb_active_yoffset==0 时提前返回,而 FBIOBLANK(4)->(0) 后 LCDC 扫描地址可能已复位
* 到非 buffer0 / 失效位置,缓存仍是 0 导致真正的 re-pan 从未发出 —— M2.7 只加 fb_norm_buf0
* 仍黑屏的原因。主界面都画在 buffer0(mmap 偏移 0),此处强制 re-pan 保证唤醒后落在 buffer0。
* 当前界面内容的重绘由调用方(run_menu 醒屏分支)经 meow_repaint_surface 完成。 */
fb_pan_buf0_force();
logmsg("meow panel ON (blank 0 + brightness %d)", meow_saved_brightness);
}
void meow_toggle_panel(void) { if (meow_screen_on) meow_panel_off(); else meow_panel_on(); }
int kp_open(struct keypoll *kp, const char *dev)
{
memset(kp, 0, sizeof *kp);
kp->fd = open(dev, O_RDONLY | O_NONBLOCK);
if (kp->fd < 0) { logmsg("open %s: %s", dev, strerror(errno)); return -1; }
if (ioctl(kp->fd, EVIOCGKEY(sizeof kp->cur), kp->cur) < 0) {
logmsg("EVIOCGKEY %s: %s", dev, strerror(errno));
close(kp->fd); return -1;
}
memcpy(kp->prev, kp->cur, sizeof kp->cur);
kp->ok = 1;
logmsg("keypoll %s ready", dev);
return 0;
}
/* 关闭 keypoll(设置页/下拉框等自开设备用;幂等,ok=0 时不动) */
void kp_close(struct keypoll *kp)
{
if (kp->ok && kp->fd >= 0) close(kp->fd);
kp->ok = 0;
}
/* Poll device key state; call cb(code, is_down) for each edge.
* Returns 1 if any edge. */
int kp_poll(struct keypoll *kp, int (*cb)(int code, int down, void *ctx),
void *ctx)
{
if (!kp->ok) return 0;
if (ioctl(kp->fd, EVIOCGKEY(sizeof kp->cur), kp->cur) < 0) return 0;
int changed = 0;
for (int w = 0; w < KEYBUF_WORDS; w++) {
if (kp->cur[w] == kp->prev[w]) continue;
for (int b = 0; b < 32; b++) {
int c = (kp->cur[w] >> b) & 1;
int p = (kp->prev[w] >> b) & 1;
if (c != p) {
int code = w * 32 + b;
changed = 1;
if (cb) cb(code, c, ctx);
}
}
kp->prev[w] = kp->cur[w];
}
return changed;
}
int kp_is_down(const struct keypoll *k, int code)
{
return (k->cur[code / 32] >> (code % 32)) & 1;
}
int hotkey_mode = HOTKEY_MODE_PWRVOL;
int seq_codes[MAX_SEQ_LEN];
int seq_len = 0;
int seq_gap_ms = 600;
static int key_name_code(const char *n)
{
if (!strcmp(n, "volup")) return KEY_VOLUMEUP;
if (!strcmp(n, "voldown")) return KEY_VOLUMEDOWN;
if (!strcmp(n, "play")) return KEY_PLAYPAUSE;
if (!strcmp(n, "next")) return KEY_NEXT;
if (!strcmp(n, "previous")) return KEY_PREVIOUSSONG;
if (!strcmp(n, "power")) return KEY_POWER;
return -1;
}
void load_config(void)
{
menu_bg = 0x000000;
hotkey_mode = HOTKEY_MODE_PWRVOL; /* default: hold power + VOL_DOWN tap */
seq_len = 0;
seq_gap_ms = 600;
char path[256];
snprintf(path, sizeof path, "%s/meow.conf", MEOWAPPS);
FILE *f = fopen(path, "r");
if (f) {
char buf[128];
while (fgets(buf, sizeof buf, f)) {
if (!strncmp(buf, "bg_color=", 9)) {
unsigned int v;
if (sscanf(buf + 9, "%x", &v) == 1) menu_bg = v & 0xFFFFFF;
} else if (!strncmp(buf, "hotkey=", 7)) {
char *p = buf + 7;
while (*p == ' ' || *p == '\t') p++;
if (!strncmp(p, "seq", 3)) hotkey_mode = HOTKEY_MODE_SEQ;
else hotkey_mode = HOTKEY_MODE_PWRVOL;
} else if (!strncmp(buf, "hotkey_seq=", 11)) {
char *p = buf + 11;
seq_len = 0;
/* BUGFIX: the outer loop must consume the EOL — with
* *p staying at '\n' the empty-name branch never advanced p
* and the daemon spun forever (found on-device: a hotkey_seq
* line wedged load_config in a busy loop). */
while (*p && *p != '\n' && *p != '\r' && seq_len < MAX_SEQ_LEN) {
char name[16];
int k = 0;
while (*p && *p != ',' && *p != '\n' && *p != '\r' && k < 15)
name[k++] = *p++;
name[k] = 0;
if (k >= 15) /* malformed long name: skip to separator/EOL */
while (*p && *p != ',' && *p != '\n' && *p != '\r') p++;
if (*p == ',') p++;
int c = key_name_code(name);
if (c > 0) seq_codes[seq_len++] = c;
}
} else if (!strncmp(buf, "hotkey_seq_gap=", 15)) {
int g = atoi(buf + 15);
if (g >= 200 && g <= 2000) seq_gap_ms = g;
}
}
fclose(f);
}
if (seq_len == 0) { seq_codes[0] = KEY_VOLUMEUP; seq_len = 3; } /* seq fallback volup x3 */
if (hotkey_mode == HOTKEY_MODE_PWRVOL)
logmsg("config: bg_color=%06x hotkey=power_voldown (window %d-%dms)",
menu_bg, HK_PWRWIN_MIN, HK_PWRWIN_MAX);
else
logmsg("config: bg_color=%06x hotkey=seq (%d taps of code %d gap=%dms)",
menu_bg, seq_len, seq_codes[0], seq_gap_ms);
}