cecmap 1.0.0
Maps CEC events to arbitrary keybindings for controlling your raspberrypi desktop via TV remote.
License: Unlicense
Requires Python: >=3.7
Keywords: cec keybindings raspberry pi raspberry-pi tv remote control

cecmap
======

Maps CEC events to arbitrary keybindings for controlling your raspberrypi desktop via TV remote.


Install
-------

You can install *cecmap* as user or root:

**as user:**

::

    pip3 install --user cecmap

Also, make sure to add ``~/.local/bin`` to your PATH.


**as root:**

::

    sudo pip3 install cecmap

In order to see notifications when switching modes, it's also necessary to
have a notification daemon installed. I recommend ``xfce4-notifyd``::

    sudo apt install xfce4-notifyd

I also recommend installing an onscreen keyboard, e.g.::

    sudo apt install matchbox-keyboard


Usage
-----

Launch::

    cecmap

    # or:

    python -m cecmap


Running as service
------------------

Enable running at startup::

    systemctl --user enable cecmap

Start as service::

    systemctl --user start cecmap


Default keybindings
-------------------

*cecmap* comes configured with default a *Keyboard* and *Mouse* mode to get
you started (see `cecmap/config/default.cfg`_). You can freely change these
keybindings and add or override modes using the config format, see
Configuration_. The default keybindings are as follows:

.. list-table::
    :header-rows: 1

    * - Key
      - *Mouse* mode
      - *Keyboard* mode

    * - 🔵 F1 blue
      - switch mode
      - switch mode
    * - 🔴 F2 red
      - launch ``matchbox-keyboard``
      - ``<Win>``
    * - 🟢 F3 green
      - mouse wheel up
      - launch kodi
    * - 🟡 F4 yellow
      - mouse wheel down
      - launch ``chromium-browser``

    * - 🡅 up
      - move cursor up
      - ``<up>``
    * - 🡇 down
      - move cursor down
      - ``<down>``
    * - 🡄 left
      - move cursor left
      - ``<left>``
    * - 🡆 right
      - move cursor right
      - ``<right>``

    * - 🆗 select
      - left click
      - ``<enter>``
    * - ▶ play
      - middle click
      - ``<media_play_pause>``

    * - ⏸ pause
      - right click
      - ``<media_play_pause>``
    * - ⮨ exit
      - ``<esc>``
      - ``<esc>``


Configuration
-------------

*cecmap* uses a simple config format to set keycodes and keybindings. The
config to be used can be specified on the command line using the ``-c
FILE.cfg`` option. The format is as follows:

.. code-block:: cfg

    [keycode]
    KEY = <NUMBER>
    ...

    [mode.NAME]
    KEY = <command> [<args>...]
    ...

e.g.:

.. code-block:: cfg

    [keycode]
    left = 123
    yellow = 321
    ...

    [mode.Keyboard]
    left = key left
    yellow = launch kodi
    ...

For a more realistic example, see `cecmap/config/default.cfg`_.

If multiple *modes* are defined, make sure to define a keybinding that
executes the ``switch`` command. This is most easily done in the special
section ``[mode.*]`` that can be used to define fallbacks bindings that apply
globally to all modes. *cecmap* will be started in the topmost declared mode, and
cycle through modes in the order of their appearance.

Multiple config files can be passed. In this case the configuration is merged
sequentially with later files overriding earlier ones. This can be used to
e.g. load keycodes and keybindings from different files::

    cecmap \
        -c keycodes.cfg \
        -c mousemode.cfg \
        -c keymode.cfg

If no ``-c CONFIG`` option is passed on the command line, *cecmap* checks user
and system, or default configuration and uses the first that exists:

- ``$XDG_CONFIG_HOME/cecmap.cfg`` (defaulting to ``~/.config/cecmap.cfg``)
- ``/etc/cecmap.cfg``
- `cecmap/config/default.cfg`_ (distributed with the package)


