1# Copyright (c) Twisted Matrix Laboratories.
2# See LICENSE for details.
3
4#
5"""Logictech MouseMan serial protocol.
6
7http://www.softnco.demon.co.uk/SerialMouse.txt
8"""
9
10from twisted.internet import protocol
11
12class MouseMan(protocol.Protocol):
13    """
14
15    Parser for Logitech MouseMan serial mouse protocol (compatible
16    with Microsoft Serial Mouse).
17
18    """
19
20    state = 'initial'
21
22    leftbutton=None
23    rightbutton=None
24    middlebutton=None
25
26    leftold=None
27    rightold=None
28    middleold=None
29
30    horiz=None
31    vert=None
32    horizold=None
33    vertold=None
34
35    def down_left(self):
36        pass
37
38    def up_left(self):
39        pass
40
41    def down_middle(self):
42        pass
43
44    def up_middle(self):
45        pass
46
47    def down_right(self):
48        pass
49
50    def up_right(self):
51        pass
52
53    def move(self, x, y):
54        pass
55
56    horiz=None
57    vert=None
58
59    def state_initial(self, byte):
60        if byte & 1<<6:
61            self.word1=byte
62            self.leftbutton = byte & 1<<5
63            self.rightbutton = byte & 1<<4
64            return 'horiz'
65        else:
66            return 'initial'
67
68    def state_horiz(self, byte):
69        if byte & 1<<6:
70            return self.state_initial(byte)
71        else:
72            x=(self.word1 & 0x03)<<6 | (byte & 0x3f)
73            if x>=128:
74                x=-256+x
75            self.horiz = x
76            return 'vert'
77
78    def state_vert(self, byte):
79        if byte & 1<<6:
80            # short packet
81            return self.state_initial(byte)
82        else:
83            x = (self.word1 & 0x0c)<<4 | (byte & 0x3f)
84            if x>=128:
85                x=-256+x
86            self.vert = x
87            self.snapshot()
88            return 'maybemiddle'
89
90    def state_maybemiddle(self, byte):
91        if byte & 1<<6:
92            self.snapshot()
93            return self.state_initial(byte)
94        else:
95            self.middlebutton=byte & 1<<5
96            self.snapshot()
97            return 'initial'
98
99    def snapshot(self):
100        if self.leftbutton and not self.leftold:
101            self.down_left()
102            self.leftold=1
103        if not self.leftbutton and self.leftold:
104            self.up_left()
105            self.leftold=0
106
107        if self.middlebutton and not self.middleold:
108            self.down_middle()
109            self.middleold=1
110        if not self.middlebutton and self.middleold:
111            self.up_middle()
112            self.middleold=0
113
114        if self.rightbutton and not self.rightold:
115            self.down_right()
116            self.rightold=1
117        if not self.rightbutton and self.rightold:
118            self.up_right()
119            self.rightold=0
120
121        if self.horiz or self.vert:
122            self.move(self.horiz, self.vert)
123
124    def dataReceived(self, data):
125        for c in data:
126            byte = ord(c)
127            self.state = getattr(self, 'state_'+self.state)(byte)
128