Skip to content

Commit

Permalink
improved mouse handling implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
ruundii committed Oct 31, 2021
1 parent c979471 commit 4168f4d
Show file tree
Hide file tree
Showing 7 changed files with 251 additions and 6 deletions.
8 changes: 6 additions & 2 deletions hid_devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import time
from hid_message_filter import HIDMessageFilter
from a1314_message_filter import A1314MessageFilter
from mouse_g502_message_filter import G502MessageFilter
from mouse_mx510_message_filter import MX510MessageFilter
from mouse_message_filter import MouseMessageFilter
from typing import Dict, List
from compatibility_device import CompatibilityModeDevice
Expand All @@ -21,11 +23,13 @@
FILTERS = [
{"id":"Default", "name":"Default"},
{"id":"Mouse", "name":"Mouse"},
{"id":"A1314", "name":"A1314"}
{"id":"A1314", "name":"A1314"},
{"id":"G502", "name":"G502"},
{"id":"MX510", "name":"MX510"}
]

FILTER_INSTANCES = {
"Default" : HIDMessageFilter(), "Mouse":MouseMessageFilter(), "A1314":A1314MessageFilter()
"Default" : HIDMessageFilter(), "Mouse":MouseMessageFilter(), "A1314":A1314MessageFilter(), "G502":G502MessageFilter(), "MX510":MX510MessageFilter()

This comment has been minimized.

Copy link
@Dreamsorcerer

Dreamsorcerer Dec 11, 2021

Collaborator

I don't think this approach is sustainable. I think we can configure these automatically (#23). If you want to give this a go, I'm happy to work on it with you.

}

class HIDDevice:
Expand Down
1 change: 1 addition & 0 deletions install/on_rpi/on_pi_setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ sudo pip3 install aiohttp-session
sudo pip3 install watchgod
sudo pip3 install hid-tools
sudo pip3 install pyudev
sudo pip3 install bitarray

cd /home/pi/bthidhub/install/on_rpi
git clone https://github.com/ruundii/bluez
Expand Down
53 changes: 53 additions & 0 deletions mouse_g502_message_filter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Copyright (c) 2020 ruundii. All rights reserved.


from hid_message_filter import HIDMessageFilter
from mouse_message_filter import MouseMessageFilter


# 0x67, 0x05, 0x01, 0x09, 0x02, // Unit (Mass: Gram, Luminous Intensity: Candela)
# 0xA1, 0x01, // Collection (Application)
# 0x09, 0x01, // Usage (0x01)
# 0xA1, 0x00, // Collection (Physical)
# 0x05, 0x09, // Usage Page (Button)
# 0x19, 0x01, // Usage Minimum (0x01)
# 0x29, 0x10, // Usage Maximum (0x10)
# 0x15, 0x00, // Logical Minimum (0)
# 0x25, 0x01, // Logical Maximum (1)
# 0x95, 0x10, // Report Count (16)
# 0x75, 0x01, // Report Size (1)
# 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
# 0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
# 0x16, 0x01, 0x80, // Logical Minimum (-32767)
# 0x26, 0xFF, 0x7F, // Logical Maximum (32767)
# 0x75, 0x10, // Report Size (16)
# 0x95, 0x02, // Report Count (2)
# 0x09, 0x30, // Usage (X)
# 0x09, 0x31, // Usage (Y)
# 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
# 0x15, 0x81, // Logical Minimum (-127)
# 0x25, 0x7F, // Logical Maximum (127)
# 0x75, 0x08, // Report Size (8)
# 0x95, 0x01, // Report Count (1)
# 0x09, 0x38, // Usage (Wheel)
# 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
# 0x05, 0x0C, // Usage Page (Consumer)
# 0x0A, 0x38, 0x02, // Usage (AC Pan)
# 0x95, 0x01, // Report Count (1)
# 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
# 0xC0, // End Collection
# 0xC0, // End Collection
#
# // 68 bytes


