chore(repo): baseline du fork input-remapper (upstream v2.2.1)
Le dépôt ne contenait que README.md ; ajout de l'intégralité du code fonctionnel du fork comme socle stable de la branche de release. L'état runtime d'orchestration (.ideai/) est exclu du suivi. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
172
inputremapper/logging/logger.py
Normal file
172
inputremapper/logging/logger.py
Normal file
@ -0,0 +1,172 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# input-remapper - GUI for device specific keyboard mappings
|
||||
# Copyright (C) 2025 sezanzeb <b8x45ygc9@mozmail.com>
|
||||
#
|
||||
# This file is part of input-remapper.
|
||||
#
|
||||
# input-remapper 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# input-remapper 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 input-remapper. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
"""Logging setup for input-remapper."""
|
||||
|
||||
from __future__ import annotations # needed for the TYPE_CHECKING import
|
||||
|
||||
import logging
|
||||
import time
|
||||
from typing import cast, Type, TYPE_CHECKING, List, Tuple
|
||||
from evdev.ecodes import EV_ABS, EV_KEY, EV_REL, ABS_HAT0X, ABS_HAT0Y
|
||||
|
||||
from inputremapper.input_event import InputEvent
|
||||
from inputremapper.logging.formatter import ColorfulFormatter
|
||||
from inputremapper.installation_info import VERSION, COMMIT_HASH
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from inputremapper.injection.mapping_handler import MappingHandler
|
||||
|
||||
|
||||
start = time.time()
|
||||
|
||||
|
||||
class Logger(logging.Logger):
|
||||
previous_abs_rel_log_time = 0.0
|
||||
previous_write_debug_log = None
|
||||
analog_log_threshold = 0.1 # s
|
||||
|
||||
def debug_mapping_handler(self, mapping_handler: MappingHandler) -> None:
|
||||
"""Parse the structure of a mapping_handler and log it."""
|
||||
if not self.isEnabledFor(logging.DEBUG):
|
||||
return
|
||||
|
||||
lines_and_indent = self._build_mapping_handler_description_tree(mapping_handler)
|
||||
for line in lines_and_indent:
|
||||
indent = " "
|
||||
msg = indent * line[1] + line[0]
|
||||
self._log(logging.DEBUG, msg, args=())
|
||||
|
||||
def write(self, key, uinput) -> None:
|
||||
"""Log that an event is being written
|
||||
|
||||
Parameters
|
||||
----------
|
||||
key
|
||||
anything that can be string formatted, but usually a tuple of
|
||||
(type, code, value) tuples
|
||||
"""
|
||||
# pylint: disable=protected-access
|
||||
if not self.isEnabledFor(logging.DEBUG):
|
||||
return
|
||||
|
||||
if isinstance(key, InputEvent):
|
||||
if key.type not in [EV_ABS, EV_REL, EV_KEY]:
|
||||
return
|
||||
|
||||
# Avoid spaming the terminal with tons of high-resolution logs
|
||||
now = time.time()
|
||||
if key.type in [EV_ABS, EV_REL] and key.code not in [ABS_HAT0X, ABS_HAT0Y]:
|
||||
if now - self.previous_abs_rel_log_time < self.analog_log_threshold:
|
||||
return
|
||||
|
||||
self.previous_abs_rel_log_time = now
|
||||
|
||||
str_key = repr(key)
|
||||
str_key = str_key.replace(",)", ")")
|
||||
|
||||
msg = f'Writing {str_key} to "{uinput.name}"'
|
||||
|
||||
if msg == self.previous_write_debug_log:
|
||||
# avoid some spam
|
||||
return
|
||||
|
||||
self.previous_write_debug_log = msg
|
||||
|
||||
self._log(logging.DEBUG, msg, args=(), stacklevel=2)
|
||||
|
||||
def _build_mapping_handler_description_tree(
|
||||
self,
|
||||
mapping_handler: MappingHandler,
|
||||
indent=0,
|
||||
) -> List[Tuple[str, int]]:
|
||||
lines_and_indent = [
|
||||
(str(mapping_handler), indent),
|
||||
]
|
||||
|
||||
mapping_handlers = mapping_handler.get_children()
|
||||
for sub_handler in mapping_handlers:
|
||||
sub_list = self._build_mapping_handler_description_tree(
|
||||
sub_handler, indent + 1
|
||||
)
|
||||
lines_and_indent.extend(sub_list)
|
||||
|
||||
return lines_and_indent
|
||||
|
||||
def is_debug(self) -> bool:
|
||||
"""True, if the logger is currently in DEBUG mode."""
|
||||
return self.level <= logging.DEBUG
|
||||
|
||||
def log_info(self, name: str = "input-remapper") -> None:
|
||||
"""Log version and name to the console."""
|
||||
logger.info(
|
||||
"%s %s %s https://github.com/sezanzeb/input-remapper",
|
||||
name,
|
||||
VERSION,
|
||||
COMMIT_HASH,
|
||||
)
|
||||
|
||||
if EVDEV_VERSION:
|
||||
logger.info("python-evdev %s", EVDEV_VERSION)
|
||||
|
||||
if self.is_debug():
|
||||
logger.warning(
|
||||
"Debug level will log all your keystrokes! Do not post this "
|
||||
"output in the internet if you typed in sensitive or private "
|
||||
"information with your device!"
|
||||
)
|
||||
|
||||
def update_verbosity(self, debug: bool) -> None:
|
||||
"""Set the logging verbosity according to the settings object."""
|
||||
if debug:
|
||||
self.setLevel(logging.DEBUG)
|
||||
else:
|
||||
self.setLevel(logging.INFO)
|
||||
|
||||
for handler in self.handlers:
|
||||
handler.setFormatter(ColorfulFormatter(debug))
|
||||
|
||||
@classmethod
|
||||
def bootstrap_logger(cls: Type[Logger]) -> Logger:
|
||||
# https://github.com/python/typeshed/issues/1801
|
||||
logging.setLoggerClass(cls)
|
||||
logger = cast(Logger, logging.getLogger("input-remapper"))
|
||||
|
||||
handler = logging.StreamHandler()
|
||||
handler.setFormatter(ColorfulFormatter(False))
|
||||
logger.addHandler(handler)
|
||||
logger.setLevel(logging.INFO)
|
||||
logging.getLogger("asyncio").setLevel(logging.WARNING)
|
||||
return logger
|
||||
|
||||
|
||||
logger = Logger.bootstrap_logger()
|
||||
|
||||
|
||||
EVDEV_VERSION = None
|
||||
try:
|
||||
from importlib.metadata import version
|
||||
|
||||
EVDEV_VERSION = version("evdev")
|
||||
except Exception as error:
|
||||
logger.info("Could not figure out the evdev version")
|
||||
logger.debug(error)
|
||||
|
||||
# check if the version is something like 1.5.0-beta or 1.5.0-beta.5
|
||||
IS_BETA = "beta" in VERSION
|
||||
Reference in New Issue
Block a user