Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Wayland support by providing evdev and libinput backends #71

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

Game4Move78
Copy link

@Game4Move78 Game4Move78 commented Feb 6, 2025

This PR introduces Wayland support by adding evdev and libinput backends as alternatives to pynput, which only supports X11 and XWayland (docs). These alternatives should provide Wayland support if run as root or with the appropriate group permissions. Works for evdev and a placeholder for libinput.
Changes:

  • Added evdev backend: Bypassing the compositor to handle input events generated in the kernel (works)
  • Added libinput backend: I have not tested this, and am not sure when/if it restricted by the compositor.

Related to issue ActivityWatch/aw-watcher-input#25.


Important

Add Wayland support with evdev and libinput backends, updating build and configuration files for optional evdev support.

  • Behavior:
    • Adds Wayland support with evdev and libinput backends in listeners_evdev.py and listeners_libinput.py.
    • evdev backend is functional and tested; libinput backend is untested.
    • listeners.py updated to select backend based on USE_EVDEV and USE_LIBINPUT environment variables.
  • Build System:
    • Makefile updated to include POETRY_EXTRAS for evdev support.
    • pyproject.toml updated with optional evdev dependency and extras configuration.
  • Misc:
    • Introduces evdev_devices.py for device detection.
    • Adds listeners_pynput.py to separate pynput backend logic.

This description was created by Ellipsis for 47a5f10. It will automatically update as commits are pushed.

Copy link

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ Changes requested. Reviewed everything up to 47a5f10 in 2 minutes and 4 seconds

More details
  • Looked at 770 lines of code in 7 files
  • Skipped 1 files when reviewing.
  • Skipped posting 9 drafted comments based on config settings.
1. Makefile:14
  • Draft comment:
    Ensure 'make typecheck' is intentional in test target; consider whether typechecking should block tests.
  • Reason this comment was not posted:
    Comment was not on a location in the diff, so it can't be submitted as a review comment.
2. aw_watcher_afk/evdev_devices.py:9
  • Draft comment:
    Consider documenting the rationale behind the chosen required keys for keyboard identification.
  • Reason this comment was not posted:
    Confidence changes required: 50% <= threshold 50%
    None
3. aw_watcher_afk/listeners.py:1
  • Draft comment:
    Remove duplicate module docstring; only one docstring is needed at the top.
  • Reason this comment was not posted:
    Comment was not on a location in the diff, so it can't be submitted as a review comment.
4. aw_watcher_afk/listeners_libinput.py:37
  • Draft comment:
    Hardcoding 'seat0' in udev_assign_seat may not be flexible; consider parameterizing or documenting the assumption.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 20% vs. threshold = 50%
    This is a new file, so the comment is about changed code. The suggestion to parameterize 'seat0' could be valid, but without understanding libinput's seat system and whether other values are common/possible, I can't be certain this is actually an issue. The code may work fine with 'seat0' in 99% of cases. Making it configurable adds complexity that may not be needed.
    I don't have enough context about libinput's seat system to know if this is actually a problem. The current implementation might be the standard approach.
    While parameterization could add flexibility, we shouldn't suggest changes without strong evidence that the current approach is problematic.
    Delete the comment since we don't have strong evidence that hardcoding 'seat0' is actually problematic in practice.
5. Makefile:9
  • Draft comment:
    Consider conditionally including the '--extras' flag only when extras are non‐empty; passing an empty string may cause unexpected behavior in some poetry versions.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 20% vs. threshold = 50%
    The comment raises a reasonable concern about poetry's behavior with empty extras. However, poetry's CLI is well-designed and should handle empty extras gracefully. Without specific evidence of which poetry versions have this issue or concrete examples of the "unexpected behavior", this feels speculative. The current code is simple and clear.
    I could be wrong about poetry's handling of empty extras - there might be real issues in some versions that I'm not aware of.
    While possible, we shouldn't make code more complex based on speculative issues. The comment doesn't provide evidence of actual problems.
    Delete this comment as it suggests a change based on speculative issues without concrete evidence of problems.
6. aw_watcher_afk/evdev_devices.py:1
  • Draft comment:
    Consider adding docstrings to functions (e.g. is_keyboard, is_mouse) to improve code readability and maintainability.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50%
    None
7. aw_watcher_afk/listeners.py:1
  • Draft comment:
    Remove duplicate module docstring to avoid redundancy.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50%
    None
8. aw_watcher_afk/listeners_pynput.py:87
  • Draft comment:
    Consider ensuring thread safety for the mutable 'self.pos' used in on_move; although pynput listeners are often single-threaded, clarifying concurrency assumptions may prevent future issues.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50%
    None
9. pyproject.toml:22
  • Draft comment:
    Consider adding documentation (e.g., in the README) about the optional 'use_evdev' extra dependency and how to enable it.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50%
    None

Workflow ID: wflow_O50oMvMhQYWqukxJ


Want Ellipsis to fix these issues? Tag @ellipsis-dev in a comment. You can customize Ellipsis with 👍 / 👎 feedback, review rules, user-specific overrides, quiet mode, and more.

