Files
ViperOS/VKernel/Kernel/drivers/input/mouse/mouse.vp
T
TermiNexus cc061b2ad3 fix(vkernel): 修复 PS/2 鼠标位移符号误判(|位移|≥128 时方向翻转、光标向左飞没)
根因(静态定位,非速度问题):PS/2 协议里第 2/3 字节是位移“幅值”,符号在第 1 字节的
bit4(X)/bit5(Y)。而驱动把位移按 int8 存储/解释,于是 |位移| ≥ 128 时字节最高位被当成
符号位:
- 向右快移(幅值 0x80~0xFF)被读成负数 → _cursor_x 一路减小 → 撞上 if _cursor_x<0
  被夹成 0 → 表现为“光标往左飞没了”;
- int8 装不下 9 位有符号位移(符号位在 flags 里),结构上必然丢符号。

修改:
- drivers/input/mouse/mouse.vp:mouse_packet.dx/dy 与 byte2/byte3 改为 uint8,保存原始
  幅值字节,消除 int8 截断;flags(含符号位)照旧保留。
- services/desktop.vp::_update_mouse:按协议用“幅值 + 符号位”重建带符号位移
  (命中 flags.bit4/bit5 时幅值 -256),再做屏幕 Y 轴反向。
- USB HID 分支不动:USB 报告的 X/Y 本身即 int8 有符号,原解释正确。
2026-10-14 15:12:19 +08:00

143 lines
3.8 KiB
Plaintext
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.
import asm
import intr.idt as idt
import platform.pch.pic as pic
import drivers.serial.uart.serial as serial
import t, c
define MOUSE_DATA = 0x60
define MOUSE_STATUS = 0x64
define MOUSE_COMMAND = 0x64
define MOUSE_BUF_SIZE = 1024
define MOUSE_LEFT = 0x01
define MOUSE_RIGHT = 0x02
define MOUSE_MIDDLE = 0x04
class mouse_packet:
flags: uint8
dx: uint8 # 原始幅值字节(符号在 flags.bit4)
dy: uint8 # 原始幅值字节(符号在 flags.bit5)
buttons: uint8
packets: [MOUSE_BUF_SIZE]mouse_packet
pack_head: static uint32 = 0
pack_tail: static uint32 = 0
pack_count: static uint32 = 0
mse_irq_cnt: static uint64 = 0
cycle: static uint8 = 0
byte1: static uint8 = 0
byte2: static uint8 = 0
byte3: static uint8 = 0
mouse_x: static int32 = 0
mouse_y: static int32 = 0
mouse_buttons: static uint8 = 0
def _wait_read():
timeout: uint32 = 100000
for _ in range(timeout, 0, -1):
if (asm.inb(MOUSE_STATUS) & 0x01) != 0: return
def _wait_write():
timeout: uint32 = 100000
for _ in range(timeout, 0, -1):
if (asm.inb(MOUSE_STATUS) & 0x02) == 0: return
def _write_cmd(cmd: uint8):
_wait_write()
asm.outb(MOUSE_COMMAND, 0xD4)
_wait_write()
asm.outb(MOUSE_DATA, cmd)
_wait_read()
asm.inb(MOUSE_DATA)
def irq_handler() -> int:
global cycle, byte1, byte2, byte3, pack_tail, pack_count, mse_irq_cnt
mse_irq_cnt += 1
status: uint8 = asm.inb(MOUSE_STATUS)
if (status & 0x20) == 0: return 0
data: uint8 = asm.inb(MOUSE_DATA)
if cycle == 0:
if (data & 0x08) != 0:
byte1 = data
cycle = 1
return 0
if cycle == 1:
byte2 = data
cycle = 2
return 0
byte3 = data
cycle = 0
# 丢弃带溢出位的包(bit6/bit7 = X/Y overflow):此时设备给的是饱和值,
# 直接采用会产生 ±127 级跳变(表现为光标“飞”)。
if (byte1 & 0xC0) != 0:
return 0
if pack_count < MOUSE_BUF_SIZE:
packets[pack_tail].flags = byte1
packets[pack_tail].dx = byte2
packets[pack_tail].dy = byte3
packets[pack_tail].buttons = byte1 & uint8(0x07)
pack_tail = pack_tail + 1
if pack_tail >= MOUSE_BUF_SIZE:
pack_tail = 0
pack_count += 1
return 0
def read_packet(out: mouse_packet*) -> int:
global pack_head, pack_count
asm.cli()
if pack_count == 0:
asm.sti()
out.flags = 0
out.dx = 0
out.dy = 0
out.buttons = 0
return -1
out.flags = packets[pack_head].flags
out.dx = packets[pack_head].dx
out.dy = packets[pack_head].dy
out.buttons = packets[pack_head].buttons
pack_head = pack_head + 1
if pack_head >= MOUSE_BUF_SIZE:
pack_head = 0
pack_count -= 1
asm.sti()
return 0
def has_data() -> int:
return pack_count
def get_x() -> int32:
return mouse_x
def get_y() -> int32:
return mouse_y
def get_buttons() -> uint8:
return mouse_buttons
def init():
_wait_write()
asm.outb(MOUSE_COMMAND, 0xA8)
_wait_write()
asm.outb(MOUSE_COMMAND, 0x20)
_wait_read()
status: uint8 = asm.inb(MOUSE_DATA)
status = status | 0x02
status = status & 0xDF
_wait_write()
asm.outb(MOUSE_COMMAND, 0x60)
_wait_write()
asm.outb(MOUSE_DATA, status)
_write_cmd(0xF6)
# 分辨率设为 8 counts/mm:0xF6(Set Defaults) 会把它重置为最粗的 4 counts/mm,
# 于是每个计数对应的位移偏大。设细一档后光标更稳、不易“飞”。
_write_cmd(0xE8)
_write_cmd(0x03)
_write_cmd(0xF4)
pic.clearMask(12)
idt.irqInstallHandler(12, irq_handler, "mouse")