diff options
| -rw-r--r-- | consumer.py | 24 | ||||
| -rwxr-xr-x | interfaces/desktopEvent.py | 3 | ||||
| -rwxr-xr-x | interfaces/endpoint.py | 2 | ||||
| -rwxr-xr-x | macropad.pyw | 50 | ||||
| -rw-r--r-- | socketserver.py | 35 | ||||
| -rw-r--r-- | win32.py | 6 | ||||
| -rw-r--r-- | xlib.py | 14 | 
7 files changed, 65 insertions, 69 deletions
| diff --git a/consumer.py b/consumer.py index 9e36dd0..31fd581 100644 --- a/consumer.py +++ b/consumer.py @@ -1,20 +1,22 @@ -from typing import Dict
 +import time
 +import abc
 +from threading import Thread
 +from queue import Queue, Empty, Full
  from zope import component, interface
 +from interfaces import endpoint, configuration
 +from interfaces.configuration import IConfiguration
  from interfaces.message import ISocketMessage, Debug
  @interface.implementer(ISocketMessage)
 -class Mapping(object):
 +class Mapping():
      """ Send an event requesting a layer change to the endpoint.
      """
      def __init__(self, message):
          self.content = {"layer": message}
 -import abc
 -from threading import Thread
 -from queue import Queue, Empty, Full
  class EventConsummer(Thread, metaclass=abc.ABCMeta):
      """ Thread processing messages. This class does nothing and is intended to
 @@ -65,9 +67,6 @@ class EventConsummer(Thread, metaclass=abc.ABCMeta):              except Full:
                  component.handle(Debug("Ignoring event: queue is full"))
 -import time
 -from interfaces import endpoint, configuration
 -from interfaces.configuration import IConfiguration
  class SocketMessageConsumer(EventConsummer):
      """ Provide a handler consuming events and sending them to the endpoint.
 @@ -128,8 +127,7 @@ class SocketMessageConsumer(EventConsummer):          configuration = component.getUtility(IConfiguration)
          if isinstance(mapping, dict):
              self._endpoint.send(mapping)
 -        elif isinstance(data, str):
 -            # TODO Query the json from the configuration
 +        elif isinstance(mapping, str):
              layer = configuration.get(mapping, None)
              if layer is not None:
                  self._endpoint.send(layer)
 @@ -137,7 +135,9 @@ class SocketMessageConsumer(EventConsummer):          if name is not None:
              # We received a name to associate the configuration with.
              # Register the element in the configuration
 -            # TODO use an event
              configuration[name] = mapping
              for key in mapping.keys():
 -              component.handle(Debug("Associating %s with %s" % (name, key)))
 +                # We do not want to log the keycode sent to the keyboard, only
 +                # the name is interresting. We are supposed to have only one, but
 +                # it’s the easer way to log it
 +                component.handle(Debug(f"Associating {name} with {key}"))
 diff --git a/interfaces/desktopEvent.py b/interfaces/desktopEvent.py index e8a30a4..9030ccd 100755 --- a/interfaces/desktopEvent.py +++ b/interfaces/desktopEvent.py @@ -4,10 +4,9 @@ from zope.interface import Attribute  class IDesktop(interface.Interface):
 -    queue = Attribute("""The queue to send the message""")
      mapping = Attribute("""Correspondance between application and layer""")
 -    def getForegroundWindowTitle(sel) -> Optional[str]:
 +    def getForegroundWindowTitle(self) -> Optional[str]:
          """ Return the name of the selected window
          """
 diff --git a/interfaces/endpoint.py b/interfaces/endpoint.py index 4da7c57..2f3af95 100755 --- a/interfaces/endpoint.py +++ b/interfaces/endpoint.py @@ -5,7 +5,6 @@ from zope.interface import Attribute  class IEndpoint(interface.Interface):
 -    queue = Attribute("""The queue to send the message""")
      state = Attribute("""The connection status""")
      def isConnected(self) ->  bool:
 @@ -59,7 +58,6 @@ class EndPoint(object):      def __init__(self, connection):
          self.connection = connection
 -        self.queue = None
          self.state = self.STATE_DISCONNECTED
      def isConnected(self) -> bool:
 diff --git a/macropad.pyw b/macropad.pyw index c7e8770..6e4f922 100755 --- a/macropad.pyw +++ b/macropad.pyw @@ -1,41 +1,33 @@  #!/usr/bin/env python3 -import serial - +import threading +from os import path  import tkinter as tk  from tkinter import Text +import configparser +from sys import platform +  import pystray  from pystray import MenuItem as item -from PIL import Image, ImageTk -from typing import Dict -import threading -import sys +from PIL import Image  from zope import component  import interfaces -from interfaces import endpoint, configuration +from interfaces import endpoint  from interfaces.message import IMessage, Debug -import configparser +import consumer +from configuration import Mapping + -from os import path  script_path = path.dirname(path.realpath(__file__))  config_file = path.join(script_path, "config.ini")  config = configparser.ConfigParser(delimiters="=")  config.read(config_file) -from collections import OrderedDict - -from configuration import Mapping
 -mapping = Mapping(config)
 - - -from queue import Queue -q = Queue() - -component.provideAdapter(interfaces.endpoint.EndPoint) +mapping = Mapping(config)  component.provideUtility(mapping, interfaces.configuration.IConfiguration)  # @@ -45,14 +37,17 @@ component.provideUtility(mapping, interfaces.configuration.IConfiguration)  #  # How to connect to the peripherical  # +component.provideAdapter(interfaces.endpoint.EndPoint)  if config.has_section("connection.serial"):      from serial_conn import SerialConnection -    endpoint = component.queryAdapter(SerialConnection(config["connection.serial"]), endpoint.IEndpoint) +    endpoint = component.queryAdapter( +            SerialConnection(config["connection.serial"]), endpoint.IEndpoint)  elif config.has_section("connection.socket"):      from socket_conn import SocketConnection -    endpoint = component.queryAdapter(SocketConnection(config["connection.socket"]), endpoint.IEndpoint) +    endpoint = component.queryAdapter( +            SocketConnection(config["connection.socket"]), endpoint.IEndpoint)  component.provideUtility(endpoint, interfaces.endpoint.IEndpoint)  endpoint.connect() @@ -64,16 +59,15 @@ if config.has_section("socket.serve"):  else:      server = None -import consumer  handler = consumer.SocketMessageConsumer()  handler.start() -class Icon(object): +class Icon():      def __init__(self, image):          menu=( -                item('Quit', self.quit_window),  +                item('Quit', self.quit_window),                  item('Show', self.show_window, default=True),                  item('Reset',self.reset),              ) @@ -106,7 +100,7 @@ class Icon(object):      def reset(self):          mapping.reset() -class Application(object): +class Application():      def __init__(self):          # Override the default function called when exception are reported @@ -142,7 +136,6 @@ class Application(object):      def connect_desktop(self):          """ Launch the thread listening events from the desktop          """ -        from sys import platform          component.handle(Debug(platform))          if platform == "win32":              import win32 @@ -167,7 +160,7 @@ class Application(object):          self.window.destroy()          component.queryUtility(interfaces.desktopEvent.IDesktop).stop()          return -                 +      def hide(self):          self.icon.show_hide.clear()          self.visible = False @@ -204,7 +197,8 @@ class Application(object):      def exec(self):          try:              self.update() -            if server is not None: server.update() +            if server is not None: +                server.update()          except BaseException as e:              component.handle(Debug( str(e) ))              print(e) diff --git a/socketserver.py b/socketserver.py index eb7d4fc..b2234bc 100644 --- a/socketserver.py +++ b/socketserver.py @@ -18,7 +18,8 @@ from typing import Callable  from zope import component
  from interfaces import desktopEvent
 -from interfaces.message import Debug, ISocketMessage
 +from interfaces.message import Debug
 +from consumer import Mapping # Event used to send the mapping change request
  @dataclass
  class waitEvent:
 @@ -34,9 +35,8 @@ actions = {      "layout" : lambda x : x,
      }
 -from consumer import Mapping # Event used to send the mapping change request
 -class Handler(object):
 +class Handler():
      """ Listen the incomming connexions and dispatch them into the connexion
          object """
 @@ -45,7 +45,7 @@ class Handler(object):          """
          super().__init__()
          self.sel = selectors.DefaultSelector()
 -        component.provideHandler(self.sendMessage)
 +        #component.provideHandler(self.sendMessage)
          self.socket = socket.socket()
          self.socket.bind((configuration["host"], int(configuration["port"])))
 @@ -67,18 +67,18 @@ class Handler(object):          self.connexions = []
 -    @component.adapter(ISocketMessage)
 -    def sendMessage(self, content:ISocketMessage) -> None:
 -        """ Send a message to all the sockets connected to the server
 -        """
 -        c = sendEvent(message = content.content)
 -        c.callback = self._send
 -        map = self.sel.get_map()
 -        for value in list(map.values())[:]:
 -            if value.fileobj == self.socket:
 -                # Ignore the main connexion, keep it only in accept mode.
 -                continue
 -            self.sel.modify(value.fileobj, selectors.EVENT_WRITE, c)
 +    #@component.adapter(ISocketMessage)
 +    #def sendMessage(self, content:ISocketMessage) -> None:
 +    #    """ Send a message to all the sockets connected to the server
 +    #    """
 +    #    c = sendEvent(message = content.content)
 +    #    c.callback = self._send
 +    #    map = self.sel.get_map()
 +    #    for value in list(map.values())[:]:
 +    #        if value.fileobj == self.socket:
 +    #            # Ignore the main connexion, keep it only in accept mode.
 +    #            continue
 +    #        self.sel.modify(value.fileobj, selectors.EVENT_WRITE, c)
      def update(self):
          """ Read the status for all the sockets, if they are available.
 @@ -137,6 +137,7 @@ class Handler(object):      def _send(self:object, conn:socket, mask:int, text) -> None:
          """ Internal method used to dispatch the message to the socket.  """
 +
          try:
              conn.sendall(bytes(text , "utf-8"))
          except:
 @@ -145,5 +146,7 @@ class Handler(object):          self._switch_read(conn)
      def close(self, conn):
 +        """ Close all the existing connexions
 +        """
          self.sel.unregister(conn)
          conn.close()
 @@ -1,6 +1,6 @@ -# Required for the window title name
  from ctypes import wintypes, windll, create_unicode_buffer, WINFUNCTYPE
  from typing import Optional, Dict
 +import sys
  from zope import interface
  from interfaces import desktopEvent
 @@ -113,8 +113,8 @@ class Listener(object):              # Fatal Python error: PyEval_RestoreThread: the function must be
              # called with the GIL held, but the GIL is released (the current
              # Python thread state is NULL)
 -            print("Mapping '%s' to default" % title)
 -            component.handle(Mapping((default, None)))
 +            print(f"Mapping '{title}' to default")
 +            component.handle(Mapping(("default", None)))
      def start(self) -> None:
          self.hookIDs = [setHook(self.WinEventProc, et) for et in eventTypes.keys()]
 @@ -1,24 +1,26 @@ +from threading import Thread
 +
  import Xlib
  import Xlib.display
  from zope import interface
 -from interfaces import desktopEvent
 -from threading import Thread
 -from interfaces.message import IMessage, Debug
  from zope import component
 +from interfaces.message import Debug
 +from interfaces import desktopEvent
  from consumer import Mapping
  @interface.implementer(desktopEvent.IDesktop)
  class Listener(Thread):
      def __init__(self, mapping):
 -        Thread.__init__(self)
 +        super().__init__()
          self.mapping = mapping
          self.active_window = None
          self.last_code = None
          self.running = False
 +        self.daemon = True
      def getForegroundWindowTitle(self):
          """ Return the name of the selected window
 @@ -80,7 +82,7 @@ class Listener(Thread):              found = True
              if code != self.last_code:
 -                component.handle(Debug("Switching to '%s' for '%s'" % (pattern, window_name)))
 +                component.handle(Debug(f"Switching to '{pattern}' for '{window_name}'"))
                  component.handle(Mapping((code, None)))
                  self.last_code = code
              # We found a matching configuration. Even if the match is the
 @@ -96,5 +98,5 @@ class Listener(Thread):              self.last_code = "default"
 -    def stop(self):
 +    def stop(self) -> None:
          self.running = False
 | 
