c/tty/pcscreen.c · 12592 字节 · 下载原文
/* pcscreen.c —— **电脑屏窗口**(第三种窗口)的最小体检程序。
* pcscreen.c — minimal self-check program for the **PC screen window** (the third window type).
*
* 用途:真机上验 `ui_win_open_pc`(`#582`)那三件与图形窗口不同的行为。
* Purpose: verify on a real device the three behaviors of `ui_win_open_pc` (`#582`) that differ from a graphics window.
* 它刻意**只画固定分辨率的东西** —— 屏幕上看到的应该是一整幅 640×480 的框,
* It deliberately draws **only fixed-resolution things** — what you see should be a full 640x480 frame,
* 等比缩放贴进画布、**四边都在**(不是被裁掉一截)。
* scaled proportionally into the canvas, with **all four edges present** (not cropped).
*
* 该看到什么:
* What you should see:
* ① 一圈边框正好贴着窗口**四边**(分辨率没被换过 / 没被裁);
* 1) A border exactly flush with the window's **four edges** (resolution not swapped / not cropped);
* ② 格线是 40 点一格 —— 数得出 16×12 格(不是自适应后的别的数字);
* 2) Grid lines every 40 points — you can count 16x12 cells (not some other adaptive number);
* ③ 底部两行:最后按下的键、以及鼠标位置;
* 3) Two bottom lines: last key pressed, and mouse position;
* ④ **触摸**:手指按在哪儿,十字准星就画在哪儿(坐标是 640×480 那套);
* 4) **Touch**: the crosshair is drawn wherever the finger lands (coordinates are the 640x480 set);
* ⑤ **没有手柄区**(底部那排方向键/A/B 不该出现);
* 5) **No gamepad area** (the bottom row of D-pad/A/B buttons should not appear);
* ⑥ 按 Esc 或点窗口的返回箭头退出。
* 6) Press Esc or tap the window's back arrow to exit.
*
* ⚠ 它**不是**给用户用的示例,是**体检程序** —— 与 `draw_prims.c` 同一性质:
* ⚠ It is **not** a user-facing example but a **self-check program** — same nature as `draw_prims.c`:
* 程序要的就是"固定格距、固定分辨率",好让截图能逐项核对。
* The program wants "fixed grid spacing, fixed resolution" so screenshots can be checked item by item.
*
* 坐标说明:窗口宽高就是程序的坐标空间(这里 640×480,取 PC 上最眼熟那一档)。
* Coordinates: the window width/height is the program's coordinate space (here 640x480, the most familiar PC tier).
* 宿主默认等比缩放让你看全貌,双指可以放大细看 —— 那只是**显示**,
* The host scales proportionally by default so you see the whole picture, and two fingers can zoom in — that is only **display**,
* 程序这边的坐标一个数都不会变。
* not a single coordinate on the program side changes.
*/
#include <vml_ui.h>
#define PC_W 640
#define PC_H 480
#define GRID 40
static int msg[4];
static int lastKey; /* 最后按下的键码 */
/* Last key code pressed */
static int mx; /* 鼠标(触摸)位置 */
/* Mouse (touch) position */
static int my;
static int clicked; /* 鼠标按下的次数 —— 用来区分"只移动"和"真的点了" */
/* Number of mouse presses — distinguishes "just moved" from "actually clicked" */
static int touchSeen; /* **收到过几次触摸消息** —— 电脑屏窗口里这个数**必须恒为 0** */
/* **How many touch messages arrived** — in a PC screen window this must **always be 0** */
static int lang; /* 界面语言:开局查一次(ui_scr_get_language 是 syscall,别每帧调) */
/* UI language: queried once at start (ui_scr_get_language is a syscall, do not call it every frame) */
/* 一个 32 位色:0xAARRGGBB */
/* A 32-bit color: 0xAARRGGBB */
#define RGB_BG 0xFF101820
#define RGB_LINE 0xFF2A3A4A
#define RGB_EDGE 0xFF40C0FF
#define RGB_TEXT 0xFFE0E0E0
#define RGB_DIM 0xFF8090A0
#define RGB_MARK 0xFFFF4040
static void put_int(char* buf, int v)
{
/* 极简十进制:避免依赖 printf 的格式化路径(当年记的是"那套会崩",见宿主接口文档)。
Minimal decimal conversion: avoids printf's formatting path (back then it was recorded as "that path crashes", see the host interface doc).
⚠ 2026-10-04 复验:**桌面脚手架**那条早已修好(`printf("%s %d %f %x %c", …)` 实测正确);
⚠ Re-checked 2026-10-04: the **desktop-scaffold** crash was fixed long ago (`printf("%s %d %f %x %c", …)` measured correct);
手机端这条**本轮未验**(需要真机)⇒ 注释原样保留,手写 put_int 也保留(能跑就别动)。
the mobile side was **not verified this round** (a real device is needed) ⇒ the note stays as-is and so does the hand-written put_int (if it runs, do not touch it).
返回写在 buf 里的字符串。
Returns the string written into buf. */
char t[12];
int n = 0, i = 0, neg = 0;
if (v < 0) { neg = 1; v = -v; }
if (v == 0) { t[n] = '0'; n = 1; }
while (v > 0 && n < 11) { t[n] = (char)('0' + v % 10); n = n + 1; v = v / 10; }
if (neg) { buf[i] = '-'; i = i + 1; }
while (n > 0) { n = n - 1; buf[i] = t[n]; i = i + 1; }
buf[i] = 0;
}
static void draw_all(void)
{
int x, y;
char buf[64];
int i;
ui_2d_clear(RGB_BG);
/* ① 格线:每 40 点一条 —— 数格子就能看出分辨率有没有被换过 */
/* 1) Grid lines: one every 40 points — counting cells shows whether the resolution was swapped */
for (x = GRID; x < PC_W; x = x + GRID)
ui_2d_line(x, 0, x, PC_H, RGB_LINE, 1);
for (y = GRID; y < PC_H; y = y + GRID)
ui_2d_line(0, y, PC_W, y, RGB_LINE, 1);
/* ② 四边贴边(空心矩形,线宽 3)—— 四边都在才说明没被裁 */
/* 2) Flush on all four edges (hollow rectangle, line width 3) — all four present means not cropped */
ui_2d_rect(2, 2, PC_W - 4, PC_H - 4, RGB_EDGE, 0, 3, 0);
/* ③ 标题 */
/* 3) Title */
ui_2d_text(20, 10, lang == 0 ? "电脑屏窗口 640x480" : "PC screen window 640x480",
RGB_EDGE, 24, VML_ANCHOR_LEFT);
/* ④ 底部两行:最后按键 + 鼠标位置 */
/* 4) Two bottom lines: last key + mouse position */
buf[0] = 'K'; buf[1] = 'E'; buf[2] = 'Y'; buf[3] = ' ';
i = 4;
{
char nb[12];
int k;
put_int(nb, lastKey);
for (k = 0; nb[k] != 0; k = k + 1) { buf[i] = nb[k]; i = i + 1; }
}
buf[i] = 0;
/* 这一行的末尾会再补上 TOUCH 计数(见下面那段) */
/* The TOUCH counter is appended at the end of this line (see the block below) */
ui_2d_text(20, PC_H - 64, buf, RGB_TEXT, 20, VML_ANCHOR_LEFT);
buf[0] = 'M'; buf[1] = 'O'; buf[2] = 'U'; buf[3] = 'S'; buf[4] = 'E'; buf[5] = ' ';
i = 6;
{
char nb[12];
int k;
put_int(nb, mx);
for (k = 0; nb[k] != 0; k = k + 1) { buf[i] = nb[k]; i = i + 1; }
buf[i] = ','; i = i + 1;
put_int(nb, my);
for (k = 0; nb[k] != 0; k = k + 1) { buf[i] = nb[k]; i = i + 1; }
buf[i] = ' '; i = i + 1;
buf[i] = '#'; i = i + 1;
put_int(nb, clicked);
for (k = 0; nb[k] != 0; k = k + 1) { buf[i] = nb[k]; i = i + 1; }
}
/* ⚠ 这一行是**"抑制触摸"的判据**:电脑屏窗口只该发鼠标消息,
⚠ This line is the **"touch suppression" criterion**: a PC screen window should only send mouse messages,
触摸消息一条都不该来。这里若数出非 0,说明抑制没生效 ——
not a single touch message should arrive. A non-zero count here means suppression is not working —
而画面上看不出任何异常(准星照旧跟着走),只有这一行会变。
and nothing looks wrong on screen (the crosshair still follows), only this line changes. */
buf[i] = ' '; i = i + 1;
buf[i] = 'T'; i = i + 1;
buf[i] = 'O'; i = i + 1;
buf[i] = 'U'; i = i + 1;
buf[i] = 'C'; i = i + 1;
buf[i] = 'H'; i = i + 1;
buf[i] = ' '; i = i + 1;
{
char nb[12];
int k;
put_int(nb, touchSeen);
for (k = 0; nb[k] != 0; k = k + 1) { buf[i] = nb[k]; i = i + 1; }
}
buf[i] = 0;
ui_2d_text(20, PC_H - 36, buf, RGB_DIM, 20, VML_ANCHOR_LEFT);
/* ⚠ **报警块**:只在"收到过触摸消息"时亮(右上角一块实心红)。
⚠ **Alarm block**: lights up only when "touch messages were received" (a solid red square in the top-right).
电脑屏窗口里它**永远不该出现**。
In a PC screen window it **should never appear**.
为什么用色块而不是文字:画布上的文字**读不出**(不是 UI 节点),
Why a color block instead of text: canvas text **cannot be read back** (it is not a UI node),
而验收脚本要能**逐像素**判 —— 色块一行断言就够,不必上 OCR。
and the acceptance script must judge **pixel by pixel** — a color block needs one assertion line, no OCR. */
if (touchSeen > 0)
ui_2d_rect(PC_W - 44, 8, 36, 20, RGB_MARK, 1, 0, 0);
/* ⑤ 十字准星:触摸落在哪儿就画在哪儿(这就是"触摸当鼠标"的判据) */
/* 5) Crosshair: drawn wherever the touch lands (this is the "touch acts as mouse" criterion) */
if (mx > 0 || my > 0)
{
ui_2d_line(mx - 16, my, mx + 16, my, RGB_MARK, 2);
ui_2d_line(mx, my - 16, mx, my + 16, RGB_MARK, 2);
ui_2d_circle(mx, my, 8, RGB_MARK, 0, 2);
}
ui_2d_present();
}
int main()
{
int h;
/* 开电脑屏窗口:固定 640×480、不锁方向、要屏幕键盘。
Open a PC screen window: fixed 640x480, orientation not locked, on-screen keyboard wanted.
⚠ 第 5 个参数是**键盘**(VML_WIN_NEED_KEYBOARD),不是手柄 ——
⚠ The 5th parameter is the **keyboard** (VML_WIN_NEED_KEYBOARD), not the gamepad —
位置与 ui_win_open_ex 的第 5 个参数对称,但语义不同。
it sits in the same position as the 5th parameter of ui_win_open_ex, but means something different. */
lang = ui_scr_get_language();
h = ui_win_open_pc(lang == 0 ? "电脑屏体检" : "PC screen self-check", PC_W, PC_H,
VML_WIN_ROTATABLE, VML_WIN_NEED_KEYBOARD);
if (h < 0) return 1;
ui_msg_clear(); /* 丢掉开窗之前积压的消息 */
/* Drop messages queued up before the window was opened */
draw_all();
while (ui_win_is_closed() == 0)
{
int t = ui_msg_wait(msg, 0); /* timeout 0 = **无限等**(事件驱动,省电) */
/* timeout 0 = **wait forever** (event driven, saves power) */
if (t == 0) continue;
if (t == VML_MSG_WINDOWCLOSE) break;
/* 触摸**在这里应该是鼠标消息**(电脑屏窗口不发触摸消息)——
Touch **should be a mouse message here** (a PC screen window does not send touch messages) —
若下面这两支一次都不进,说明"抑制触摸"那条没生效。
if neither of the two branches below is ever entered, that "touch suppression" is not working. */
if (t == VML_MSG_MOUSEDOWN) { clicked = clicked + 1; mx = msg[1]; my = msg[2]; draw_all(); }
else if (t == VML_MSG_MOUSEMOVE) { mx = msg[1]; my = msg[2]; draw_all(); }
/* 触摸消息:**电脑屏窗口里不该出现**(见 touchSeen 的说明)。
Touch messages: **should not appear in a PC screen window** (see the note on touchSeen).
计数而不是忽略,是为了让"抑制失效"这件事**看得见**。
Counting instead of ignoring makes "suppression failed" **visible**. */
else if (t == VML_MSG_TOUCHDOWN || t == VML_MSG_TOUCHMOVE || t == VML_MSG_TOUCHUP)
{
touchSeen = touchSeen + 1;
draw_all();
}
else if (t == VML_MSG_KEYDOWN)
{
lastKey = msg[1];
if (lastKey == VML_KEY_ESCAPE) break;
draw_all();
}
}
ui_win_close();
return 0;
}