Files
MeowOS-For-R3P2/patch_v2/meow_launcherd/keys.c
T
AskaEth 3d70a3dd2c feat: M6.10–M6.19 批量收编 + M6.19 推卡验收
- M7 launcher 重写 5 期(虚拟化宫格/meow_theme 单一权威/横幅动画/自定义 PIN 键盘)
- OOM 通用化(cachegov 上收 SDK)、自动切歌根治、meowpanel jv_free 泄漏修复、Hello 滚动卡顿修复
- ncm 歌词 UI / 媒体通知封面 / 封面分辨率 640
- 5 bug 修复:ncm 后台化 UI 叠层+点击穿透、再进 ncm 桌面叠层、播放页新旧 UI 叠层抢刷脏区(meow_ui_gfx 恢复边沿整帧重画)、PIN 亮屏亮度跳(keys.c meow_panel_on 按 settings_brightness_clamped 恢复)、通知中心封面显歌单封面(cover.c save_cover_raw 加 is_song + 命中块守卫)
- 四 App 统一重链新 meow_ui.a 51caee4a;M6.19=0.8.19 固件 2d2331f2 推卡自刷验收全绿
2026-09-03 12:16:01 +08:00

215 lines
8.3 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* 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, "meow_panel_off");
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); }
/* 亮度恢复以**用户设置**为准,而非 meow_saved_brightness(可能过期)。
* watchdog 独立息屏(wd_panel_off 直接 write_brightness(0),见 meow_watchdog.c)**不会**
* 更新本进程 meow_saved_brightness——若用其恢复会回错值(真机「PIN 亮屏亮度跳高」,
* 2026-09-03)。settings 已从盘上读到→按 display.brightness(clamp)恢复;未读到(早启动)
* →回退 meow_saved_brightness 现值(保持旧行为,防开机竞态)。 */
if (meow_settings_loaded()) {
int b = meow_settings_brightness_clamped();
if (b > 0) { write_brightness(b, "meow_panel_on"); meow_saved_brightness = b; }
} else {
write_brightness(meow_saved_brightness > 0 ? meow_saved_brightness : 60, "meow_panel_on");
}
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);
}