Skip to main content

atmos/kernel/
mouse.rs

1#[derive(Debug, Clone, Copy)]
2pub struct MouseEvent {
3    pub dx: i32,
4    pub dy: i32,
5    pub left_btn: bool,
6    pub right_btn: bool,
7    pub middle_btn: bool,
8}
9
10pub struct MouseDecoder {
11    state: u8,
12    buf: [u8; 3],
13}
14
15impl Default for MouseDecoder {
16    fn default() -> Self {
17        Self::new()
18    }
19}
20
21impl MouseDecoder {
22    pub const fn new() -> Self {
23        Self {
24            state: 0,
25            buf: [0; 3],
26        }
27    }
28
29    /// 1バイト受信し、状態マシンを用いてパケットのデコードを試みます。
30    /// 3バイトのパケットが完成すると、MouseEvent を返します。
31    pub fn decode(&mut self, data: u8) -> Option<MouseEvent> {
32        match self.state {
33            0 => {
34                // PS/2 マウスの1バイト目は、ビット3が常に 1 である必要があります。
35                // これを用いてパケットの同期(アライメント)を取ります。
36                if (data & 0x08) != 0 {
37                    self.buf[0] = data;
38                    self.state = 1;
39                }
40            }
41            1 => {
42                self.buf[1] = data;
43                self.state = 2;
44            }
45            2 => {
46                self.buf[2] = data;
47                self.state = 0; // 次の受信のために状態をリセット
48
49                let btn = self.buf[0];
50                let raw_x = self.buf[1];
51                let raw_y = self.buf[2];
52
53                let left_btn = (btn & 0x01) != 0;
54                let right_btn = (btn & 0x02) != 0;
55                let middle_btn = (btn & 0x04) != 0;
56
57                // 2の補数表現から 32bit 符号付き整数へデコード (符号拡張)
58                let mut dx = raw_x as i32;
59                let mut dy = raw_y as i32;
60
61                // X_sign (bit 4) が 1 なら負の値
62                if (btn & 0x10) != 0 {
63                    dx |= !0xFF;
64                }
65                // Y_sign (bit 5) が 1 なら負の値
66                if (btn & 0x20) != 0 {
67                    dy |= !0xFF;
68                }
69
70                // 画面座標系は「下がプラス」ですが、PS/2マウスは「上がプラス(手前に引くとマイナス)」であるため、
71                // Y軸の移動量を反転させて画面座標と一致させます。
72                dy = -dy;
73
74                return Some(MouseEvent {
75                    dx,
76                    dy,
77                    left_btn,
78                    right_btn,
79                    middle_btn,
80                });
81            }
82            _ => self.state = 0,
83        }
84        None
85    }
86}