From bae4e80500b552f7b3658a1a6a158fef02047f58 Mon Sep 17 00:00:00 2001 From: Sébastien Dailly Date: Wed, 7 May 2025 11:31:20 +0200 Subject: Remove the existing handler (and unused) in socketserver --- consumer.py | 24 +++++++++++----------- interfaces/desktopEvent.py | 3 +-- interfaces/endpoint.py | 2 -- macropad.pyw | 50 ++++++++++++++++++++-------------------------- socketserver.py | 35 +++++++++++++++++--------------- win32.py | 6 +++--- 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() diff --git a/win32.py b/win32.py index 1b45a95..c1b0ae3 100644 --- a/win32.py +++ b/win32.py @@ -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()] diff --git a/xlib.py b/xlib.py index 20476aa..d28dfd4 100644 --- a/xlib.py +++ b/xlib.py @@ -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 -- cgit v1.2.3