.. _cecmap/config/default.cfg: https://github.com/coldfix/cecmap/blob/main/cecmap/config/default.cfg

Commands
~~~~~~~~

Currently, the following commands are supported as right hand sides of
keybindings:

.. list-table:: Commands

    * - ``launch <command> [<args>...]``
      - Start the given program. You can use shell-like quoting to pass
        arguments with spaces in them.

    * - ``toggle <command> [<args>...]``
      - Start the given program with command line options. If we have
        previously started the program, terminate it. Useful for commands such
        as ``matchbox-keyboard``.

    * - ``key <name>|<keycode>|@<letter>``
      - Type the specified key. For a list of key names, see Key_.

    * - ``button left|middle|right|<number>``
      - Perform a mouse click using the specified button. More button names
        are available, see Button_.

    * - ``scroll up|down|left|right [<ticks>]``
      - Scroll the mouse wheel in the specified direction a specified number
        of scroll ticks (default = 1).

    * - ``motion up|down|left|right``
      - Perform a mouse cursor motion along the given direction while the key
        is pressed.

    * - ``switch [<mode>]``
      - Switch to the specified ``<mode>``, or if this optional argument is
        omitted, cycle through modes in the order of their appearance in the
        config files.

.. _Key: https://pynput.readthedocs.io/en/latest/keyboard.html#pynput.keyboard.Key
.. _Button: https://github.com/moses-palmer/pynput/blob/master/lib/pynput/mouse/_xorg.py


Keycodes
~~~~~~~~

If the default keycodes do not work as expected, you can configure the
keycodes specific to your setting. In order to determine which key corresponds
to which keycode, open a terminal and execute::

    cec-client

Watch the output as you press buttons, and write down the keycodes for the
config file.


Reloading
~~~~~~~~~

*cecmap* can be told to reload the config by sending ``SIGUSR1``, e.g.::

    pkill -USR1 cecmap

or, if started as a service::

    systemctl --user reload cecmap

Changes
-------

v1.0.0
~~~~~~
Date: 28.11.2021

- rename to cecmap
- switch default keybindings for F1 (blue) and F4 (yellow)
- add keycodes for all user control codes defined by CEC


v0.0.5
~~~~~~
Date: 27.11.2021

- fix KeyError if a motion-bound key was already pressed before starting
  picec but released afterwards
- set/decrease notification timeout to 3s
- move code to picec.cli submodule
- remove ability to load .py config files
- add ability to load .cfg config files
- add ability to reload config on the fly using SIGUSR1
- add ability to merge config from multiple .cfg files
- document config format


v0.0.4
~~~~~~
Date: 26.11.2021

- fix: TypeError: __init__() missing 1 required positional argument: 'app_name'
- fix: AttributeError: 'dict' object has no attribute 'setup'
- fix: AttributeError: module 'os' has no attribute 'setpgrgp'


v0.0.3
~~~~~~
Date: 25.11.2021

- spawn subprocesses in new process group
  (to avoid tearing them down with us when we are stopped)
- execute via ``bash -l`` in .service file to ensure PATH customizations are
  available. This may fix an error when autostarting the service, and will
  be useful for launching locally installed applications.
- move code to package structure
- use entrypoint for creating the executable
- rename executable from ``picec.py`` to ``picec``
- add command line option to change config
  (undocumented so far, and the API will change!)
- load config from ``~/.config/picec/config.py`` if exists
- simplify config
- bind ``matchbox-keyboard`` to red button in mouse mode
- add notification about mode changes using notify2


v0.0.2
~~~~~~
Date: 22.11.2021

- replace xdotool by ``pynput``
- make .service restart on failure


v0.0.1
~~~~~~
Date: 22.11.2021

Initial prototype:

- hard coded keybindings
- for LG TV with magic remote
- "mouse" and "keyboard" mode for controlling the mouse or cursor keys
- based on xdotool
- includes an example .service file