device: improve imports in logitech_receiver
device: move some imports to top of modules device: break up imports loop with device descriptors device: break up imports loop by moving a function from notifications.py to setting_templates.py device: break import loop between device.py and diversion.py by using device to access method
This commit is contained in:
parent
008d3df50b
commit
31d795fcb8
|
@ -33,13 +33,57 @@ import hidapi as _hid
|
|||
from . import hidpp10 as _hidpp10
|
||||
from . import hidpp20 as _hidpp20
|
||||
from .base_usb import ALL as _RECEIVER_USB_IDS
|
||||
from .base_usb import DEVICES as _DEVICE_IDS
|
||||
from .base_usb import other_device_check as _other_device_check
|
||||
from .common import KwException as _KwException
|
||||
from .common import strhex as _strhex
|
||||
from .descriptors import DEVICES as _DEVICES
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
_wired_device = lambda product_id, interface: {
|
||||
'vendor_id': 0x046d,
|
||||
'product_id': product_id,
|
||||
'bus_id': 0x3,
|
||||
'usb_interface': interface,
|
||||
'isDevice': True
|
||||
}
|
||||
|
||||
_bt_device = lambda product_id: {'vendor_id': 0x046d, 'product_id': product_id, 'bus_id': 0x5, 'isDevice': True}
|
||||
|
||||
DEVICE_IDS = []
|
||||
|
||||
for _ignore, d in _DEVICES.items():
|
||||
if d.usbid:
|
||||
DEVICE_IDS.append(_wired_device(d.usbid, d.interface if d.interface else 2))
|
||||
if d.btid:
|
||||
DEVICE_IDS.append(_bt_device(d.btid))
|
||||
|
||||
|
||||
def other_device_check(bus_id, vendor_id, product_id):
|
||||
"""Check whether product is a Logitech USB-connected or Bluetooth device based on bus, vendor, and product IDs
|
||||
This allows Solaar to support receiverless HID++ 2.0 devices that it knows nothing about"""
|
||||
if vendor_id != 0x46d: # Logitech
|
||||
return
|
||||
if bus_id == 0x3: # USB
|
||||
if (product_id >= 0xC07D and product_id <= 0xC094 or product_id >= 0xC32B and product_id <= 0xC344):
|
||||
return _wired_device(product_id, 2)
|
||||
elif bus_id == 0x5: # Bluetooth
|
||||
if (product_id >= 0xB012 and product_id <= 0xB0FF or product_id >= 0xB317 and product_id <= 0xB3FF):
|
||||
return _bt_device(product_id)
|
||||
|
||||
|
||||
def product_information(usb_id):
|
||||
if isinstance(usb_id, str):
|
||||
usb_id = int(usb_id, 16)
|
||||
for r in _RECEIVER_USB_IDS:
|
||||
if usb_id == r.get('product_id'):
|
||||
return r
|
||||
return {}
|
||||
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
|
@ -122,13 +166,13 @@ def filter(bus_id, vendor_id, product_id, hidpp_short=False, hidpp_long=False):
|
|||
record = filter_receivers(bus_id, vendor_id, product_id, hidpp_short, hidpp_long)
|
||||
if record: # known or unknown receiver
|
||||
return record
|
||||
for record in _DEVICE_IDS: # known devices
|
||||
for record in DEVICE_IDS: # known devices
|
||||
if match(record, bus_id, vendor_id, product_id):
|
||||
return record
|
||||
if hidpp_short or hidpp_long: # unknown devices that use HID++
|
||||
return {'vendor_id': vendor_id, 'product_id': product_id, 'bus_id': bus_id, 'isDevice': True}
|
||||
elif hidpp_short is None and hidpp_long is None: # unknown devices in correct range of IDs
|
||||
return _other_device_check(bus_id, vendor_id, product_id)
|
||||
return other_device_check(bus_id, vendor_id, product_id)
|
||||
|
||||
|
||||
def receivers_and_devices():
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
# USB ids of Logitech wireless receivers.
|
||||
# Only receivers supporting the HID++ protocol can go in here.
|
||||
|
||||
from .descriptors import DEVICES as _DEVICES
|
||||
from .i18n import _
|
||||
|
||||
# max_devices is only used for receivers that do not support reading from _R.receiver_info offset 0x03, default to 1
|
||||
|
@ -206,45 +205,4 @@ ALL = (
|
|||
EX100_27MHZ_RECEIVER_C517,
|
||||
)
|
||||
|
||||
_wired_device = lambda product_id, interface: {
|
||||
'vendor_id': 0x046d,
|
||||
'product_id': product_id,
|
||||
'bus_id': 0x3,
|
||||
'usb_interface': interface,
|
||||
'isDevice': True
|
||||
}
|
||||
|
||||
_bt_device = lambda product_id: {'vendor_id': 0x046d, 'product_id': product_id, 'bus_id': 0x5, 'isDevice': True}
|
||||
|
||||
DEVICES = []
|
||||
|
||||
for _ignore, d in _DEVICES.items():
|
||||
if d.usbid:
|
||||
DEVICES.append(_wired_device(d.usbid, d.interface if d.interface else 2))
|
||||
if d.btid:
|
||||
DEVICES.append(_bt_device(d.btid))
|
||||
|
||||
|
||||
def other_device_check(bus_id, vendor_id, product_id):
|
||||
"""Check whether product is a Logitech USB-connected or Bluetooth device based on bus, vendor, and product IDs
|
||||
This allows Solaar to support receiverless HID++ 2.0 devices that it knows nothing about"""
|
||||
if vendor_id != 0x46d: # Logitech
|
||||
return
|
||||
if bus_id == 0x3: # USB
|
||||
if (product_id >= 0xC07D and product_id <= 0xC094 or product_id >= 0xC32B and product_id <= 0xC344):
|
||||
return _wired_device(product_id, 2)
|
||||
elif bus_id == 0x5: # Bluetooth
|
||||
if (product_id >= 0xB012 and product_id <= 0xB0FF or product_id >= 0xB317 and product_id <= 0xB3FF):
|
||||
return _bt_device(product_id)
|
||||
|
||||
|
||||
def product_information(usb_id):
|
||||
if isinstance(usb_id, str):
|
||||
usb_id = int(usb_id, 16)
|
||||
for r in ALL:
|
||||
if usb_id == r.get('product_id'):
|
||||
return r
|
||||
return {}
|
||||
|
||||
|
||||
del _DRIVER, _unifying_receiver, _nano_receiver, _lenovo_receiver, _lightspeed_receiver
|
||||
|
|
|
@ -24,10 +24,6 @@
|
|||
# - the device uses a USB interface other than 2
|
||||
# - the name or codename should be different from what the device reports
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
from . import settings_templates as _ST
|
||||
from .common import NamedInts as _NamedInts
|
||||
from .hidpp10 import DEVICE_KIND as _DK
|
||||
from .hidpp10 import REGISTERS as _R
|
||||
|
||||
|
@ -35,11 +31,32 @@ from .hidpp10 import REGISTERS as _R
|
|||
#
|
||||
#
|
||||
|
||||
_DeviceDescriptor = namedtuple(
|
||||
'_DeviceDescriptor',
|
||||
('name', 'kind', 'wpid', 'codename', 'protocol', 'registers', 'settings', 'usbid', 'interface', 'btid')
|
||||
)
|
||||
del namedtuple
|
||||
|
||||
class _DeviceDescriptor:
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name=None,
|
||||
kind=None,
|
||||
wpid=None,
|
||||
codename=None,
|
||||
protocol=None,
|
||||
registers=None,
|
||||
usbid=None,
|
||||
interface=None,
|
||||
btid=None
|
||||
):
|
||||
self.name = name
|
||||
self.kind = kind
|
||||
self.wpid = wpid
|
||||
self.codename = codename
|
||||
self.protocol = protocol
|
||||
self.registers = registers
|
||||
self.usbid = usbid
|
||||
self.interface = interface
|
||||
self.btid = btid
|
||||
self.settings = None
|
||||
|
||||
|
||||
DEVICES_WPID = {}
|
||||
DEVICES = {}
|
||||
|
@ -57,7 +74,6 @@ def _D(
|
|||
interface=None,
|
||||
btid=None,
|
||||
):
|
||||
|
||||
if kind is None:
|
||||
kind = (
|
||||
_DK.mouse if 'Mouse' in name else _DK.keyboard if 'Keyboard' in name else _DK.numpad
|
||||
|
@ -83,7 +99,6 @@ def _D(
|
|||
codename=codename,
|
||||
protocol=protocol,
|
||||
registers=registers,
|
||||
settings=settings,
|
||||
usbid=usbid,
|
||||
interface=interface,
|
||||
btid=btid
|
||||
|
@ -157,13 +172,13 @@ def get_btid(btid):
|
|||
# The 'protocol' and 'wpid' fields are optional (they can be discovered at
|
||||
# runtime), but specifying them here speeds up device discovery and reduces the
|
||||
# USB traffic Solaar has to do to fully identify peripherals.
|
||||
# Same goes for HID++ 2.0 feature settings (like _feature_fn_swap).
|
||||
#
|
||||
# The 'registers' field indicates read-only registers, specifying a state. These
|
||||
# are valid (AFAIK) only to HID++ 1.0 devices.
|
||||
# The 'settings' field indicates a read/write register; based on them Solaar
|
||||
# generates, at runtime, the settings controls in the device panel. HID++ 1.0
|
||||
# devices may only have register-based settings; HID++ 2.0 devices may only have
|
||||
# generates, at runtime, the settings controls in the device panel.
|
||||
# Solaar now sets up this field in settings_templates.py to eliminate a imports loop.
|
||||
# HID++ 1.0 devices may only have register-based settings; HID++ 2.0 devices may only have
|
||||
# feature-based settings.
|
||||
|
||||
# Devices are organized by kind
|
||||
|
@ -175,40 +190,38 @@ def get_btid(btid):
|
|||
|
||||
_D('Wireless Keyboard EX110', codename='EX110', protocol=1.0, wpid='0055', registers=(_R.battery_status, ))
|
||||
_D('Wireless Keyboard S510', codename='S510', protocol=1.0, wpid='0056', registers=(_R.battery_status, ))
|
||||
_D('Wireless Wave Keyboard K550', codename='K550', protocol=1.0, wpid='0060', registers=(_R.battery_status, ),
|
||||
settings=[_ST.RegisterFnSwap])
|
||||
_D('Wireless Wave Keyboard K550', codename='K550', protocol=1.0, wpid='0060', registers=(_R.battery_status, ))
|
||||
_D('Wireless Keyboard EX100', codename='EX100', protocol=1.0, wpid='0065', registers=(_R.battery_status, ))
|
||||
_D('Wireless Keyboard MK300', codename='MK300', protocol=1.0, wpid='0068', registers=(_R.battery_status, ))
|
||||
_D('Number Pad N545', codename='N545', protocol=1.0, wpid='2006', registers=(_R.battery_status, ))
|
||||
_D('Wireless Compact Keyboard K340', codename='K340', protocol=1.0, wpid='2007', registers=(_R.battery_status, ))
|
||||
_D('Wireless Keyboard MK700', codename='MK700', protocol=1.0, wpid='2008',
|
||||
registers=(_R.battery_status, ), settings=[_ST.RegisterFnSwap])
|
||||
registers=(_R.battery_status, ))
|
||||
_D('Wireless Wave Keyboard K350', codename='K350', protocol=1.0, wpid='200A', registers=(_R.battery_status, ))
|
||||
_D('Wireless Keyboard MK320', codename='MK320', protocol=1.0, wpid='200F', registers=(_R.battery_status, ))
|
||||
_D('Wireless Illuminated Keyboard K800', codename='K800', protocol=1.0, wpid='2010',
|
||||
registers=(_R.battery_status, _R.three_leds), settings=[_ST.RegisterFnSwap, _ST.RegisterHandDetection])
|
||||
_D('Wireless Keyboard K520', codename='K520', protocol=1.0, wpid='2011',
|
||||
registers=(_R.battery_status, ), settings=[_ST.RegisterFnSwap])
|
||||
_D('Wireless Solar Keyboard K750', codename='K750', protocol=2.0, wpid='4002', settings=[_ST.FnSwap])
|
||||
registers=(_R.battery_status, _R.three_leds))
|
||||
_D('Wireless Keyboard K520', codename='K520', protocol=1.0, wpid='2011', registers=(_R.battery_status, ))
|
||||
_D('Wireless Solar Keyboard K750', codename='K750', protocol=2.0, wpid='4002')
|
||||
_D('Wireless Keyboard K270 (unifying)', codename='K270', protocol=2.0, wpid='4003')
|
||||
_D('Wireless Keyboard K360', codename='K360', protocol=2.0, wpid='4004', settings=[_ST.FnSwap])
|
||||
_D('Wireless Keyboard K360', codename='K360', protocol=2.0, wpid='4004')
|
||||
_D('Wireless Keyboard K230', codename='K230', protocol=2.0, wpid='400D')
|
||||
_D('Wireless Touch Keyboard K400', codename='K400', protocol=2.0, wpid=('400E', '4024'), settings=[_ST.FnSwap])
|
||||
_D('Wireless Keyboard MK270', codename='MK270', protocol=2.0, wpid='4023', settings=[_ST.FnSwap])
|
||||
_D('Illuminated Living-Room Keyboard K830', codename='K830', protocol=2.0, wpid='4032', settings=[_ST.NewFnSwap])
|
||||
_D('Wireless Touch Keyboard K400', codename='K400', protocol=2.0, wpid=('400E', '4024'))
|
||||
_D('Wireless Keyboard MK270', codename='MK270', protocol=2.0, wpid='4023')
|
||||
_D('Illuminated Living-Room Keyboard K830', codename='K830', protocol=2.0, wpid='4032')
|
||||
_D('Wireless Touch Keyboard K400 Plus', codename='K400 Plus', protocol=2.0, wpid='404D')
|
||||
_D('Wireless Multi-Device Keyboard K780', codename='K780', protocol=4.5, wpid='405B', settings=[_ST.NewFnSwap])
|
||||
_D('Wireless Keyboard K375s', codename='K375s', protocol=2.0, wpid='4061', settings=[_ST.K375sFnSwap])
|
||||
_D('Wireless Multi-Device Keyboard K780', codename='K780', protocol=4.5, wpid='405B')
|
||||
_D('Wireless Keyboard K375s', codename='K375s', protocol=2.0, wpid='4061')
|
||||
_D('Craft Advanced Keyboard', codename='Craft', protocol=4.5, wpid='4066', btid=0xB350)
|
||||
_D('Wireless Illuminated Keyboard K800 new', codename='K800 new', protocol=4.5, wpid='406E', settings=[_ST.FnSwap])
|
||||
_D('Wireless Keyboard K470', codename='K470', protocol=4.5, wpid='4075', settings=[_ST.FnSwap])
|
||||
_D('Wireless Illuminated Keyboard K800 new', codename='K800 new', protocol=4.5, wpid='406E')
|
||||
_D('Wireless Keyboard K470', codename='K470', protocol=4.5, wpid='4075')
|
||||
_D('MX Keys Keyboard', codename='MX Keys', protocol=4.5, wpid='408A', btid=0xB35B)
|
||||
_D('G915 TKL LIGHTSPEED Wireless RGB Mechanical Gaming Keyboard', codename='G915 TKL', protocol=4.2, wpid='408E', usbid=0xC343)
|
||||
_D('Illuminated Keyboard', codename='Illuminated', protocol=1.0, usbid=0xc318, interface=1, settings=[_ST.RegisterFnSwap])
|
||||
_D('Illuminated Keyboard', codename='Illuminated', protocol=1.0, usbid=0xc318, interface=1)
|
||||
_D('G213 Prodigy Gaming Keyboard', codename='G213', usbid=0xc336, interface=1)
|
||||
_D('G512 RGB Mechanical Gaming Keyboard', codename='G512', usbid=0xc33c, interface=1)
|
||||
_D('G815 Mechanical Keyboard', codename='G815', usbid=0xc33f, interface=1)
|
||||
_D('diNovo Edge Keyboard', codename='diNovo', protocol=1.0, wpid='C714', settings=[_ST.RegisterFnSwap])
|
||||
_D('diNovo Edge Keyboard', codename='diNovo', protocol=1.0, wpid='C714')
|
||||
_D('K845 Mechanical Keyboard', codename='K845', usbid=0xc341, interface=3)
|
||||
|
||||
# Mice
|
||||
|
@ -229,41 +242,25 @@ _D('MX Air', codename='MX Air', protocol=1.0, kind=_DK.mouse, wpid=('1007', '100
|
|||
_D('MX Revolution', codename='MX Revolution', protocol=1.0, kind=_DK.mouse, wpid=('1008', '100C'),
|
||||
registers=(_R.battery_charge, ))
|
||||
_D('MX620 Laser Cordless Mouse', codename='MX620', protocol=1.0, wpid=('100A', '1016'), registers=(_R.battery_charge, ))
|
||||
_D('VX Nano Cordless Laser Mouse', codename='VX Nano', protocol=1.0, wpid=('100B', '100F'),
|
||||
registers=(_R.battery_charge, ), settings=[_ST.RegisterSmoothScroll, _ST.RegisterSideScroll])
|
||||
_D('VX Nano Cordless Laser Mouse', codename='VX Nano', protocol=1.0, wpid=('100B', '100F'), registers=(_R.battery_charge, ))
|
||||
_D('V450 Nano Cordless Laser Mouse', codename='V450 Nano', protocol=1.0, wpid='1011', registers=(_R.battery_charge, ))
|
||||
_D('V550 Nano Cordless Laser Mouse', codename='V550 Nano', protocol=1.0, wpid='1013',
|
||||
registers=(_R.battery_charge, ), settings=[_ST.RegisterSmoothScroll, _ST.RegisterSideScroll, ])
|
||||
_D('V550 Nano Cordless Laser Mouse', codename='V550 Nano', protocol=1.0, wpid='1013', registers=(_R.battery_charge, ))
|
||||
_D('MX 1100 Cordless Laser Mouse', codename='MX 1100', protocol=1.0, kind=_DK.mouse, wpid='1014',
|
||||
registers=(_R.battery_charge, ), settings=[_ST.RegisterSmoothScroll, _ST.RegisterSideScroll])
|
||||
_D('Anywhere Mouse MX', codename='Anywhere MX', protocol=1.0, wpid='1017',
|
||||
registers=(_R.battery_charge, ), settings=[_ST.RegisterSmoothScroll, _ST.RegisterSideScroll])
|
||||
|
||||
|
||||
class _PerformanceMXDpi(_ST.RegisterDpi):
|
||||
choices_universe = _NamedInts.range(0x81, 0x8F, lambda x: str((x - 0x80) * 100))
|
||||
validator_options = {'choices': choices_universe}
|
||||
|
||||
|
||||
_D('Performance Mouse MX', codename='Performance MX', protocol=1.0, wpid='101A',
|
||||
registers=(_R.battery_status, _R.three_leds),
|
||||
settings=[_PerformanceMXDpi, _ST.RegisterSmoothScroll, _ST.RegisterSideScroll])
|
||||
_D('Marathon Mouse M705 (M-R0009)', codename='M705 (M-R0009)', protocol=1.0, wpid='101B',
|
||||
registers=(_R.battery_charge, ), settings=[_ST.RegisterSmoothScroll, _ST.RegisterSideScroll])
|
||||
registers=(_R.battery_charge, ))
|
||||
_D('Anywhere Mouse MX', codename='Anywhere MX', protocol=1.0, wpid='1017', registers=(_R.battery_charge, ))
|
||||
_D('Performance Mouse MX', codename='Performance MX', protocol=1.0, wpid='101A', registers=(_R.battery_status, _R.three_leds))
|
||||
_D('Marathon Mouse M705 (M-R0009)', codename='M705 (M-R0009)', protocol=1.0, wpid='101B', registers=(_R.battery_charge, ))
|
||||
_D('Wireless Mouse M350', codename='M350', protocol=1.0, wpid='101C', registers=(_R.battery_charge, ))
|
||||
_D('Wireless Mouse M505', codename='M505/B605', protocol=1.0, wpid='101D',
|
||||
registers=(_R.battery_charge, ), settings=[_ST.RegisterSmoothScroll, _ST.RegisterSideScroll])
|
||||
_D('Wireless Mouse M305', codename='M305', protocol=1.0, wpid='101F',
|
||||
registers=(_R.battery_status, ), settings=[_ST.RegisterSideScroll])
|
||||
_D('Wireless Mouse M505', codename='M505/B605', protocol=1.0, wpid='101D', registers=(_R.battery_charge, ))
|
||||
_D('Wireless Mouse M305', codename='M305', protocol=1.0, wpid='101F', registers=(_R.battery_status, ))
|
||||
_D('Wireless Mouse M215', codename='M215', protocol=1.0, wpid='1020')
|
||||
_D('G700 Gaming Mouse', codename='G700', protocol=1.0, wpid='1023', usbid=0xc06b, interface=1,
|
||||
registers=(_R.battery_status, _R.three_leds,), settings=[_ST.RegisterSmoothScroll, _ST.RegisterSideScroll])
|
||||
registers=(_R.battery_status, _R.three_leds,))
|
||||
_D('Wireless Mouse M310', codename='M310', protocol=1.0, wpid='1024', registers=(_R.battery_status, ))
|
||||
_D('Wireless Mouse M510', codename='M510', protocol=1.0, wpid='1025',
|
||||
registers=(_R.battery_status, ), settings=[_ST.RegisterSideScroll])
|
||||
_D('Wireless Mouse M510', codename='M510', protocol=1.0, wpid='1025', registers=(_R.battery_status, ))
|
||||
_D('Fujitsu Sonic Mouse', codename='Sonic', protocol=1.0, wpid='1029')
|
||||
_D('G700s Gaming Mouse', codename='G700s', protocol=1.0, wpid='102A', usbid=0xc07c, interface=1,
|
||||
registers=(_R.battery_status, _R.three_leds,), settings=[_ST.RegisterSmoothScroll, _ST.RegisterSideScroll])
|
||||
registers=(_R.battery_status, _R.three_leds,))
|
||||
_D('Couch Mouse M515', codename='M515', protocol=2.0, wpid='4007')
|
||||
_D('Wireless Mouse M175', codename='M175', protocol=2.0, wpid='4008')
|
||||
_D('Wireless Mouse M325', codename='M325', protocol=2.0, wpid='400A')
|
||||
|
@ -274,24 +271,20 @@ _D('Touch Mouse M600', codename='M600', protocol=2.0, wpid='401A')
|
|||
_D('Wireless Mouse M150', codename='M150', protocol=2.0, wpid='4022')
|
||||
_D('Wireless Mouse M185', codename='M185', protocol=2.0, wpid='4038')
|
||||
_D('Wireless Mouse MX Master', codename='MX Master', protocol=4.5, wpid='4041', btid=0xb012)
|
||||
_D('Anywhere Mouse MX 2', codename='Anywhere MX 2', protocol=4.5, wpid='404A', settings=[_ST.HiresSmoothInvert])
|
||||
_D('Anywhere Mouse MX 2', codename='Anywhere MX 2', protocol=4.5, wpid='404A')
|
||||
_D('Wireless Mouse M510', codename='M510v2', protocol=2.0, wpid='4051')
|
||||
_D('Wireless Mouse M185 new', codename='M185n', protocol=4.5, wpid='4054')
|
||||
_D('Wireless Mouse M185/M235/M310', codename='M185/M235/M310', protocol=4.5, wpid='4055')
|
||||
_D('Wireless Mouse MX Master 2S', codename='MX Master 2S', protocol=4.5, wpid='4069', btid=0xb019,
|
||||
settings=[_ST.HiresSmoothInvert])
|
||||
_D('Wireless Mouse MX Master 2S', codename='MX Master 2S', protocol=4.5, wpid='4069', btid=0xb019)
|
||||
_D('Multi Device Silent Mouse M585/M590', codename='M585/M590', protocol=4.5, wpid='406B')
|
||||
_D('Marathon Mouse M705 (M-R0073)', codename='M705 (M-R0073)', protocol=4.5, wpid='406D',
|
||||
settings=[_ST.HiresSmoothInvert, _ST.PointerSpeed])
|
||||
_D('Marathon Mouse M705 (M-R0073)', codename='M705 (M-R0073)', protocol=4.5, wpid='406D',)
|
||||
_D('MX Vertical Wireless Mouse', codename='MX Vertical', protocol=4.5, wpid='407B', btid=0xb020, usbid=0xc08a)
|
||||
_D('Wireless Mouse Pebble M350', codename='Pebble', protocol=2.0, wpid='4080')
|
||||
_D('MX Master 3 Wireless Mouse', codename='MX Master 3', protocol=4.5, wpid='4082', btid=0xb023)
|
||||
_D('PRO X Wireless', kind='mouse', codename='PRO X', wpid='4093', usbid=0xc094)
|
||||
|
||||
_D('G9 Laser Mouse', codename='G9', usbid=0xc048, interface=1, protocol=1.0,
|
||||
settings=[_PerformanceMXDpi, _ST.RegisterSmoothScroll, _ST.RegisterSideScroll])
|
||||
_D('G9x Laser Mouse', codename='G9x', usbid=0xc066, interface=1, protocol=1.0,
|
||||
settings=[_PerformanceMXDpi, _ST.RegisterSmoothScroll, _ST.RegisterSideScroll])
|
||||
_D('G9 Laser Mouse', codename='G9', usbid=0xc048, interface=1, protocol=1.0)
|
||||
_D('G9x Laser Mouse', codename='G9x', usbid=0xc066, interface=1, protocol=1.0)
|
||||
_D('G502 Gaming Mouse', codename='G502', usbid=0xc07d, interface=1)
|
||||
_D('G402 Gaming Mouse', codename='G402', usbid=0xc07e, interface=1)
|
||||
_D('G900 Chaos Spectrum Gaming Mouse', codename='G900', usbid=0xc081)
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
import errno as _errno
|
||||
import logging
|
||||
import threading as _threading
|
||||
import time
|
||||
|
||||
from typing import Optional
|
||||
|
||||
|
@ -107,7 +108,6 @@ class Device:
|
|||
self.handle = _base.open_path(self.path) if self.path else None
|
||||
except Exception: # maybe the device wasn't set up
|
||||
try:
|
||||
import time
|
||||
time.sleep(1)
|
||||
self.handle = _base.open_path(self.path) if self.path else None
|
||||
except Exception: # give up
|
||||
|
@ -170,8 +170,7 @@ class Device:
|
|||
# may be a 2.0 device; if not, it will fix itself later
|
||||
self.features = _hidpp20.FeaturesArray(self)
|
||||
|
||||
@classmethod
|
||||
def find(self, serial):
|
||||
def find(self, serial): # find a device by serial number or unit ID
|
||||
assert serial, 'need serial number or unit ID to find a device'
|
||||
result = None
|
||||
for device in Device.instances:
|
||||
|
|
|
@ -43,7 +43,6 @@ from yaml import dump_all as _yaml_dump_all
|
|||
from yaml import safe_load_all as _yaml_safe_load_all
|
||||
|
||||
from .common import NamedInt
|
||||
from .device import Device as _Device
|
||||
from .hidpp20 import FEATURE as _F
|
||||
from .special_keys import CONTROL as _CONTROL
|
||||
|
||||
|
@ -749,7 +748,7 @@ class Setting(Condition):
|
|||
logger.debug('evaluate condition: %s', self)
|
||||
if len(self.args) < 3:
|
||||
return None
|
||||
dev = _Device.find(self.args[0]) if self.args[0] is not None else device
|
||||
dev = device.find(self.args[0]) if self.args[0] is not None else device
|
||||
if dev is None:
|
||||
logger.warning('Setting condition: device %s is not known', self.args[0])
|
||||
return False
|
||||
|
@ -1040,7 +1039,7 @@ class Active(Condition):
|
|||
def evaluate(self, feature, notification, device, status, last_result):
|
||||
if logger.isEnabledFor(logging.DEBUG):
|
||||
logger.debug('evaluate condition: %s', self)
|
||||
dev = _Device.find(self.devID)
|
||||
dev = device.find(self.devID)
|
||||
return bool(dev and dev.ping())
|
||||
|
||||
def data(self):
|
||||
|
@ -1294,7 +1293,7 @@ class Set(Action):
|
|||
return None
|
||||
if logger.isEnabledFor(logging.INFO):
|
||||
logger.info('Set action: %s', self.args)
|
||||
dev = _Device.find(self.args[0]) if self.args[0] is not None else device
|
||||
dev = device.find(self.args[0]) if self.args[0] is not None else device
|
||||
if dev is None:
|
||||
logger.warning('Set action: device %s is not known', self.args[0])
|
||||
return None
|
||||
|
|
|
@ -454,7 +454,7 @@ def _process_feature_notification(device, status, n, feature):
|
|||
if (n.address == 0x00):
|
||||
profile_sector = _unpack('!H', n.data[:2])[0]
|
||||
if profile_sector:
|
||||
profile_change(device, profile_sector)
|
||||
_st.profile_change(device, profile_sector)
|
||||
elif (n.address == 0x10):
|
||||
resolution_index = _unpack('!B', n.data[:1])[0]
|
||||
profile_sector = _unpack('!H', device.feature_request(_F.ONBOARD_PROFILES, 0x40)[:2])[0]
|
||||
|
@ -465,15 +465,3 @@ def _process_feature_notification(device, status, n, feature):
|
|||
|
||||
_diversion.process_notification(device, status, n, feature)
|
||||
return True
|
||||
|
||||
|
||||
# change UI to show result of onboard profile change
|
||||
def profile_change(device, profile_sector):
|
||||
from solaar.ui.config_panel import record_setting # prevent circular import
|
||||
record_setting(device, _st.OnboardProfiles, [profile_sector])
|
||||
for profile in device.profiles.profiles.values() if device.profiles else []:
|
||||
if profile.sector == profile_sector:
|
||||
resolution_index = profile.resolution_default_index
|
||||
record_setting(device, _st.AdjustableDpi, [profile.resolutions[resolution_index]])
|
||||
record_setting(device, _st.ReportRate, [profile.report_rate])
|
||||
break
|
||||
|
|
|
@ -23,7 +23,7 @@ import hidapi as _hid
|
|||
|
||||
from . import base as _base
|
||||
from . import hidpp10 as _hidpp10
|
||||
from .base_usb import product_information as _product_information
|
||||
from .base import product_information as _product_information
|
||||
from .common import strhex as _strhex
|
||||
from .device import Device
|
||||
|
||||
|
|
|
@ -17,19 +17,24 @@
|
|||
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
import logging
|
||||
import socket as _socket
|
||||
|
||||
from logging import WARN as _WARN
|
||||
from struct import pack as _pack
|
||||
from struct import unpack as _unpack
|
||||
from time import time as _time
|
||||
from traceback import format_exc as _format_exc
|
||||
|
||||
from . import descriptors as _descriptors
|
||||
from . import hidpp10 as _hidpp10
|
||||
from . import hidpp20 as _hidpp20
|
||||
from . import special_keys as _special_keys
|
||||
from .base import _HIDPP_Notification as _HIDPP_Notification
|
||||
from .common import NamedInt as _NamedInt
|
||||
from .common import NamedInts as _NamedInts
|
||||
from .common import bytes2int as _bytes2int
|
||||
from .common import int2bytes as _int2bytes
|
||||
from .diversion import process_notification as _process_notification
|
||||
from .i18n import _
|
||||
from .settings import KIND as _KIND
|
||||
from .settings import ActionSettingRW as _ActionSettingRW
|
||||
|
@ -187,12 +192,34 @@ class RegisterFnSwap(FnSwapVirtual):
|
|||
validator_options = {'true_value': b'\x00\x01', 'mask': b'\x00\x01'}
|
||||
|
||||
|
||||
class FnSwap(FnSwapVirtual):
|
||||
feature = _F.FN_INVERSION
|
||||
class _PerformanceMXDpi(RegisterDpi):
|
||||
choices_universe = _NamedInts.range(0x81, 0x8F, lambda x: str((x - 0x80) * 100))
|
||||
validator_options = {'choices': choices_universe}
|
||||
|
||||
|
||||
class NewFnSwap(FnSwapVirtual):
|
||||
feature = _F.NEW_FN_INVERSION
|
||||
# set up register settings for devices - this is done here to break up an import loop
|
||||
_descriptors.get_wpid('0060').settings = [RegisterFnSwap]
|
||||
_descriptors.get_wpid('2008').settings = [RegisterFnSwap]
|
||||
_descriptors.get_wpid('2010').settings = [RegisterFnSwap, RegisterHandDetection]
|
||||
_descriptors.get_wpid('2011').settings = [RegisterFnSwap]
|
||||
_descriptors.get_usbid(0xc318).settings = [RegisterFnSwap]
|
||||
_descriptors.get_wpid('C714').settings = [RegisterFnSwap]
|
||||
_descriptors.get_wpid('100B').settings = [RegisterSmoothScroll, RegisterSideScroll]
|
||||
_descriptors.get_wpid('100F').settings = [RegisterSmoothScroll, RegisterSideScroll]
|
||||
_descriptors.get_wpid('1013').settings = [RegisterSmoothScroll, RegisterSideScroll]
|
||||
_descriptors.get_wpid('1014').settings = [RegisterSmoothScroll, RegisterSideScroll]
|
||||
_descriptors.get_wpid('1017').settings = [RegisterSmoothScroll, RegisterSideScroll]
|
||||
_descriptors.get_wpid('1023').settings = [RegisterSmoothScroll, RegisterSideScroll]
|
||||
_descriptors.get_wpid('4004').settings = [_PerformanceMXDpi, RegisterSmoothScroll, RegisterSideScroll]
|
||||
_descriptors.get_wpid('101A').settings = [_PerformanceMXDpi, RegisterSmoothScroll, RegisterSideScroll]
|
||||
_descriptors.get_wpid('101B').settings = [RegisterSmoothScroll, RegisterSideScroll]
|
||||
_descriptors.get_wpid('101D').settings = [RegisterSmoothScroll, RegisterSideScroll]
|
||||
_descriptors.get_wpid('101F').settings = [RegisterSideScroll]
|
||||
_descriptors.get_usbid(0xc06b).settings = [RegisterSmoothScroll, RegisterSideScroll]
|
||||
_descriptors.get_wpid('1025').settings = [RegisterSideScroll]
|
||||
_descriptors.get_wpid('102A').settings = [RegisterSmoothScroll, RegisterSideScroll]
|
||||
_descriptors.get_usbid(0xc048).settings = [_PerformanceMXDpi, RegisterSmoothScroll, RegisterSideScroll]
|
||||
_descriptors.get_usbid(0xc066).settings = [_PerformanceMXDpi, RegisterSmoothScroll, RegisterSideScroll]
|
||||
|
||||
|
||||
# ignore the capabilities part of the feature - all devices should be able to swap Fn state
|
||||
|
@ -203,6 +230,14 @@ class K375sFnSwap(FnSwapVirtual):
|
|||
validator_options = {'true_value': b'\x01', 'false_value': b'\x00', 'read_skip_byte_count': 1}
|
||||
|
||||
|
||||
class FnSwap(FnSwapVirtual):
|
||||
feature = _F.FN_INVERSION
|
||||
|
||||
|
||||
class NewFnSwap(FnSwapVirtual):
|
||||
feature = _F.NEW_FN_INVERSION
|
||||
|
||||
|
||||
class Backlight(_Setting):
|
||||
name = 'backlight-qualitative'
|
||||
label = _('Backlight')
|
||||
|
@ -441,6 +476,18 @@ class ThumbInvert(_Setting):
|
|||
validator_options = {'true_value': b'\x00\x01', 'false_value': b'\x00\x00', 'mask': b'\x00\x01'}
|
||||
|
||||
|
||||
# change UI to show result of onboard profile change
|
||||
def profile_change(device, profile_sector):
|
||||
from solaar.ui.config_panel import record_setting # prevent circular import
|
||||
record_setting(device, OnboardProfiles, [profile_sector])
|
||||
for profile in device.profiles.profiles.values() if device.profiles else []:
|
||||
if profile.sector == profile_sector:
|
||||
resolution_index = profile.resolution_default_index
|
||||
record_setting(device, AdjustableDpi, [profile.resolutions[resolution_index]])
|
||||
record_setting(device, ReportRate, [profile.report_rate])
|
||||
break
|
||||
|
||||
|
||||
class OnboardProfiles(_Setting):
|
||||
name = 'onboard_profiles'
|
||||
label = _('Onboard Profiles')
|
||||
|
@ -466,13 +513,12 @@ class OnboardProfiles(_Setting):
|
|||
return b'\x00\x00'
|
||||
|
||||
def write(self, device, data_bytes):
|
||||
from . import notifications as _notifications # prevent circular import
|
||||
if data_bytes == b'\x00\x00':
|
||||
result = device.feature_request(_F.ONBOARD_PROFILES, 0x10, b'\x02')
|
||||
else:
|
||||
device.feature_request(_F.ONBOARD_PROFILES, 0x10, b'\x01')
|
||||
result = device.feature_request(_F.ONBOARD_PROFILES, 0x30, data_bytes)
|
||||
_notifications.profile_change(device, _bytes2int(data_bytes))
|
||||
profile_change(device, _bytes2int(data_bytes))
|
||||
return result
|
||||
|
||||
class validator_class(_ChoicesV):
|
||||
|
@ -798,8 +844,6 @@ class MouseGesturesXY(_RawXYProcessing):
|
|||
def release_action(self):
|
||||
if self.fsmState == 'pressed':
|
||||
# emit mouse gesture notification
|
||||
from .base import _HIDPP_Notification as _HIDPP_Notification
|
||||
from .diversion import process_notification as _process_notification
|
||||
self.push_mouse_event()
|
||||
if logger.isEnabledFor(logging.INFO):
|
||||
logger.info('mouse gesture notification %s', self.data)
|
||||
|
@ -1098,8 +1142,7 @@ class ChangeHost(_Setting):
|
|||
hostNames = _hidpp20.get_host_names(device)
|
||||
hostNames = hostNames if hostNames is not None else {}
|
||||
if currentHost not in hostNames or hostNames[currentHost][1] == '':
|
||||
import socket # find name of current host and use it
|
||||
hostNames[currentHost] = (True, socket.gethostname().partition('.')[0])
|
||||
hostNames[currentHost] = (True, _socket.gethostname().partition('.')[0])
|
||||
choices = _NamedInts()
|
||||
for host in range(0, numHosts):
|
||||
paired, hostName = hostNames.get(host, (True, ''))
|
||||
|
@ -1533,8 +1576,7 @@ def check_feature(device, sclass):
|
|||
logger.debug('check_feature %s [%s] detected %s', sclass.name, sclass.feature, detected)
|
||||
return detected
|
||||
except Exception as e:
|
||||
from traceback import format_exc
|
||||
logger.error('check_feature %s [%s] error %s\n%s', sclass.name, sclass.feature, e, format_exc())
|
||||
logger.error('check_feature %s [%s] error %s\n%s', sclass.name, sclass.feature, e, _format_exc())
|
||||
return False # differentiate from an error-free determination that the setting is not supported
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue