EventGhost/EventGhost

View on GitHub
plugins/SmallPcRemote/__init__.py

Summary

Maintainability
B
6 hrs
Test Coverage
# -*- coding: utf-8 -*-
#
# This file is a plugin for EventGhost.
# Copyright © 2005-2020 EventGhost Project <http://www.eventghost.net/>
#
# EventGhost is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 2 of the License, or (at your option)
# any later version.
#
# EventGhost is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with EventGhost. If not, see <http://www.gnu.org/licenses/>.

ur"""<rst>
Plugin for some small no-name USB-PC-Remote from China.
"""

import eg

eg.RegisterPlugin(
    name = "Small PC-Remote",
    author = "Bitmonster",
    version = "1.0.0",
    kind = "remote",
    guid = "{B7440E71-AE2F-4928-9270-5728E81FED5B}",
    description = __doc__,
    hardwareId = "USB\\VID_073A&PID_2230",
)

from math import atan2, pi

# the first byte of every code chain identifies the length of the chain
LENGTHES = {
    1: 3,
    2: 4,
    3: 3,
    4: 3,
    5: 4,
    6: 3,
}

CODES = {
    (6, 129, 0): (0, 'Power', 3),
    (3, 138, 1): (3, 'eMail', 3),
    (3, 35, 2): (3, 'WWW', 3),
    (1, 4, 61): (3, 'Close', 3),
    (1, 5, 4): (17, 'A', 10),
    (1, 5, 5): (17, 'B', 10),
    (1, 5, 6): (17, 'C', 10),
    (1, 5, 7): (17, 'D', 10),
    (3, 182, 0): (3, 'PreviousTrack', 3),
    (3, 181, 0): (3, 'NextTrack', 3),
    (3, 203, 0): (10, 'FastRewind', 13),
    (3, 202, 0): (10, 'FastForward', 13),
    (3, 205, 0): (3, 'Play', 3),
    (3, 183, 0): (3, 'Stop', 3),
    (3, 48, 2): (15, 'Fullscreen', 9),
    (3, 226, 0): (3, 'Mute', 3),
    (3, 234, 0): (0, 'VolumeDown', 3),
    (3, 233, 0): (0, 'VolumeUp', 3),
    (1, 0, 42): (0, 'Backspace', 3),
    (1, 0, 75): (0, 'PageUp', 3),
    (1, 0, 78): (0, 'PageDown', 3),
    (1, 8, 8): (3, 'MyPc', 3),
    (1, 8, 7): (3, 'Desktop', 3),
    (1, 0, 43): (0, 'Tab', 3),
    (5, 0, 42, 30): (4, 'Tab', 4),
    (5, 0, 42, 54): (4, 'Tab', 4),
    (5, 0, 42, 55): (4, 'Tab', 4),
    (5, 2, 42, 56): (4, 'Tab', 4),
    (5, 0, 0, 54): (4, 'Tab', 4),
    (1, 0, 82): (0, 'Up', 3),
    (5, 0, 0, 4): (4, 'Up', 4),
    (5, 0, 42, 5): (4, 'Up', 4),
    (5, 0, 42, 6): (4, 'Up', 4),
    (5, 0, 42, 31): (4, 'Up', 4),
    (5, 0, 42, 4): (4, 'Up', 4),
    (5, 2, 42, 4): (4, 'Up', 4),
    (5, 2, 42, 5): (4, 'Up', 4),
    (5, 2, 42, 6): (4, 'Up', 4),
    (5, 2, 0, 4): (4, 'Up', 4),
    (1, 8, 0): (3, 'Start', 3),
    (5, 0, 0, 7): (4, 'Start', 4),
    (5, 0, 42, 8): (4, 'Start', 4),
    (5, 0, 42, 9): (4, 'Start', 4),
    (5, 0, 42, 32): (4, 'Start', 4),
    (5, 0, 42, 7): (4, 'Start', 4),
    (5, 2, 0, 7): (4, 'Start', 4),
    (5, 2, 42, 7): (4, 'Start', 4),
    (5, 2, 42, 8): (4, 'Start', 4),
    (5, 2, 42, 9): (4, 'Start', 4),
    (1, 0, 80): (0, 'Left', 3),
    (5, 0, 0, 10): (4, 'Left', 4),
    (5, 0, 42, 10): (4, 'Left', 4),
    (5, 0, 42, 11): (4, 'Left', 4),
    (5, 0, 42, 12): (4, 'Left', 4),
    (5, 0, 42, 33): (4, 'Left', 4),
    (5, 2, 0, 10): (4, 'Left', 4),
    (5, 2, 42, 10): (4, 'Left', 4),
    (5, 2, 42, 11): (4, 'Left', 4),
    (5, 2, 42, 12): (4, 'Left', 4),
    (1, 0, 40): (0, 'Ok', 3),
    (5, 0, 0, 13): (4, 'Ok', 4),
    (5, 0, 42, 14): (4, 'Ok', 4),
    (5, 0, 42, 15): (4, 'Ok', 4),
    (5, 0, 42, 34): (4, 'Ok', 4),
    (5, 0, 42, 13): (4, 'Ok', 4),
    (5, 2, 0, 13): (4, 'Ok', 4),
    (5, 2, 42, 13): (4, 'Ok', 4),
    (5, 2, 42, 14): (4, 'Ok', 4),
    (5, 2, 42, 15): (4, 'Ok', 4),
    (1, 0, 79): (0, 'Right', 3),
    (5, 0, 0, 16): (4, 'Right', 4),
    (5, 0, 42, 16): (4, 'Right', 4),
    (5, 0, 42, 17): (4, 'Right', 4),
    (5, 0, 42, 18): (4, 'Right', 4),
    (5, 0, 42, 35): (4, 'Right', 4),
    (5, 2, 0, 16): (4, 'Right', 4),
    (5, 2, 42, 16): (4, 'Right', 4),
    (5, 2, 42, 17): (4, 'Right', 4),
    (5, 2, 42, 18): (4, 'Right', 4),
    (1, 1, 18): (0, 'Open', 3),
    (5, 0, 0, 19): (4, 'Open', 4),
    (5, 0, 42, 19): (4, 'Open', 4),
    (5, 0, 42, 20): (4, 'Open', 4),
    (5, 0, 42, 21): (4, 'Open', 4),
    (5, 0, 42, 22): (4, 'Open', 4),
    (5, 0, 42, 36): (4, 'Open', 4),
    (5, 2, 0, 19): (4, 'Open', 4),
    (5, 2, 42, 19): (4, 'Open', 4),
    (5, 2, 42, 20): (4, 'Open', 4),
    (5, 2, 42, 21): (4, 'Open', 4),
    (5, 2, 42, 22): (4, 'Open', 4),
    (1, 0, 81): (0, 'Down', 3),
    (5, 0, 0, 23): (4, 'Down', 4),
    (5, 0, 42, 23): (4, 'Down', 4),
    (5, 0, 42, 24): (4, 'Down', 4),
    (5, 0, 42, 25): (4, 'Down', 4),
    (5, 0, 42, 37): (4, 'Down', 4),
    (5, 2, 0, 23): (4, 'Down', 4),
    (5, 2, 42, 23): (4, 'Down', 4),
    (5, 2, 42, 24): (4, 'Down', 4),
    (5, 2, 42, 25): (4, 'Down', 4),
    (1, 0, 41): (0, 'Esc', 3),
    (5, 0, 0, 26): (4, 'Esc', 4),
    (5, 0, 42, 26): (4, 'Esc', 4),
    (5, 0, 42, 27): (4, 'Esc', 4),
    (5, 0, 42, 28): (4, 'Esc', 4),
    (5, 0, 42, 29): (4, 'Esc', 4),
    (5, 0, 42, 38): (4, 'Esc', 4),
    (5, 2, 0, 26): (4, 'Esc', 4),
    (5, 2, 42, 26): (4, 'Esc', 4),
    (5, 2, 42, 27): (4, 'Esc', 4),
    (5, 2, 42, 28): (4, 'Esc', 4),
    (5, 2, 42, 29): (4, 'Esc', 4),
    (1, 4, 43): (3, 'SwitchWindows', 3),
    (5, 0, 0, 44): (4, 'SwitchWindows', 4),
    (5, 2, 42, 31): (4, 'SwitchWindows', 4),
    (5, 2, 42, 37): (4, 'SwitchWindows', 4),
    (5, 2, 42, 32): (4, 'SwitchWindows', 4),
    (5, 0, 42, 39): (4, 'SwitchWindows', 4),
    (5, 0, 42, 44): (4, 'SwitchWindows', 4),
}


