c/test/wintest.c · 25467 字节 · 下载原文
/* wintest.c —— **开窗参数 / 屏幕信息** 试验台
* wintest.c — a test bench for **window parameters / screen info**
*
* 这个程序只做一件事:把「**你开窗时声明了什么**」与「**宿主实际给了什么**」并排摆出来,
* 让两边对不上的地方**一眼可见**。它是 E141 那条「开窗前问尺寸必然偏」的现场取证工具 ——
* 那条规则的正解是「开窗传 0(尺寸交给宿主)、开完再问」,而**对不对只能量**:
* 本程序把 (0,0,宽,高) 的边框和中心十字**画出来**,边框贴不上画布边就是坐标系不对。
* This program does one thing: put "**what you declared when opening the window**" side by side with
* "**what the host actually gave you**", so a mismatch is **visible at a glance**. It is the on-site
* instrument for E141 ("asking for the size before opening is always off"); the sanctioned workaround is
* "pass 0 when opening (let the host size it), ask afterwards" — and whether that is right **can only be
* measured**: this program **draws** the (0,0,w,h) border and a centre crosshair, so if the border does not
* hug the canvas edge the coordinate space is wrong.
*
* ── 操作(屏幕手柄 / 物理键盘同一套 Win32 虚拟键值)──
* ── Controls (the on-screen gamepad and a physical keyboard use the same Win32 virtual key codes) ──
* G 手柄档(ui_win_open_ex + 要手柄)
* G gamepad chrome (ui_win_open_ex + needs gamepad)
* K 键盘档(ui_win_open_pc + 要屏幕键盘)
* K keyboard chrome (ui_win_open_pc + needs on-screen keyboard)
* N 无 chrome(画布吃满整屏)
* N no chrome (the canvas fills the whole screen)
* L 循环 锁定方向:自动 → 纵向 → 横向 → 自动
* L cycle the orientation lock: auto -> portrait -> landscape -> auto
* Q / 返回箭头 退出
* Q / Back arrow quit
*
* ⚠ **宿主只有三档键盘**:手柄 / 屏幕键盘 / 都不要。没有独立的 `keypad` / `numpad` 档
* —— 键盘档在横屏时是**左右分栏的 PC 键盘**(见 `DrawWindowPage.xaml` 的布局说明)。
* ⚠ **The host has only three keyboard modes**: gamepad / on-screen keyboard / neither. There is no
* separate `keypad` / `numpad` mode — the keyboard mode is a **PC keyboard split left/right in landscape**
* (see the layout notes in `DrawWindowPage.xaml`).
*
* 跑:
* Run:
* vml run examples/c/test/wintest.c
*/
#include <vml_ui.h>
#include <stdlib.h>
/* 键盘档 */
/* Keyboard modes */
#define KB_GAMEPAD 0
#define KB_KEYBOARD 1
#define KB_NONE 2
#define LOGN 5 /* 消息日志留几行 */
/* how many lines of message log to keep */
int g_lang;
int g_kb = KB_GAMEPAD;
int g_lock = VML_LOCK_AUTO;
int g_w;
int g_h;
int g_open_w; /* 开窗后**立刻**问到的(可能还是估算值) */
int g_open_h; /* what was read **immediately** after opening (may still be an estimate) */
int g_had_resize; /* 开窗后第一条 WINDOWRESIZE 到了没有(拿它跟上面那对数比一次) */
/* whether the first WINDOWRESIZE after opening has arrived (compared once against the pair above) */
int g_flash; /* 最近一次「尺寸/方向变了」的时刻(0=还没有) */
/* timestamp of the last "size/orientation changed" (0 = none yet) */
char g_log[LOGN][56];
int g_logn = 0;
char g_txt[192]; /* 一行拼好的文字 */
/* one assembled line of text */
char g_est[3][64]; /* 三行「估算」文字 —— **只在开窗/尺寸变化时重算** */
/* the three "estimate" lines - **recomputed only on open / size change** */
/* 追加字符串(自己数长度;不依赖库里的拼接语义) */
/* Append a string (counting the length myself; not relying on the library's concatenation semantics) */
void cat(char* d, char* s) {
int n = 0;
int i = 0;
while (d[n] != 0) { n = n + 1; }
while (s[i] != 0) { d[n] = s[i]; n = n + 1; i = i + 1; }
d[n] = 0;
}
/* 十进制(含负号) */
/* Decimal (with a minus sign) */
void fmt(int v, char* out) {
char tmp[16];
int n = 0;
int i = 0;
int neg = 0;
if (v < 0) { neg = 1; v = 0 - v; }
if (v == 0) { tmp[n] = '0'; n = n + 1; }
while (v > 0) { tmp[n] = (char)(48 + (v % 10)); n = n + 1; v = v / 10; }
if (neg != 0) { out[i] = '-'; i = i + 1; }
while (n > 0) { n = n - 1; out[i] = tmp[n]; i = i + 1; }
out[i] = 0;
}
/* ── 当前按着的键 ──
* 消息驱动(KEYDOWN 加 / KEYUP 删)+ **每帧拿 `ui_key_is_down` 对一次账**。
* ⚠ 光靠消息会**漏**:手指划出按键范围、系统吃掉 CANCEL 都会让 KEYUP 永远不来
* (`vml_ui.h` 的 `ui_key_is_down` 注释点名了这件事),于是那个键会永远"按着"。
* ── Keys currently held ──
* Message-driven (add on KEYDOWN / remove on KEYUP) plus **a reconcile pass per frame using
* `ui_key_is_down`**. ⚠ Messages alone **leak**: a finger sliding off a button or the system eating
* CANCEL means KEYUP never arrives (the `ui_key_is_down` comment in `vml_ui.h` calls this out), so that
* key would stay "held" forever. */
#define KEYMAX 6
int g_keys[KEYMAX];
int g_keyn = 0;
char g_kbuf[8];
void keys_add(int k) {
int i = 0;
while (i < g_keyn) {
if (g_keys[i] == k) { return; }
i = i + 1;
}
if (g_keyn < KEYMAX) { g_keys[g_keyn] = k; g_keyn = g_keyn + 1; }
}
void keys_del(int k) {
int i = 0;
int j = 0;
while (i < g_keyn) {
if (g_keys[i] != k) { g_keys[j] = g_keys[i]; j = j + 1; }
i = i + 1;
}
g_keyn = j;
}
void keys_reconcile(void) {
int i = 0;
int j = 0;
while (i < g_keyn) {
if (ui_key_is_down(g_keys[i]) != 0) { g_keys[j] = g_keys[i]; j = j + 1; }
i = i + 1;
}
g_keyn = j;
}
/* 键码 → 名字(**键值一律取库里的 `VML_KEY_*`**,不在程序里重写一遍魔法数字;
* 字母/数字用字符字面量表达,那本身就说清了是什么)。
* ⚠ 手柄 **START 没有单独的常量** —— 它走的就是回车(`VML_KEY_ENTER`)。
* Key code -> name (**key values come from the library's `VML_KEY_*`**; no magic numbers rewritten here;
* letters/digits use character literals, which already say what they are).
* ⚠ The gamepad **START has no constant of its own** - it goes through Enter (`VML_KEY_ENTER`). */
char* keyname(int k) {
char b[8];
int i = 0;
if (k == VML_KEY_BACKSPACE) { return "Bksp"; }
if (k == VML_KEY_ENTER) { return "START"; }
if (k == VML_KEY_SELECT) { return "SELECT"; }
if (k == VML_KEY_PAUSE) { return "PAUSE"; }
if (k == VML_KEY_ESCAPE) { return "Esc"; }
if (k == VML_KEY_SPACE) { return "Space"; }
if (k == VML_KEY_LEFT) { return "<-"; }
if (k == VML_KEY_UP) { return "^"; }
if (k == VML_KEY_RIGHT) { return "->"; }
if (k == VML_KEY_DOWN) { return "v"; }
if (k == VML_KEY_PAD_A) { return "A"; }
if (k == VML_KEY_PAD_B) { return "B"; }
if (k == VML_KEY_PAD_X) { return "X"; }
if (k == VML_KEY_PAD_Y) { return "Y"; }
/* 字母 / 数字:本身就是可读的字符,不必再立常量 */
/* letters / digits: they are readable characters already, no constants needed */
if ((k >= '0' && k <= '9') || (k >= 'A' && k <= 'Z') || (k >= 'a' && k <= 'z')) {
g_kbuf[0] = (char)k;
g_kbuf[1] = 0;
return g_kbuf;
}
/* 其余:给个 `#码`,总比什么都不显示强 */
/* everything else: show `#code`, better than showing nothing at all */
g_kbuf[0] = '#';
fmt(k, b);
i = 0;
while (b[i] != 0 && i < 5) { g_kbuf[i + 1] = b[i]; i = i + 1; }
g_kbuf[i + 1] = 0;
return g_kbuf;
}
/* 往日志里加一条(环形,满了顶掉最老的) */
/* Add one entry to the log (ring buffer; when full the oldest is dropped) */
void log_add(char* s) {
int i = 0;
int n = 0;
if (g_logn == LOGN) {
/* 整体上移一行 */
/* shift every row up by one */
i = 1;
while (i < LOGN) {
n = 0;
while (n < 56) { g_log[i - 1][n] = g_log[i][n]; n = n + 1; }
i = i + 1;
}
g_logn = LOGN - 1;
}
i = 0;
while (i < 55 && s[i] != 0) { g_log[g_logn][i] = s[i]; i = i + 1; }
g_log[g_logn][i] = 0;
g_logn = g_logn + 1;
}
/* 重算三行「估算」。
* ⚠ **别每帧问**:`ui_scr_get_w_ex` 在宿主侧每次都要**写一张静态表**(记下"这个数是我们给的",
* 开窗时拿它判断"程序主张的尺寸是不是问了我们要的")。每帧问 6 次 = 每秒 60 次写那张共享表,
* 而它**没有加锁**、主线程开窗时也要读它 —— 纯属自找麻烦,而且这几个数在两次尺寸变化之间根本不变。
* Recompute the three "estimate" lines.
* ⚠ **Do not ask every frame**: `ui_scr_get_w_ex` **writes a static table** host-side on every call
* (it records "this number came from us"; the host reads it at open time to tell whether the size a
* program claims is one it asked us for). Asking 6 times per frame = 60 writes/sec to that shared,
* **unlocked** table which the main thread also reads when opening a window - asking for trouble,
* and these numbers do not change between two size changes anyway. */
void est_refresh(void) {
int i = 0;
while (i < 3) {
int chrome;
int o = 0;
char b[16];
chrome = VML_CHROME_GAMEPAD;
if (i == 1) { chrome = VML_CHROME_KEYBOARD; }
if (i == 2) { chrome = VML_CHROME_NONE; }
g_est[i][0] = 0;
cat(g_est[i], g_lang == 0 ? "估算 " : "est ");
if (i == 0) { cat(g_est[i], g_lang == 0 ? "手柄 " : "pad "); }
if (i == 1) { cat(g_est[i], g_lang == 0 ? "键盘 " : "kbd "); }
if (i == 2) { cat(g_est[i], g_lang == 0 ? "无 " : "none "); }
while (o < 2) {
cat(g_est[i], o == 0 ? (g_lang == 0 ? "竖 " : "P ") : (g_lang == 0 ? "横 " : "L "));
fmt(ui_scr_get_w_ex(o, chrome), b);
cat(g_est[i], b);
cat(g_est[i], "x");
fmt(ui_scr_get_h_ex(o, chrome), b);
cat(g_est[i], b);
cat(g_est[i], " ");
o = o + 1;
}
i = i + 1;
}
}
/* 按当前档位开窗(**可重开** —— 换键盘档、换方向都要重新声明) */
/* Open the window for the current mode (**reopenable** - switching keyboard mode or orientation re-declares it) */
void reopen_window(void) {
char* title;
title = g_lang == 0 ? "开窗试验台" : "WinTest";
if (g_kb == KB_KEYBOARD) {
/* 电脑屏窗口:坐标空间固定(0 会兜底成 640x480),输入是键盘 + 鼠标 */
/* PC-screen window: fixed coordinate space (0 falls back to 640x480), input is keyboard + mouse */
ui_win_open_pc(title, 0, 0, VML_WIN_ROTATABLE, VML_WIN_NEED_KEYBOARD);
} else {
ui_win_open_ex(title, 0, 0, VML_WIN_ROTATABLE,
g_kb == KB_GAMEPAD ? VML_WIN_NEED_GAMEPAD : VML_WIN_NO_GAMEPAD);
}
ui_scr_set_keep_on(1);
/* ⚠ **开窗之后**才问尺寸:这时给的是实测画布;开窗前问的只是估算(E141) */
/* ⚠ Ask for the size **after** opening: this is the measured canvas; before the open it is only an estimate (E141) */
g_w = ui_scr_get_w();
g_h = ui_scr_get_h();
if (g_w <= 0) { g_w = 360; }
if (g_h <= 0) { g_h = 620; }
g_open_w = g_w;
g_open_h = g_h;
g_had_resize = 0;
est_refresh();
}
void draw(void) {
int fs;
int lh;
int i;
int slot;
int n;
int needle; /* 这一帧光标画到第几行 */
/* which row the cursor is drawing on this frame */
int border;
ui_2d_clear(VML_COLOR_BLACK);
fs = 12;
if (g_w < 460) { fs = 10; }
if (g_w >= 760) { fs = 15; }
lh = fs + 6;
needle = 6;
/* ── 自检图形:外框 + 九宫格 + 两条对角线 ──
* 三层都要**贴到画布四边**。任何一层贴不上(或只贴一半),就说明「宿主报的位置」与
* 「渲染映到的矩形」不是同一个空间 —— 这正是 E141 那条的现场判据。
* 对角线交于正中;九宫格的四个交点落在 (w/3, h/3) 一类的整数分位上,边界对不上时最扎眼。
* ── Self-check shapes: outer border + 3x3 grid + both diagonals ──
* All three must **reach the four canvas edges**. If any of them does not (or only half does), then
* "the position the host reports" and "the rectangle the render maps to" are not the same space -
* that is the on-site criterion for E141. The diagonals cross at the exact centre, and the grid's four
* intersections land on integer thirds (w/3, h/3), which makes a mismatched boundary most obvious. */
border = VML_COLOR_GRAY;
if (g_flash != 0 && ui_time_get_ms() - g_flash < 1200) { border = VML_COLOR_YELLOW; }
/* 外框 */
/* outer border */
ui_2d_rect(1, 1, g_w - 2, g_h - 2, border, 0, 2, 0);
/* 九宫格 */
/* 3x3 grid */
ui_2d_line(g_w / 3, 2, g_w / 3, g_h - 3, VML_COLOR_NAVY, 1);
ui_2d_line(g_w * 2 / 3, 2, g_w * 2 / 3, g_h - 3, VML_COLOR_NAVY, 1);
ui_2d_line(2, g_h / 3, g_w - 3, g_h / 3, VML_COLOR_NAVY, 1);
ui_2d_line(2, g_h * 2 / 3, g_w - 3, g_h * 2 / 3, VML_COLOR_NAVY, 1);
/* 两条对角线 */
/* both diagonals */
ui_2d_line(2, 2, g_w - 3, g_h - 3, VML_COLOR_TEAL, 1);
ui_2d_line(g_w - 3, 2, 2, g_h - 3, VML_COLOR_TEAL, 1);
/* ── 1. 实测画布 ── */
g_txt[0] = 0;
cat(g_txt, g_lang == 0 ? "画布(实测) " : "canvas(measured) ");
{
char b[16];
fmt(g_w, b);
cat(g_txt, b);
cat(g_txt, " x ");
fmt(g_h, b);
cat(g_txt, b);
}
ui_2d_text(8, needle, g_txt, VML_COLOR_WHITE, fs + 3, VML_ANCHOR_LEFT);
needle = needle + lh + 4;
/* ── 2. 三种 chrome × 两个方向的**估算**(开窗前问到的就是这些;数值由 `est_refresh` 备好) ── */
i = 0;
while (i < 3) {
ui_2d_text(8, needle, g_est[i], VML_COLOR_SILVER, fs, VML_ANCHOR_LEFT);
needle = needle + lh;
i = i + 1;
}
needle = needle + 4;
/* ── 3. 当前方向 / 语言 / 键盘 / 锁定 ── */
g_txt[0] = 0;
cat(g_txt, g_lang == 0 ? "方向 " : "orient ");
cat(g_txt, ui_scr_get_orientation() == VML_ORIENT_LANDSCAPE
? (g_lang == 0 ? "横向" : "landscape")
: (g_lang == 0 ? "纵向" : "portrait"));
cat(g_txt, " ");
cat(g_txt, g_lang == 0 ? "语言 " : "lang ");
cat(g_txt, g_lang == 0 ? "中文" : "English");
ui_2d_text(8, needle, g_txt, VML_COLOR_WHITE, fs, VML_ANCHOR_LEFT);
needle = needle + lh;
g_txt[0] = 0;
cat(g_txt, g_lang == 0 ? "键盘 " : "keyboard ");
if (g_kb == KB_GAMEPAD) { cat(g_txt, g_lang == 0 ? "手柄(gamepad)" : "gamepad"); }
if (g_kb == KB_KEYBOARD) { cat(g_txt, g_lang == 0 ? "屏幕键盘(keyboard)" : "keyboard"); }
if (g_kb == KB_NONE) { cat(g_txt, g_lang == 0 ? "无(none)" : "none"); }
cat(g_txt, " ");
cat(g_txt, g_lang == 0 ? "锁定 " : "lock ");
if (g_lock == VML_LOCK_PORTRAIT) { cat(g_txt, g_lang == 0 ? "纵向" : "portrait"); }
if (g_lock == VML_LOCK_LANDSCAPE) { cat(g_txt, g_lang == 0 ? "横向" : "landscape"); }
if (g_lock == VML_LOCK_AUTO) { cat(g_txt, g_lang == 0 ? "自动" : "auto"); }
ui_2d_text(8, needle, g_txt, VML_COLOR_WHITE, fs, VML_ANCHOR_LEFT);
needle = needle + lh;
/* ── 当前按下的键(同时按几个就把几个名字都列出来) ── */
keys_reconcile();
g_txt[0] = 0;
cat(g_txt, g_lang == 0 ? "按键 " : "keys ");
if (g_keyn == 0) {
cat(g_txt, g_lang == 0 ? "(无)" : "(none)");
} else {
i = 0;
while (i < g_keyn) {
if (i > 0) { cat(g_txt, " + "); }
cat(g_txt, keyname(g_keys[i]));
i = i + 1;
}
}
ui_2d_text(8, needle, g_txt, VML_COLOR_CYAN, fs, VML_ANCHOR_LEFT);
needle = needle + lh + 4;
/* ── 4. 多点触摸:每个**按着的**槽位一个圈 + 坐标 ──
* ⚠ `ui_touch_fetch(slot)` 的返回值是「**这个槽位号合法**」(0..9 恒真),
* 不是「这个槽位有手指」—— 有没有按在 `ui_touch_is_down()` 里(实测:不判它会有 10 个幽灵点)。
* ── Multi-touch: one circle + coordinates per **pressed** slot ──
* ⚠ The return value of `ui_touch_fetch(slot)` means "**this slot number is valid**" (always true for 0..9),
* not "this slot has a finger" - whether it is pressed lives in `ui_touch_is_down()`
* (measured: without checking it you get 10 ghost points). */
g_txt[0] = 0;
cat(g_txt, g_lang == 0 ? "触摸 " : "touch ");
n = 0;
slot = 0;
while (slot < 10) {
ui_touch_fetch(slot);
if (ui_touch_is_down() != 0) { n = n + 1; }
slot = slot + 1;
}
{
char b[16];
fmt(n, b);
cat(g_txt, b);
cat(g_txt, g_lang == 0 ? " 点" : " down");
}
ui_2d_text(8, needle, g_txt, VML_COLOR_LIME, fs, VML_ANCHOR_LEFT);
needle = needle + lh;
slot = 0;
while (slot < 10) {
ui_touch_fetch(slot);
if (ui_touch_is_down() != 0) {
int tx;
int ty;
char b[16];
int px;
int py;
tx = ui_touch_get_x();
ty = ui_touch_get_y();
px = tx;
py = ty;
if (px < 16) { px = 16; }
if (py < 16) { py = 16; }
if (px > g_w - 16) { px = g_w - 16; }
if (py > g_h - 16) { py = g_h - 16; }
ui_2d_circle(px, py, 22, VML_COLOR_ORANGE, 0, 3);
g_txt[0] = 0;
cat(g_txt, g_lang == 0 ? "手指" : "slot");
fmt(slot, b);
cat(g_txt, b);
cat(g_txt, " (");
fmt(tx, b);
cat(g_txt, b);
cat(g_txt, ",");
fmt(ty, b);
cat(g_txt, b);
cat(g_txt, ")");
ui_2d_text(8, needle, g_txt, VML_COLOR_GOLD, fs, VML_ANCHOR_LEFT);
needle = needle + lh;
}
slot = slot + 1;
}
needle = needle + 4;
/* ── 5. 消息日志(尺寸/方向变了会在这里留痕 + 边框闪一下) ── */
ui_2d_text(8, needle, g_lang == 0 ? "消息:" : "messages:", VML_COLOR_GRAY, fs, VML_ANCHOR_LEFT);
needle = needle + lh - 2;
i = 0;
while (i < g_logn) {
ui_2d_text(16, needle, g_log[i], VML_COLOR_GRAY, fs, VML_ANCHOR_LEFT);
needle = needle + lh - 2;
i = i + 1;
}
/* ── 6. 热键提示钉在底部 ── */
ui_2d_text(8, g_h - fs - 8,
g_lang == 0 ? "G 手柄 K 键盘 N 无 L 锁方向 Q 退出"
: "G pad K kbd N none L lock Q quit",
VML_COLOR_GRAY, fs, VML_ANCHOR_LEFT);
ui_2d_present();
}
int main(void) {
int msg[4];
int t;
int k;
int want = -1; /* 请求换档(-1 = 不换) */
/* requested mode change (-1 = none) */
g_lang = ui_scr_get_language();
reopen_window();
log_add(g_lang == 0 ? "已开窗(手柄档)" : "opened (gamepad)");
while (ui_win_is_closed() == 0) {
t = ui_msg_wait(msg, 100);
if (t == VML_MSG_WINDOWCLOSE) { break; }
if (t == VML_MSG_WINDOWORIENT) {
char b[16];
g_txt[0] = 0;
cat(g_txt, g_lang == 0 ? "方向→" : "orient->");
cat(g_txt, msg[1] == VML_ORIENT_LANDSCAPE ? (g_lang == 0 ? "横向" : "landscape")
: (g_lang == 0 ? "纵向" : "portrait"));
log_add(g_txt);
est_refresh();
g_flash = ui_time_get_ms();
}
if (t == VML_MSG_WINDOWRESIZE) {
char b[16];
/* ⚠ 开窗后**第一条** resize 才是判据:拿"开窗那一刻问到的"跟"宿主真正给的"比。
* 两者不等 ⇒ 开窗后立刻问仍然是估算值,**必须以这条消息为准重排**(E141 的正解)。 */
/* ⚠ Only the **first** resize after the open is the criterion: compare "what was read at open time"
* with "what the host actually gives". If they differ, the value read right after the open was still
* an estimate and you **must relay out from this message** (the sanctioned fix for E141). */
if (g_had_resize == 0) {
g_had_resize = 1;
if (g_open_w != msg[1] || g_open_h != msg[2]) {
g_txt[0] = 0;
cat(g_txt, g_lang == 0 ? "开窗问到的 " : "at open ");
fmt(g_open_w, b); cat(g_txt, b);
cat(g_txt, "x");
fmt(g_open_h, b); cat(g_txt, b);
cat(g_txt, g_lang == 0 ? " 是估算,实际 " : " was an estimate; real ");
fmt(msg[1], b); cat(g_txt, b);
cat(g_txt, "x");
fmt(msg[2], b); cat(g_txt, b);
log_add(g_txt);
} else {
log_add(g_lang == 0 ? "开窗问到的 = 实际(一致)"
: "at-open value = real (match)");
}
}
g_txt[0] = 0;
cat(g_txt, g_lang == 0 ? "尺寸→" : "resize->");
fmt(msg[1], b); cat(g_txt, b);
cat(g_txt, "x");
fmt(msg[2], b); cat(g_txt, b);
log_add(g_txt);
/* 尺寸变了:**重取一次大小**(`ui_scr_get_w/h`)、按新尺寸**全量重画**
* (外框 / 九宫格 / 对角线都是按 g_w×g_h 现算的,下一帧自然就是新的)。
* ⚠ 两个来源(消息里的 A/B 与重取的值)**不一定相等** —— 不等就留一条痕。
* ── Size changed: **re-query the size** (`ui_scr_get_w/h`) and **redraw everything** for it
* (the border / grid / diagonals are all computed from g_w x g_h, so the next frame is already new).
* ⚠ The two sources (A/B in the message and the re-queried value) **are not necessarily equal** -
* leave a mark when they differ. */
{
int qw;
int qh;
qw = ui_scr_get_w();
qh = ui_scr_get_h();
if (qw != msg[1] || qh != msg[2]) {
g_txt[0] = 0;
cat(g_txt, g_lang == 0 ? "重取 " : "requery ");
fmt(qw, b); cat(g_txt, b);
cat(g_txt, "x");
fmt(qh, b); cat(g_txt, b);
cat(g_txt, g_lang == 0 ? " ≠ 消息" : " != message");
log_add(g_txt);
}
g_w = msg[1];
g_h = msg[2];
if (g_w <= 0) { g_w = qw; }
if (g_h <= 0) { g_h = qh; }
if (g_w <= 0) { g_w = 360; }
if (g_h <= 0) { g_h = 620; }
}
est_refresh();
g_flash = ui_time_get_ms();
}
if (t == VML_MSG_KEYUP) {
keys_del(msg[1]);
}
if (t == VML_MSG_KEYDOWN) {
k = msg[1];
keys_add(k);
if (k == VML_KEY_ESCAPE || k == 'Q' || k == 'q') { break; }
if (k == 'G' || k == 'g') { want = KB_GAMEPAD; }
if (k == 'K' || k == 'k') { want = KB_KEYBOARD; }
if (k == 'N' || k == 'n') { want = KB_NONE; }
if (k == 'L' || k == 'l') {
g_lock = g_lock + 1;
if (g_lock > VML_LOCK_AUTO) { g_lock = VML_LOCK_PORTRAIT; }
ui_scr_lock_orientation(g_lock);
log_add(g_lang == 0 ? "锁定已切换" : "lock cycled");
}
}
/* 换档在**消息处理之外**做:重开窗会重置消息队列,在循环里换会踩到自己 */
/* The mode switch happens **outside message handling**: reopening resets the queue, so switching inside the loop trips over itself */
if (want >= 0) {
g_kb = want;
want = -1;
reopen_window();
ui_msg_clear();
log_add(g_lang == 0 ? "已重开窗(换档)" : "reopened (mode switch)");
}
draw();
}
ui_scr_set_keep_on(0);
return 0;
}