class G502MessageFilter(MouseMessageFilter):
# first 16 bits are flags for buttons. 01 is left button, 02 is right, 04 is scroll
# second 16 bits are X -32767 to 32767
# third 16 bits are Y -32767 to 32767
# then 8 bits of wheel -127 to 127
# then AC pan

def __init__(self):
self.message_size = 8

63 changes: 60 additions & 3 deletions mouse_message_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,72 @@
#
from hid_message_filter import HIDMessageFilter

#default mouse filter

# first 16 bits are flags for buttons. 01 is left button, 02 is right, 04 is scroll
# second 16 bits are X -32767 to 32767
# third 16 bits are Y -32767 to 32767
# then 8 bits of wheel -127 to 127


# from the default sdp record

# 0x05, 0x01, // Usage Page (Generic Desktop) 0
# 0x09, 0x02, // Usage (Mouse) 2
# 0xa1, 0x01, // Collection (Application) 4
# 0x09, 0x01, // Usage (Pointer) 6
# 0xa1, 0x00, // Collection (Physical) 8
# 0x05, 0x09, // Usage Page (Button) 10
# 0x19, 0x01, // Usage Minimum (1) 12
# 0x29, 0x10, // Usage Maximum (16) 14
# 0x15, 0x00, // Logical Minimum (0) 16
# 0x25, 0x01, // Logical Maximum (1) 18
# 0x95, 0x10, // Report Count (16) 20
# 0x75, 0x01, // Report Size (1) 22
# 0x81, 0x02, // Input (Data,Var,Abs) 24
# 0x05, 0x01, // Usage Page (Generic Desktop) 26
# 0x16, 0x01, 0x80, // Logical Minimum (-32767) 28
# 0x26, 0xff, 0x7f, // Logical Maximum (32767) 31
# 0x75, 0x10, // Report Size (16) 34
# 0x95, 0x02, // Report Count (2) 36
# 0x09, 0x30, // Usage (X) 38
# 0x09, 0x31, // Usage (Y) 40
# 0x81, 0x06, // Input (Data,Var,Rel) 42
# 0x15, 0x81, // Logical Minimum (-127) 44
# 0x25, 0x7f, // Logical Maximum (127) 46
# 0x75, 0x08, // Report Size (8) 48
# 0x95, 0x01, // Report Count (1) 50
# 0x09, 0x38, // Usage (Wheel) 52
# 0x81, 0x06, // Input (Data,Var,Rel) 54
# 0x05, 0x0c, // Usage Page (Consumer Devices) 56
# 0x0a, 0x38, 0x02, // Usage (AC Pan) 58
# 0x95, 0x01, // Report Count (1) 61
# 0x81, 0x06, // Input (Data,Var,Rel) 63
# 0xc0, // End Collection 65
# 0xc0, // End Collection 66


class MouseMessageFilter(HIDMessageFilter):
def __init__(self):
pass
self.message_size = 7

def filter_message_to_host(self, msg):
if len(msg) != 7:
if len(msg) != self.message_size:
return None
msg = b'\xa1\x03' + msg
msg = b'\xa1\x03' + self.get_buttons_flags(msg) + self.get_x(msg) + self.get_y(msg) + self.get_wheel(msg)
return msg

def get_buttons_flags(self, msg):
return msg[0:2]

def get_x(self, msg):
return msg[2:4]

def get_y(self, msg):
return msg[4:6]

def get_wheel(self, msg):
return msg[6:7]

def filter_message_from_host(self, msg):
return None
76 changes: 76 additions & 0 deletions mouse_mx510_message_filter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Copyright (c) 2020 ruundii. All rights reserved.


from hid_message_filter import HIDMessageFilter
from mouse_message_filter import MouseMessageFilter
from bitarray import bitarray
from bitarray.util import ba2int


