ohhhhhhhhhhh (exclude linux-extra-rootfs.img build artifact)
This commit is contained in:
@@ -0,0 +1,306 @@
|
||||
/* input.c — PS/2 鼠标键盘、光标管理、RTC/TSC 时钟(M0 自 main.c 平移)
|
||||
*/
|
||||
#include "desktop.h"
|
||||
|
||||
/* ---- 全局状态 ---- */
|
||||
int g_mouse_x = 400, g_mouse_y = 300;
|
||||
int g_mouse_btn = 0; /* bit0=左 bit1=右 */
|
||||
int g_left_pressed = 0, g_left_released = 0, g_right_pressed = 0;
|
||||
static u8 g_mouse_buf[3];
|
||||
static int g_mouse_idx = 0;
|
||||
static int g_mouse_has_pkt = 0;
|
||||
|
||||
/* 光标背景保存 */
|
||||
static u32 g_cursor_save[CURSOR_SIZE * CURSOR_SIZE];
|
||||
int g_cursor_saved = 0;
|
||||
int g_cursor_old_x = -1, g_cursor_old_y = -1;
|
||||
|
||||
/* 键盘状态 */
|
||||
int g_shift = 0, g_ctrl = 0, g_alt = 0;
|
||||
int g_e0 = 0;
|
||||
|
||||
/* 时钟 */
|
||||
int g_rtc_boot_sec = 0; /* 开机时刻(秒级当天秒) */
|
||||
int g_last_sec = -1;
|
||||
u64 g_tsc_per_sec = 0;
|
||||
|
||||
/* ============================================================
|
||||
* 箭头光标形状(24×24,1=前景 0=透明)
|
||||
* ============================================================ */
|
||||
|
||||
static const u8 cursor_shape[24][24] = {
|
||||
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
};
|
||||
|
||||
/* ============================================================
|
||||
* RTC 时钟
|
||||
* ============================================================ */
|
||||
|
||||
static int bcd2bin(u8 v) { return (v >> 4) * 10 + (v & 0xF); }
|
||||
|
||||
void rtc_read(int *yy, int *mo, int *dd, int *hh, int *mi, int *ss) {
|
||||
outb(0x70, 0x00); *ss = bcd2bin(inb(0x71));
|
||||
outb(0x70, 0x02); *mi = bcd2bin(inb(0x71));
|
||||
outb(0x70, 0x04); *hh = bcd2bin(inb(0x71));
|
||||
outb(0x70, 0x07); *dd = bcd2bin(inb(0x71));
|
||||
outb(0x70, 0x08); *mo = bcd2bin(inb(0x71));
|
||||
outb(0x70, 0x09); *yy = bcd2bin(inb(0x71));
|
||||
}
|
||||
|
||||
int rtc_day_sec(void) {
|
||||
int y, mo, d, h, mi, s;
|
||||
rtc_read(&y, &mo, &d, &h, &mi, &s);
|
||||
return h * 3600 + mi * 60 + s;
|
||||
}
|
||||
|
||||
/* 格式化 HH:MM:SS */
|
||||
void fmt_hms(char *out, int sec) {
|
||||
int h = sec / 3600, m = (sec / 60) % 60, s = sec % 60;
|
||||
out[0] = '0' + h / 10; out[1] = '0' + h % 10; out[2] = ':';
|
||||
out[3] = '0' + m / 10; out[4] = '0' + m % 10; out[5] = ':';
|
||||
out[6] = '0' + s / 10; out[7] = '0' + s % 10; out[8] = 0;
|
||||
}
|
||||
|
||||
/* 校准 TSC(约 1 秒):用于双击间隔判定 */
|
||||
void tsc_calibrate(void) {
|
||||
int s0 = rtc_day_sec();
|
||||
while (rtc_day_sec() == s0) __asm__("pause");
|
||||
u64 t0 = rdtsc();
|
||||
int s1 = rtc_day_sec();
|
||||
while (rtc_day_sec() == s1) __asm__("pause");
|
||||
g_tsc_per_sec = rdtsc() - t0;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 光标管理
|
||||
* ============================================================ */
|
||||
|
||||
void cursor_save_bg(int mx, int my) {
|
||||
for (int r = 0; r < CURSOR_SIZE; r++) {
|
||||
for (int c = 0; c < CURSOR_SIZE; c++) {
|
||||
int x = mx + c, y = my + r;
|
||||
if (x >= 0 && (u64)x < g_fb_w && y >= 0 && (u64)y < g_fb_h) {
|
||||
u32 *line = (u32 *)((u8 *)g_fb.fb + (u64)y * g_fb.pitch);
|
||||
g_cursor_save[r * CURSOR_SIZE + c] = line[x];
|
||||
} else {
|
||||
g_cursor_save[r * CURSOR_SIZE + c] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
g_cursor_saved = 1;
|
||||
g_cursor_old_x = mx;
|
||||
g_cursor_old_y = my;
|
||||
}
|
||||
|
||||
void cursor_restore_bg(void) {
|
||||
if (!g_cursor_saved) return;
|
||||
for (int r = 0; r < CURSOR_SIZE; r++) {
|
||||
for (int c = 0; c < CURSOR_SIZE; c++) {
|
||||
int x = g_cursor_old_x + c, y = g_cursor_old_y + r;
|
||||
if (x >= 0 && (u64)x < g_fb_w && y >= 0 && (u64)y < g_fb_h) {
|
||||
u32 *line = (u32 *)((u8 *)g_fb.fb + (u64)y * g_fb.pitch);
|
||||
line[x] = g_cursor_save[r * CURSOR_SIZE + c];
|
||||
}
|
||||
}
|
||||
}
|
||||
g_cursor_saved = 0;
|
||||
}
|
||||
|
||||
void cursor_draw(int mx, int my) {
|
||||
for (int r = 0; r < CURSOR_SIZE; r++) {
|
||||
for (int c = 0; c < CURSOR_SIZE; c++) {
|
||||
if (cursor_shape[r][c]) {
|
||||
du_pixel(&g_fb, mx + c, my + r, KS_ACCENT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* PS/2 鼠标处理
|
||||
* ============================================================ */
|
||||
|
||||
static int ps2_wait_write(void) {
|
||||
for (int t = 0; t < 200000; t++) {
|
||||
if (!(inb(0x64) & 0x02)) return 0;
|
||||
__asm__ volatile("pause");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int ps2_wait_read(void) {
|
||||
for (int t = 0; t < 200000; t++) {
|
||||
if (inb(0x64) & 0x01) return 0;
|
||||
__asm__ volatile("pause");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void ps2_drain(void) {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (!(inb(0x64) & 0x01)) break;
|
||||
inb(0x60);
|
||||
}
|
||||
}
|
||||
|
||||
void ps2_mouse_init(void) {
|
||||
ps2_drain();
|
||||
|
||||
ps2_wait_write();
|
||||
outb(0x64, 0xA8);
|
||||
|
||||
ps2_wait_write();
|
||||
outb(0x64, 0x20);
|
||||
ps2_wait_read();
|
||||
u8 cfg = inb(0x60);
|
||||
|
||||
cfg &= ~0x20;
|
||||
cfg |= 0x02;
|
||||
cfg |= 0x40;
|
||||
|
||||
ps2_wait_write();
|
||||
outb(0x64, 0x60);
|
||||
ps2_wait_write();
|
||||
outb(0x60, cfg);
|
||||
|
||||
ps2_wait_write();
|
||||
outb(0x64, 0xD4);
|
||||
ps2_wait_write();
|
||||
outb(0x60, 0xFF);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (ps2_wait_read() != 0) break;
|
||||
inb(0x60);
|
||||
}
|
||||
|
||||
ps2_wait_write();
|
||||
outb(0x64, 0xD4);
|
||||
ps2_wait_write();
|
||||
outb(0x60, 0xF4);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (ps2_wait_read() != 0) break;
|
||||
inb(0x60);
|
||||
}
|
||||
|
||||
ps2_drain();
|
||||
|
||||
g_mouse_idx = 0;
|
||||
g_mouse_has_pkt = 0;
|
||||
|
||||
slog("mouse init ok");
|
||||
}
|
||||
|
||||
int ps2_mouse_poll(void) {
|
||||
u8 st = inb(0x64);
|
||||
if (!(st & 1)) return 0;
|
||||
if (!(st & 0x20)) return 0;
|
||||
u8 data = inb(0x60);
|
||||
|
||||
g_mouse_buf[g_mouse_idx++] = data;
|
||||
if (g_mouse_idx < 3) return 0;
|
||||
g_mouse_idx = 0;
|
||||
|
||||
if (!(g_mouse_buf[0] & 0x08)) return 0;
|
||||
|
||||
int dx = (int)(i8)g_mouse_buf[1];
|
||||
int dy = (int)(i8)g_mouse_buf[2];
|
||||
dy = -dy;
|
||||
|
||||
g_mouse_x += dx;
|
||||
g_mouse_y += dy;
|
||||
if (g_mouse_x < 0) g_mouse_x = 0;
|
||||
if (g_mouse_y < 0) g_mouse_y = 0;
|
||||
if (g_mouse_x >= (int)g_fb_w - CURSOR_SIZE) g_mouse_x = (int)g_fb_w - CURSOR_SIZE;
|
||||
if (g_mouse_y >= (int)g_fb_h - CURSOR_SIZE) g_mouse_y = (int)g_fb_h - CURSOR_SIZE;
|
||||
|
||||
int old_btn = g_mouse_btn;
|
||||
g_mouse_btn = g_mouse_buf[0] & 0x03;
|
||||
if ((g_mouse_btn & 1) && !(old_btn & 1)) g_left_pressed = 1;
|
||||
if (!(g_mouse_btn & 1) && (old_btn & 1)) g_left_released = 1;
|
||||
if ((g_mouse_btn & 2) && !(old_btn & 2)) g_right_pressed = 1;
|
||||
if (dx == 0 && dy == 0 && g_mouse_btn == old_btn) return 0;
|
||||
|
||||
/* VSCode Phase 2: IDE attached 时把相对位移 + 按钮状态镜像到 Linux guest。
|
||||
* dy 已在上方取反为屏幕坐标系(正=下),与 Linux REL_Y 约定一致;
|
||||
* input_forward_mouse 内部与上次状态比较,仅产生变化按钮事件 + SYN。
|
||||
* 即使宿主光标已抵边界被钳位,原始 dx/dy 仍转发,guest 光标自由移动。 */
|
||||
if (g_input_forward_enabled && g_lxc_svc && g_lxc_svc->input_forward_mouse) {
|
||||
g_lxc_svc->input_forward_mouse(dx, dy, (u8)g_mouse_btn);
|
||||
}
|
||||
|
||||
g_mouse_has_pkt = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 键盘扫描码 → ASCII
|
||||
* ============================================================ */
|
||||
|
||||
char scan_to_ascii(u8 sc, int shift) {
|
||||
static const char normal[58] = {
|
||||
0, 27, '1','2','3','4','5','6','7','8','9','0','-','=', 8, '\t',
|
||||
'q','w','e','r','t','y','u','i','o','p','[',']','\n',0,
|
||||
'a','s','d','f','g','h','j','k','l',';','\'', '`',0,'\\',
|
||||
'z','x','c','v','b','n','m',',','.','/',0,'*',0,' '
|
||||
};
|
||||
static const char shifted[58] = {
|
||||
0, 27, '!','@','#','$','%','^','&','*','(',')','_','+', 8, '\t',
|
||||
'Q','W','E','R','T','Y','U','I','O','P','{','}','\n',0,
|
||||
'A','S','D','F','G','H','J','K','L',':','"','~',0,'|',
|
||||
'Z','X','C','V','B','N','M','<','>','?',0,'*',0,' '
|
||||
};
|
||||
if (sc >= 58) return 0;
|
||||
return shift ? shifted[sc] : normal[sc];
|
||||
}
|
||||
|
||||
/* VSCode Phase 2: PS/2 set-1 扫描码 → Linux keycode(linux/input-event-codes.h)。
|
||||
* base : 已去除 0x80 release 位的基础扫描码(0x01..0x39 主键区 + 少数扩展)
|
||||
* e0 : 上一字节为 0xE0 前缀时置 1,选取扩展键变体
|
||||
* 返回 0 表示该扫描码无映射(调用方应丢弃)。
|
||||
*
|
||||
* 巧合:主键区 0x01..0x39 的 Linux keycode 与扫描码数值完全一致
|
||||
* (IBM XT 布局历史遗留),故直接透传;仅 E0 扩展键需单独查表。 */
|
||||
u16 scancode_to_linux_keycode(u8 base, int e0) {
|
||||
if (e0) {
|
||||
switch (base) {
|
||||
case 0x1D: return 97; /* KEY_RIGHTCTRL */
|
||||
case 0x38: return 100; /* KEY_RIGHTALT */
|
||||
case 0x48: return 103; /* KEY_UP */
|
||||
case 0x4B: return 105; /* KEY_LEFT */
|
||||
case 0x4D: return 106; /* KEY_RIGHT */
|
||||
case 0x50: return 108; /* KEY_DOWN */
|
||||
case 0x52: return 110; /* KEY_INSERT */
|
||||
case 0x53: return 111; /* KEY_DELETE */
|
||||
case 0x47: return 102; /* KEY_HOME */
|
||||
case 0x4F: return 107; /* KEY_END */
|
||||
case 0x49: return 104; /* KEY_PAGEUP */
|
||||
case 0x51: return 109; /* KEY_PAGEDOWN */
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
/* 主键区:0x01..0x39 透传,超出范围无映射 */
|
||||
if (base >= 0x01 && base <= 0x39) return (u16)base;
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user