"""
This module provides the :class:`whad.unifying.connector.mouse.Mouse` class
that behaves like a Logitech Unifying mouse. This class is able to synchronize
with a specific dongle and send valid mouse and wheel moves as well as clicks.
This connector must be used with a compatible Logitech Unifying device.
"""
from whad.device import WhadDevice
from whad.unifying.connector import Unifying
from whad.esb.stack import ESBStack
from whad.unifying.stack import UnifyingApplicativeLayer, UnifyingRole, ClickType
from whad.exceptions import UnsupportedCapability
[docs]
class Mouse(Unifying):
"""
Logitech Unifying Mouse interface for compatible WHAD device.
"""
def __init__(self, device: WhadDevice):
"""Logitech mouse initialisation
:param device: WHAD device
:type device: :class:`whad.device.WhadDevice`
"""
super().__init__(device)
self.__channel = 5
self.__address = "ca:e9:06:ec:a4"
self.__started = False
ESBStack.add(UnifyingApplicativeLayer)
self.__stack = ESBStack(self)
# Check if device can choose its own address
if not self.can_set_node_address():
raise UnsupportedCapability("SetNodeAddress")
# Check if device can perform mouse simulation
if not self.can_be_mouse():
raise UnsupportedCapability("MouseSimulation")
self._enable_role()
[docs]
def lock(self):
"""Lock mouse onto current channel.
"""
return self.__stack.app.lock_channel()
[docs]
def unlock(self):
"""Unlock mouse from current channel.
"""
return self.__stack.app.unlock_channel()
def _enable_role(self):
"""Enable mouse role.
"""
if self.__started:
super().stop()
self.set_node_address(self.__address)
self.enable_mouse_mode(channel=self.__channel)
self.__stack.app.role = UnifyingRole.MOUSE
if self.__started:
super().start()
@property
def channel(self) -> int:
"""Retrieve current channel.
:return: current channel number
:rtype: int
"""
return self.__channel
@channel.setter
def channel(self, channel: int = 5):
"""Select channel.
:param channel: channel to select (0-100)
:type channel: int
"""
self.__channel = channel
self._enable_role()
[docs]
def start(self):
"""Start mouse emulation
"""
self.__started = True
self._enable_role()
[docs]
def stop(self):
"""Stop mouse emulation
"""
self.__started = False
self.unlock()
super().stop()
@property
def stack(self):
return self.__stack
@property
def address(self) -> ESBStack:
"""Retrieve the underlying stack
:return: Underlying ESB stack instance
:rtype: :class:`whad.esb.stack.ESBStack`
"""
return self.__address
@address.setter
def address(self, address: str):
"""Set mouse address
:param address: Mouse ESB address
:type address: str
"""
self.__address = address
self._enable_role()
[docs]
def on_pdu(self, packet):
"""ESB packet handler. Feed the underlying ESB stack.
"""
self.__stack.on_pdu(packet)
[docs]
def synchronize(self, timeout: float = 10.0) -> bool:
"""Synchronize with target mouse.
:param timeout: timeout in seconds
:type timeout: float
:return: ``True`` if synchronization succeeded, ``False`` otherwise
:rtype: bool
"""
return self.__stack.ll.synchronize(timeout=timeout)
[docs]
def move(self, x: int, y: int):
"""Send a move event to the target mouse dongle.
:param x: Delta X in ticks
:type x: int
:param y: Delta Y in ticks
:type y: int
"""
return self.__stack.app.move_mouse(x, y)
[docs]
def left_click(self):
"""Send a left click to the target mouse dongle.
"""
return self.__stack.app.click_mouse(type=ClickType.LEFT)
[docs]
def right_click(self):
"""Send a right click to the target mouse dongle.
"""
return self.__stack.app.click_mouse(type=ClickType.RIGHT)
[docs]
def middle_click(self):
"""Send a middle click to the target mouse dongle.
"""
return self.__stack.app.click_mouse(type=ClickType.MIDDLE)
[docs]
def wheel_up(self):
"""Send a wheel up event to target mouse dongle.
"""
return self.__stack.app.wheel_mouse(x=0, y=1)
[docs]
def wheel_down(self):
"""Send a wheel down event to target mouse dongle.
"""
return self.__stack.app.wheel_mouse(x=0, y=-1)
[docs]
def wheel_right(self):
"""Send a wheel right event to target mouse dongle.
"""
return self.__stack.app.wheel_mouse(x=1, y=0)
[docs]
def wheel_left(self):
"""Send a wheel left event to target mouse dongle.
"""
return self.__stack.app.wheel_mouse(x=-1, y=0)