# Logitech USB-PS/2 Optical Mouse
# 0x05, 0x01, // Usage Page (Generic Desktop) 0
# 0x09, 0x02, // Usage (Mouse) 2
# 0xa1, 0x01, // Collection (Application) 4
# 0x09, 0x01, // Usage (Pointer) 6
# 0xa1, 0x00, // Collection (Physical) 8
# 0x05, 0x09, // Usage Page (Button) 10
# 0x19, 0x01, // Usage Minimum (1) 12
# 0x29, 0x08, // Usage Maximum (8) 14
# 0x15, 0x00, // Logical Minimum (0) 16
# 0x25, 0x01, // Logical Maximum (1) 18
# 0x95, 0x08, // Report Count (8) 20
# 0x75, 0x01, // Report Size (1) 22
# 0x81, 0x02, // Input (Data,Var,Abs) 24
# 0x95, 0x00, // Report Count (0) 26
# 0x81, 0x03, // Input (Cnst,Var,Abs) 28
# 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 30
# 0x09, 0x40, // Usage (Vendor Usage 0x40) 33
# 0x95, 0x02, // Report Count (2) 35
# 0x75, 0x08, // Report Size (8) 37
# 0x15, 0x81, // Logical Minimum (-127) 39
# 0x25, 0x7f, // Logical Maximum (127) 41
# 0x81, 0x02, // Input (Data,Var,Abs) 43
# 0x05, 0x01, // Usage Page (Generic Desktop) 45
# 0x09, 0x38, // Usage (Wheel) 47
# 0x15, 0x81, // Logical Minimum (-127) 49
# 0x25, 0x7f, // Logical Maximum (127) 51
# 0x75, 0x08, // Report Size (8) 53
# 0x95, 0x01, // Report Count (1) 55
# 0x81, 0x06, // Input (Data,Var,Rel) 57
# 0x09, 0x30, // Usage (X) 59
# 0x09, 0x31, // Usage (Y) 61
# 0x16, 0x01, 0xf8, // Logical Minimum (-2047) 63
# 0x26, 0xff, 0x07, // Logical Maximum (2047) 66
# 0x75, 0x0c, // Report Size (12) 69
# 0x95, 0x02, // Report Count (2) 71
# 0x81, 0x06, // Input (Data,Var,Rel) 73
# 0xc0, // End Collection 75
# 0xc0, // End Collection 76



class MX510MessageFilter(MouseMessageFilter):
# first 8 bits are flags for buttons. 01 is left button, 02 is right, 04 is scroll
# second 16 bits are vendor specific x and y, one byte each
# then 8 bits of wheel -127 to 127
# then x and y from -2047 to 2047, 12 bits each

def __init__(self):
self.message_size = 7

def get_buttons_flags(self, msg):
return msg[0:1]+b'\x00'

def get_x(self, msg):
a = bitarray()
a.frombytes(msg[4:6])
return int.to_bytes(ba2int(a[12:16] + a[0:8], signed=True), 2, "little", signed=True)

def get_y(self, msg):
a = bitarray()
a.frombytes(msg[5:7])
return int.to_bytes(ba2int(a[8:16]+a[0:4],signed=True), 2, "little", signed=True)

def get_wheel(self, msg):
return msg[3:4]

54 changes: 54 additions & 0 deletions mouse_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
from mouse_message_filter import MouseMessageFilter
from mouse_g502_message_filter import G502MessageFilter
from mouse_mx510_message_filter import MX510MessageFilter

m = MouseMessageFilter()
g = G502MessageFilter()
mx = MX510MessageFilter()

#generic mouse test
# Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | X: -1 | Y: -13 | Wheel: 0
print(m.filter_message_to_host(b'\x00\x00\xff\xff\xf3\xff\x00')==b'\xa1\x03\x00\x00\xff\xff\xf3\xff\x00')

# Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | X: 1 | Y: 5 | Wheel: 0
print(m.filter_message_to_host(b'\x00\x00\x01\x00\x05\x00\x00')==b'\xa1\x03\x00\x00\x01\x00\x05\x00\x00')

# Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | X: 0 | Y: 0 | Wheel: 1
print(m.filter_message_to_host(b'\x00\x00\x00\x00\x00\x00\x01')==b'\xa1\x03\x00\x00\x00\x00\x00\x00\x01')

# Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | X: 0 | Y: 0 | Wheel: -1
print(m.filter_message_to_host(b'\x00\x00\x00\x00\x00\x00\xff')==b'\xa1\x03\x00\x00\x00\x00\x00\x00\xff')

# Button: 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 | X: 0 | Y: 0 | Wheel: 0
print(m.filter_message_to_host(b'\x05\x00\x00\x00\x00\x00\x00')==b'\xa1\x03\x05\x00\x00\x00\x00\x00\x00')


#G502 mouse test
# Button: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | X: -1 | Y: -13 | Wheel: 0 | AC Pan: 0
print(g.filter_message_to_host(b'\x00\x00\xff\xff\xf3\xff\x00\x00')==b'\xa1\x03\x00\x00\xff\xff\xf3\xff\x00')

#MX510 mouse test
from bitarray import bitarray
from bitarray.util import ba2int

# Button: 0 0 0 0 0 0 0 0 | # | 0xff000040: 23 , 12 | Wheel: 0 | X: 23 | Y: 12
#00 17 0c 00 17 c0 00
print(mx.filter_message_to_host(b'\x00\x17\x0c\x00\x17\xc0\x00')==b'\xa1\x03\x00\x00\x17\x00\x0c\x00\x00')


# Button: 0 0 0 0 0 0 0 0 | # | 0xff000040: 15 , -42 | Wheel: 0 | X: 15 | Y: -42
#00 0f d6 00 0f 60 fd
print(mx.filter_message_to_host(b'\x00\x0f\xd6\x00\x0f\x60\xfd')==b'\xa1\x03\x00\x00\x0f\x00\xd6\xff\x00')


# Button: 0 0 0 0 0 0 0 0 | # | 0xff000040: -7 , 18 | Wheel: 0 | X: -7 | Y: 18
#00 f9 12 00 f9 2f 01
print(mx.filter_message_to_host(b'\x00\xf9\x12\x00\xf9\x2f\x01')==b'\xa1\x03\x00\x00\xf9\xff\x12\x00\x00')

# Button: 1 1 0 0 0 0 0 0 | # | 0xff000040: 0 , 0 | Wheel: 0 | X: 0 | Y: 0
#03 00 00 00 00 00 00
print(mx.filter_message_to_host(b'\x03\x00\x00\x00\x00\x00\x00')==b'\xa1\x03\x03\x00\x00\x00\x00\x00\x00')

# Button: 0 0 0 0 0 0 0 0 | # | 0xff000040: 0 , 0 | Wheel: -1 | X: 0 | Y: 0
#00 00 00 ff 00 00 00
print(mx.filter_message_to_host(b'\x00\x00\x00\xff\x00\x00\x00')==b'\xa1\x03\x00\x00\x00\x00\x00\x00\xff')
2 changes: 1 addition & 1 deletion sdp/sdp_record.xml
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
<sequence>
<sequence>
<uint8 value="0x22" />
<text encoding="hex" value="05010906a1018501050719e029e715002501750195088102950175088103950575010508190129059102950175039103950675081500256d05071900296d8100c0050C0901A1018502050C150025017501950709B509B609B709CD09E209E909EA810295018101C005010902a1010901a100850305091901290815002501950875018102950081030600ff0940950275081581257f8102050109381581257f750895018106093009311601f826ff07750c95028106c0c0"/>
<text encoding="hex" value="05010906a1018501050719e029e715002501750195088102950175088103950575010508190129059102950175039103950675081500256d05071900296d8100c0050C0901A1018502050C150025017501950709B509B609B709CD09E209E909EA810295018101C005010902a1010901a10005091901291015002501951075018102050116018026ff7f751095020930093181061581257f7508950109388106c0c0"/>
</sequence>
</sequence>
</attribute>
Expand Down

0 comments on commit 4168f4d

Please sign in to comment.