class SmallPcRemote(eg.PluginBase):

    def __start__(self):
        self.buf = []
        self.lastDirection = None
        self.lastMouseState = 0
        self.stopCodeLength = 0
        self.bytesToIgnore = 0
        self.winUsb = eg.WinUsb(self)
        self.winUsb.Device(self.Callback, 1).AddHardwareId(
            "PC Remote Controller", "USB\\VID_073A&PID_2230"
        )
        self.winUsb.Start()
        self.timer = eg.ResettableTimer(self.OnTimeOut)


    def __stop__(self):
        self.timer.Stop()
        self.winUsb.Stop()


    def Callback(self, data):
        buf = self.buf
        buf.append(data[0])
        first = buf[0]
        if first not in LENGTHES:
            del buf[:]
            return
        if len(buf) < LENGTHES[first]:
            return
        try:
            if first == 2:
                mButton, x, y = buf[1:4]
                if mButton != self.lastMouseState:
                    self.lastMouseState = mButton
                    if mButton == 32:
                        self.TriggerEnduringEvent("LeftMouseButton")
                    elif mButton == 64:
                        self.TriggerEnduringEvent("RightMouseButton")
                    else:
                        self.EndLastEvent()
                if x != 0 or y != 0:
                    if x > 127:
                        x -= 256
                    if y > 127:
                        y -= 256
                    degree = (round((atan2(x, -y) / pi) * 180)) % 360
                    if self.lastDirection != degree:
                        self.TriggerEnduringEvent(
                            "MouseDirection.%03d" % degree
                        )
                        self.lastDirection = degree
                    self.timer.Reset(75)
                return

            if self.bytesToIgnore:
                self.bytesToIgnore -= len(buf)
                if self.bytesToIgnore < 0:
                    self.bytesToIgnore = 0
                return

            if self.stopCodeLength:
                self.stopCodeLength -= len(buf)
                if self.stopCodeLength <= 0:
                    self.EndLastEvent()
                    self.stopCodeLength = 0
                return

            if buf == [1, 0, 0]:
                self.TriggerEvent("NumLock")
                return

            if buf == [1, 3, 0]:
                return

            data = CODES.get(tuple(buf), None)
            if data:
                self.bytesToIgnore, eventname, self.stopCodeLength = data
                self.TriggerEnduringEvent(eventname)
            else:
                self.EndLastEvent()
                self.bytesToIgnore = 0
                self.stopCodeLength = 0
                self.lastDirection = None
                self.PrintError("Unknown code %r received." % buf)
        finally:
            del buf[:]


    def OnTimeOut(self):
        self.EndLastEvent()
        self.lastDirection = None