def _create_tasks(self, loop):
"""Schedule a read loop for all relevant devices"""
devices = list(self._find_devices())
assert len(devices), "You may need to add your user to the 'input' group"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The assert on device list length is helpful; consider handling no-device case more gracefully than assertion in production.


def start(self):
from pynput import keyboard
def use_evdev():
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency, consider using the provided 'env_true' helper function in use_evdev() and use_libinput() instead of directly comparing os.getenv values.

aw_watcher_afk/listeners_evdev.py Show resolved Hide resolved
aw_watcher_afk/listeners_libinput.py Show resolved Hide resolved
Copy link

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ Changes requested. Reviewed everything up to 47a5f10 in 2 minutes and 4 seconds

More details
  • Looked at 770 lines of code in 7 files
  • Skipped 1 files when reviewing.
  • Skipped posting 9 drafted comments based on config settings.
1. Makefile:14
  • Draft comment:
    Ensure 'make typecheck' is intentional in test target; consider whether typechecking should block tests.
  • Reason this comment was not posted:
    Comment was not on a location in the diff, so it can't be submitted as a review comment.
2. aw_watcher_afk/evdev_devices.py:9
  • Draft comment:
    Consider documenting the rationale behind the chosen required keys for keyboard identification.
  • Reason this comment was not posted:
    Confidence changes required: 50% <= threshold 50%
    None
3. aw_watcher_afk/listeners.py:1
  • Draft comment:
    Remove duplicate module docstring; only one docstring is needed at the top.
  • Reason this comment was not posted:
    Comment was not on a location in the diff, so it can't be submitted as a review comment.
4. aw_watcher_afk/listeners_libinput.py:37
  • Draft comment:
    Hardcoding 'seat0' in udev_assign_seat may not be flexible; consider parameterizing or documenting the assumption.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 20% vs. threshold = 50%
    This is a new file, so the comment is about changed code. The suggestion to parameterize 'seat0' could be valid, but without understanding libinput's seat system and whether other values are common/possible, I can't be certain this is actually an issue. The code may work fine with 'seat0' in 99% of cases. Making it configurable adds complexity that may not be needed.
    I don't have enough context about libinput's seat system to know if this is actually a problem. The current implementation might be the standard approach.
    While parameterization could add flexibility, we shouldn't suggest changes without strong evidence that the current approach is problematic.
    Delete the comment since we don't have strong evidence that hardcoding 'seat0' is actually problematic in practice.
5. Makefile:9
  • Draft comment:
    Consider conditionally including the '--extras' flag only when extras are non‐empty; passing an empty string may cause unexpected behavior in some poetry versions.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 20% vs. threshold = 50%
    The comment raises a reasonable concern about poetry's behavior with empty extras. However, poetry's CLI is well-designed and should handle empty extras gracefully. Without specific evidence of which poetry versions have this issue or concrete examples of the "unexpected behavior", this feels speculative. The current code is simple and clear.
    I could be wrong about poetry's handling of empty extras - there might be real issues in some versions that I'm not aware of.
    While possible, we shouldn't make code more complex based on speculative issues. The comment doesn't provide evidence of actual problems.
    Delete this comment as it suggests a change based on speculative issues without concrete evidence of problems.
6. aw_watcher_afk/evdev_devices.py:1
  • Draft comment:
    Consider adding docstrings to functions (e.g. is_keyboard, is_mouse) to improve code readability and maintainability.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50%
    None
7. aw_watcher_afk/listeners.py:1
  • Draft comment:
    Remove duplicate module docstring to avoid redundancy.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50%
    None
8. aw_watcher_afk/listeners_pynput.py:87
  • Draft comment:
    Consider ensuring thread safety for the mutable 'self.pos' used in on_move; although pynput listeners are often single-threaded, clarifying concurrency assumptions may prevent future issues.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50%
    None
9. pyproject.toml:22
  • Draft comment:
    Consider adding documentation (e.g., in the README) about the optional 'use_evdev' extra dependency and how to enable it.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50%
    None

Workflow ID: wflow_O50oMvMhQYWqukxJ


Want Ellipsis to fix these issues? Tag @ellipsis-dev in a comment. You can customize Ellipsis with 👍 / 👎 feedback, review rules, user-specific overrides, quiet mode, and more.

def _create_tasks(self, loop):
"""Schedule a read loop for all relevant devices"""
devices = list(self._find_devices())
assert len(devices), "You may need to add your user to the 'input' group"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The assert on device list length is helpful; consider handling no-device case more gracefully than assertion in production.


def start(self):
from pynput import keyboard
def use_evdev():
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency, consider using the provided 'env_true' helper function in use_evdev() and use_libinput() instead of directly comparing os.getenv values.


async for event in dev.async_read_loop():
# logger.debug(f"Evdev event ({dev.name}): {evdev.categorize(event)}")
if event.type == ecodes.EV_KEY and event.value == 1:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding error handling (or logging) for device disconnections inside the async read loop to prevent silent failures.

threading.Thread(target=self._listen, daemon=True).start()

def _listen(self):
for event in self.libinput_context.get_event():
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrap event processing in a try/except block to safeguard against unexpected libinput errors that could terminate the listening thread.

(Pulled in by pynput on Linux anyway)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant