dtoverlay=gpio-ir,gpio_pin=23,rc-map-name=apple_remote
The string apple_remote can freely chosen filename and the number is the IO-Pin I used (not all can be used!). After reboot this provides a new device under /dev/input/event0 (eventually the number might be different in your system). You can try cat /dev/input/event0 to see if the remote is recognized already.# table apple_remote, type: NEC
0x87eec30b KEY_UP
0x87eec30d KEY_DOWN
0x87eec308 KEY_LEFT
0x87eec307 KEY_RIGHT
0x87eec304 KEY_ENTER
0x87eec302 KEY_ESC
* * apple_remote
I need a DIY IR receiver. Already have TSOP1738 IR receiver IC, and CH340 or FT232R serial to USB bridges.
I would prefer LIRC because many media players like Rhythmbox, VLC, etc. have LIRC support.
Why should I use LIRC?
Recent Linux kernels have built-in support for IR remotes. Using that, pressing an up-arrow on the remote works the same way as pressing the up-arrow on a keyboard. This is a modern "just works" solution. On the other hand, LIRC is an old style linux application which can be tweaked to do almost anything, but is tricky to setup. So, why would you use LIRC?
You might have a remote which is supported by LIRC but not the kernel.
If you have a remote which isn't supported at all, LIRC is probably your best bet to get it running.
You might be on a non-Linux platform supporting lirc e. g., MacOS.
You might have an application which is more or less designed to use LIRC.
You might need LIRC's capabilities e. g., modes where a single remote button can be teached to deliver different keys to the application. Handling input to multiple program is also easier with lirc
You might want to send IR signals to other devices (IR blasting).
You might want to use lirc's applications e. g., irexec(1) which can run arbitrary commands in parallel with an application such as mythtv or kodi.
So, while the kernel built-in handling works out of the box in many cases, there are still scenarios when LIRC is the right tool.
For why LIRC, at this point the sunk-cost fallacy alone would be a strong enough reason.
The pitch from the LIRC devs is this:
# add xenial repo to the sources.list (temporary, will delete it after install)
echo 'deb [trusted=yes] http://ca.archive.ubuntu.com/ubuntu/ xenial universe' | sudo tee -a /etc/apt/sources.list > /dev/null
sudo apt update
# install good old LIRC and lock it against further upgrades
sudo apt install lirc/xenial
sudo apt-mark hold lirc
# at install time, a configure text wizard should appear, if that didn't happen do
sudo dpkg-reconfigure lirc
# choose the FTDI driver, that will create proper config files in /etc/lirc/
# remove the temporary added xenial repo from /etc/apt/sources.list
sudo truncate -s -"$(tail -n1 /etc/apt/sources.list | wc -c)" /etc/apt/sources.list
sudo apt update
# to configure lirc
# download a config file for your IR remote (mine is Leadtek from a former WinFast tuner)
# download the remote from [url]https://sourceforge.net/p/lirc-remotes/code/ci/master/tree/remotes/leadtek/Y04G0033.lircd.conf[/url]
wget [url]https://sourceforge.net/p/lirc-remotes/code/ci/master/tree/remotes/leadtek/Y04G0033.lircd.conf?format=raw[/url]
# add the downloaded remote as remote(s) config file
sudo mv /etc/lirc/lircd.conf /etc/lirc/lircd.conf.original
sudo cp ./Y04G0033.lircd.conf /etc/lirc/lircd.conf
# restart the lirc service (or reboot the PC) for changes to take effect
sudo /etc/init.d/lirc restart
# if all OK, irw should tell the received button pressed in the IR remote
irw
00000000c03f30cf 00 KEY_UP Leadtek_Cool_Command_Y04G0033
00000000c03f08f7 00 KEY_DOWN Leadtek_Cool_Command_Y04G0033
00000000c03f08f7 01 KEY_DOWN Leadtek_Cool_Command_Y04G0033
00000000c03fc837 00 KEY_ENTER Leadtek_Cool_Command_Y04G0033
00000000c03f6a95 00 KEY_TV Leadtek_Cool_Command_Y04G0033
00000000c03fea15 00 KEY_RADIO Leadtek_Cool_Command_Y04G0033
00000000c03fea15 01 KEY_RADIO Leadtek_Cool_Command_Y04G0033
00000000c03f1ae5 00 KEY_DVD Leadtek_Cool_Command_Y04G0033
00000000c03f1ae5 01 KEY_DVD Leadtek_Cool_Command_Y04G0033
# note KEY_LEFT denotes a button from the IR remote, not the arrow key button from the PC keyboard
begin
remote = Leadtek_Cool_Command_Y04G0033
prog = pulseaudio
config = volume-down
button = KEY_LEFT
repeat = 0
end
begin
remote = Leadtek_Cool_Command_Y04G0033
prog = pulseaudio
config = volume-up
button = KEY_RIGHT
repeat = 0
end
begin
remote = Leadtek_Cool_Command_Y04G0033
prog = pulseaudio
config = mute-toggle
button = KEY_DOWN
end
# this last one is to toggle pause/play in Rhythmbox
# (you must also go to settings in the Rhythmbox GUI and enable its LIRC plugin)
begin
prog = Rhythmbox
button = KEY_ENTER
config = playpause
end
load-module module-lirc
# if you have multiple PulseAudio sinks, to specify which one will listen to IR buttons
# load-module module-lirc sink=[your sink name]
irrecord -Hftdi some_new_remote
# then follow the text wizard
# and at the end irrecord will produce a text file 'some_new_remote' in the local directory
# open file 'some_new_remote' in a text editor and copy/add its content inside the file /etc/lirc/lircd.conf
# save edited /etc/lirc/lircd.conf (you'll need admin rights)
#
# open ~/.lircrc file and add inside new buttons from the new remote
#
# then restart the lirc daemon or reboot the PC
I do not currently have any IR remotes at all.
Would it help if I create an uinput example program? For example, one that reads single-character "commands" from a serial port, and injects them into the Linux input subsystem just like a hardware USB HID device would? This would allow you to use your current hardware without buying anything, but leverage the input subsystem instead of relying on LIRC.
- to send shell commands from the IR remote, start irexec
https://linuxaudiofoundation.org/category/irexec/
to start irexec automatically at each boot
create a unit file for systemd, '/lib/systemd/system/irexec.service',
so systemd will start irexec at boot, as a service
# sudo nano /lib/systemd/system/irexec.service
[Unit]
Documentation=man:irexec(1)
Documentation=http://lirc.org/html/configure.html
Documentation=http://lirc.org/html/configure.html#lircrc_format
Description=Handle events from IR remotes decoded by lircd(8)
After=network.target
# note the 'Wants=' for lirc 0.9.0 is called 'lirc', while in 0.10.1 'lircd'
Wants=lirc.service
[Service]
Type=simple
# when not specified, the default lircrc is expected to be in /home/<your_username>/.lircrc
# use hardcoded path to avoid variable substitutions and shell expansion uncertainty
# ExecStart=/usr/bin/irexec /etc/lirc/irexec.lircrc
ExecStart=/usr/bin/irexec /home/<your_username>/.lircrc
ExecStart=/usr/bin/irexec
Restart=on-failure
SuccessExitStatus=3 4
RestartForceExitStatus=3 4
[Install]
WantedBy=multi-user.target
- to enable loading irexec at boot
sudo systemctl daemon-reload
sudo systemctl enable irexec
reboot
- when 'irexec' is running (either from a terminal, as a daemon or as a service)
'irexec' will listen to LIRC and will emit
the commands specified inside the LIRC button mapings file, '~/.lircrc', e.g.
begin
remote = EBODA_DVD_black
prog = irexec
button = KEY_PAUSE
# use hardcoded path, system variables mught not work
# config = echo cycle pause | socat - "$HOME/.config/mpv/socket"
config = echo cycle pause | socat - "/home/<your_username>/.config/mpv/socket"
end
# add the following line(s) inside file ~/.config/mpv/mpv.conf (create the file if it's missing)
# for mpv to receive inputs from a command-line (while mpv is running)
# (LIRC irexec daemon will use this socket to control mpv from an IR remote)
input-ipc-server=/home/<your_username>/.config/mpv/socket
sudo systemctl restart lirc && sudo systemctl restart irexec && pulseaudio -k
A reboot might be easier, to be sure no components to be restarted were forgotten.- customised files to backup for lirc v0.9.0
/etc/lirc/hardware.conf
/etc/lirc/lircd.conf
/home/<your_username>/.lircrc
/lib/systemd/system/irexec.service
/home/<your_username>/.config/mpv/mpv.conf
any other files you created with irrecord for unknown IR remotes
If you want, I can write you a simple C program that maps serial port inputs into Linux input events, using the uinput device. (Linux allows one to programmatically create USB HID devices that behave exactly like the physical device would.) I'm just saying that with a MCU with a native USB interface, like on ATmega32u4, you don't need such daemons or drivers at all, just program it to support whatever IR remotes you like, and off you go.
why do you want to over-complicate simple stuff?
##
# mpv IR keys binding (mpv has no LIRC plugin)
#
# https://stackoverflow.com/questions/19536799/lirc-how-to-use-as-keyboard-command
# https://alexherbo2.github.io/config/mpv/control-mpv-from-the-command-line/
# echo cycle pause | socat - "$XDG_CONFIG_HOME/mpv/socket"
# $XDG_CONFIG_HOME might not be defined, use "$HOME/.config" instead
#
# # better use a hardcoded already expanded path
# echo cycle pause | socat - "/home/aaa/.config/mpv/socket"
# echo playlist-next | socat - "$XDG_CONFIG_HOME/mpv/socket"
# echo playlist-prev | socat - "$XDG_CONFIG_HOME/mpv/socket"
#
# !!! DO NOT USE SYSTEM VARIABLES or ~, use hardcoded paths instead !!!
#
# mpv commands format
# echo '{ "command": ["set_property", "pause", true] }' | socat - /tmp/mpvsocket
# for example
# {"command": ["cycle", "pause"]}
#
# see also e.g. 'mpv --list-properties | grep fullscreen'
# mpv --list-options | less
# # note this will stop the currently running mpv to respond to MPC (socat) commands, restart the mpv to recover
##
# mpv cycle pause KEY_PAUSE
begin
remote = EBODA_DVD_black
prog = irexec
button = KEY_PAUSE
config = echo cycle pause | socat - "home/aaa/.config/mpv/socket"
end
# mpv cycle pause KEY_PLAY
begin
remote = EBODA_DVD_black
prog = irexec
button = KEY_PLAY
config = echo cycle pause | socat - "home/aaa/.config/mpv/socket"
end
# mpv playlist-next KEY_RIGHT
begin
remote = EBODA_DVD_black
prog = irexec
button = KEY_RIGHT
config = echo playlist-next | socat - "home/aaa/.config/mpv/socket"
end
# mpv playlist-prev KEY_LEFT
begin
remote = EBODA_DVD_black
prog = irexec
button = KEY_LEFT
config = echo playlist-prev | socat - "home/aaa/.config/mpv/socket"
end
# mpv cycle fullscreen KEY_ENTER
begin
remote = EBODA_DVD_black
prog = irexec
button = KEY_ENTER
config = echo cycle fullscreen | socat - "/home/aaa/.config/mpv/socket"
end
# mpv cycle fullscreen KEY_ZOOM
begin
remote = EBODA_DVD_black
prog = irexec
button = KEY_ZOOM
config = echo cycle fullscreen | socat - "/home/aaa/.config/mpv/socket"
end
# mpv show subtitles KEY_SUBTITLE
begin
remote = EBODA_DVD_black
prog = irexec
button = KEY_SUBTITLE
config = echo cycle sub-visibility | socat - "/home/aaa/.config/mpv/socket"
end
# mpv cycle subtitles KEY_OPEN_CLOSE
begin
remote = EBODA_DVD_black
prog = irexec
button = KEY_OPEN_CLOSE
config = echo cycle sid | socat - "/home/aaa/.config/mpv/socket"
end
# mpv cycle audio KEY_LANGUAGE
begin
remote = EBODA_DVD_black
prog = irexec
button = KEY_LANGUAGE
config = echo cycle aid | socat - "/home/aaa/.config/mpv/socket"
end
# mpv cycle audio KEY_PROGRAM
begin
remote = EBODA_DVD_black
prog = irexec
button = KEY_PROGRAM
config = echo cycle vid | socat - "/home/aaa/.config/mpv/socket"
end
# mpv cycle aspect ratio KEY_ANGLE
begin
remote = EBODA_DVD_black
prog = irexec
button = KEY_ANGLE
config = echo cycle aspect | socat - "/home/aaa/.config/mpv/socket"
end
# mpv cycle osd time KEY_OSD
begin
remote = EBODA_DVD_black
prog = irexec
button = KEY_OSD
config = echo cycle osd-level | socat - "/home/aaa/.config/mpv/socket"
end
# mpv cycle osd time KEY_TIME
begin
remote = EBODA_DVD_black
prog = irexec
button = KEY_TIME
config = echo cycle osd-level | socat - "/home/aaa/.config/mpv/socket"
end
# mpv seek back -3s KEY_REWIND
begin
remote = EBODA_DVD_black
prog = irexec
button = KEY_REWIND
config = echo seek -3 | socat - "/home/aaa/.config/mpv/socket"
end
# mpv seek forward +1s KEY_FORWARD
begin
remote = EBODA_DVD_black
prog = irexec
button = KEY_FORWARD
config = echo seek +1 | socat - "/home/aaa/.config/mpv/socket"
end
# mpv play faster KEY_NEXT
begin
remote = EBODA_DVD_black
prog = irexec
button = KEY_NEXT
config = echo add speed +0.1 | socat - "/home/aaa/.config/mpv/socket"
end
# mpv play slower KEY_PREVIOUS
begin
remote = EBODA_DVD_black
prog = irexec
button = KEY_PREVIOUS
config = echo add speed -0.1 | socat - "/home/aaa/.config/mpv/socket"
end
# mpv volume up KEY_VOL_PLUS
begin
remote = EBODA_DVD_black
prog = irexec
button = KEY_VOL_PLUS
config = echo add volume +5 | socat - "/home/aaa/.config/mpv/socket"
end
# mpv volume down KEY_VOL_MINUS
begin
remote = EBODA_DVD_black
prog = irexec
button = KEY_VOL_MINUS
config = echo add volume -5 | socat - "/home/aaa/.config/mpv/socket"
end
// SPDX-License-Identifier: CC0-1.0
//
// Compile using for example
// gcc -Wall -O2 thisfile.c -o binary
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <linux/uinput.h>
#include <string.h>
#include <signal.h>
#include <stdio.h>
#include <errno.h>
// Signal handling for graceful restart
static volatile sig_atomic_t restart = 0;
void handle_restart(int signum)
{
(void)signum;
restart = 1;
}
int install_restart(int signum)
{
struct sigaction act;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_handler = handle_restart;
act.sa_flags = 0; // No SA_RESTART flag!
return sigaction(signum, &act, NULL);
}
// Signal handling for graceful exit
static volatile sig_atomic_t done = 0;
void handle_done(int signum)
{
(void)signum;
done = 1;
}
int install_done(int signum)
{
struct sigaction act;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_handler = handle_done;
act.sa_flags = 0; // No SA_RESTART flag!
return sigaction(signum, &act, NULL);
}
// Helper function, since signal delivery can cause an EINTR "error". Async-signal safe, too.
int writeall(int fd, const void *buf, size_t len)
{
const int saved_errno = errno;
int err = 0;
const unsigned char *const end = (const unsigned char *)buf + len;
const unsigned char *src = (const unsigned char *)buf;
while (src < end) {
ssize_t n = write(fd, src, (size_t)(end - src));
if (n > 0) {
src += n;
} else
if (n != -1) {
err = EIO;
break;
} else
if (errno != EINTR) {
err = errno;
break;
}
}
errno = saved_errno;
return err;
}
// Emit a keypress and release
void keypress(int fd, int code)
{
struct input_event ev[2];
// Timestamp is ignored
ev[0].time.tv_sec = 0;
ev[0].time.tv_usec = 0;
ev[1].time = ev[0].time;
// Keypress
ev[0].type = EV_KEY;
ev[0].code = code;
ev[0].value = 1; // Keypress
ev[1].type = EV_SYN;
ev[1].code = SYN_REPORT;
ev[1].value = 0;
writeall(fd, ev, sizeof ev);
// Key release
ev[0].value = 0; // Release
writeall(fd, ev, sizeof ev);
}
int parse_usbid(const char *src, struct uinput_setup *to)
{
unsigned long val;
const char *end;
if (!src || !*src || !to)
return -1;
memset(to, 0, sizeof *to);
to->id.bustype = 0;
to->id.vendor = 0;
to->id.product = 0;
to->id.version = 0;
// Vendor
end = src;
errno = 0;
val = strtoul(src, (char **)&end, 16);
if (errno || end == src || *end != ':' || val > 0xFFFF)
return -1;
to->id.vendor = val;
// Product
src = ++end;
errno = 0;
val = strtoul(src, (char **)&end, 16);
if (errno || end == src || val > 0xFFFF)
return -1;
to->id.product = val;
// Version (optional)
if (*end == ':') {
src = ++end;
errno = 0;
val = strtoul(src, (char **)&end, 0);
if (errno || end == src || val > 0xFFFF)
return -1;
to->id.version = val;
}
// Name (optional)
if (*end == '/') {
src = ++end;
end = src + strlen(src);
if ((size_t)(end - src) >= UINPUT_MAX_NAME_SIZE)
return -1;
strncpy(to->name, src, UINPUT_MAX_NAME_SIZE - 1);
}
if (*end)
return -1;
return 0;
}
int main(int argc, char *argv[])
{
const char *arg0 = (argc > 0 && argv && argv[0] && argv[0][0]) ? argv[0] : "(this)";
struct uinput_setup setup;
struct termios oldsettings, settings;
int uinputfd, devfd = -1;
// Check command-line arguments
if (argc != 3 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", arg0);
fprintf(stderr, " %s DEVICE-PATH VENDOR:PRODUCT[:VERSION][/NAME]\n", arg0);
fprintf(stderr, "\n");
return EXIT_FAILURE;
}
if (parse_usbid(argv[2], &setup)) {
fprintf(stderr, "%s: Invalid synthetic USB HID device identifier.\n", argv[2]);
return EXIT_FAILURE;
}
// Install signal handlers
if (install_done(SIGINT) ||
install_done(SIGTERM) ||
install_restart(SIGHUP) ||
install_restart(SIGUSR1)) {
fprintf(stderr, "Cannot install signal handlers: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
// Construct new input event device
uinputfd = open("/dev/uinput", O_RDWR | O_CLOEXEC);
if (uinputfd == -1) {
fprintf(stderr, "/dev/uinput: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
// List event types and events this can produce
ioctl(uinputfd, UI_SET_EVBIT, EV_KEY);
ioctl(uinputfd, UI_SET_KEYBIT, KEY_VOLUMEDOWN);
ioctl(uinputfd, UI_SET_KEYBIT, KEY_VOLUMEUP);
// Create the new synthetic input device
ioctl(uinputfd, UI_DEV_SETUP, &setup);
ioctl(uinputfd, UI_DEV_CREATE);
while (1) {
// Close already open serial port
if (devfd != -1) {
tcflush(devfd, TCIOFLUSH);
tcsetattr(devfd, TCSANOW, &oldsettings);
close(devfd);
}
if (done)
break;
// Open serial port or TTY device,
devfd = open(argv[1], O_RDWR | O_CLOEXEC);
if (devfd == -1) {
fprintf(stderr, "%s: Cannot open: %s.\n", argv[1], strerror(errno));
close(uinputfd);
return EXIT_FAILURE;
}
// obtain its current configuration,
if (tcgetattr(devfd, &oldsettings) == -1) {
fprintf(stderr, "%s: Not a TTY or serial port: %s.\n", argv[1], strerror(errno));
close(devfd);
close(uinputfd);
return EXIT_FAILURE;
}
// and configure it.
settings = oldsettings;
settings.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
settings.c_oflag &= ~(OPOST | OCRNL | ONOCR | ONLRET);
settings.c_cflag &= ~(CSIZE | PARENB);
settings.c_cflag |= CS8 | CREAD;
settings.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL | TOSTOP | IEXTEN);
settings.c_cc[VMIN] = 1;
settings.c_cc[VTIME] = 0;
if (tcsetattr(devfd, TCSANOW, &settings) == -1) {
fprintf(stderr, "%s: Cannot configure: %s.\n", argv[1], strerror(errno));
tcflush(devfd, TCIOFLUSH);
tcsetattr(devfd, TCSANOW, &oldsettings);
close(devfd);
close(uinputfd);
return EXIT_FAILURE;
}
// We have now restarted.
restart = 0;
while (!done && !restart) {
unsigned char buf[512];
ssize_t n = read(devfd, buf, sizeof buf);
if (n > 0) {
unsigned char *const end = buf + n;
unsigned char *src = buf;
while (src < end) {
switch (*(src++)) {
case '+':
keypress(uinputfd, KEY_VOLUMEUP);
break;
case '-':
keypress(uinputfd, KEY_VOLUMEDOWN);
break;
}
}
} else
if (n != -1) {
// End of input from serial device; reopen.
break;
} else
if (errno != EINTR) {
// Other error from serial device; reopen.
break;
}
}
}
close(uinputfd);
return EXIT_SUCCESS;
}
Now I have so many questions...
We do need to be aware of the security implications
ask
I don't have yet a clean view of how the signals travel in general.
I was expecting something like the RFC specs for networking, yet the kernel input system refers to very specific items like i.e. joystick or a multi-touch.
For now, the biggest inconvenient in using the Linux kernel media keys is that the controls (play/pause) are sent to the active window. Often the player is in the background or minimized, and in the foreground is some other window open and active.
How do I map the media keys (for example the play/pause) to always go to the media player?
Is there any Linux mechanism to tell which player was last playing (in case there are more players open and paused)?
I'd put each player on their own virtual desktop (AKA workspace), maximized
Why making a Linux kernel specification in such a lousy way that a click into another window will render useless any input controller with physical media buttons on it, like this play/pause button on a PC keyboard?
Shouldn't such a standard specify to play/pause the last player in focus?
- specify in the standard to send the multimedia events to the last player that was in focus
- specify a switch current player mechanism (like the Alt+TAB for windows, but for players only), in case more players are already open
I expect a physical IR remote to interact with whatever it is playing now in the desktop, no mater the player. This works as expected for system volume and system mute (because LIRC was set to control the pulseaudio mute/volume), but not for play/pause/next/previous.
(I seriously dislike dbus stuff, you see)
Indeed, playerctldoes the expected jobnope, when the player is not specified, plyerctl sends the commands to the first player seen (in alphabetical order ).
My own solution approach would differ: I'd use the X11 approach, mapping windows to audio sources, and use X11 events rather than dbus events to control the players. But that's just me.
Can you tell more about your [X11] approach?
sudo apt install mpv-mpris
sudo apt install playerctl
mkdir -p ~/.config/systemd/user && touch ~/.config/systemd/user/playerctld.service
nano ~/.config/systemd/user/playerctld.service
Add this content to it and save the playerctld.service file[Unit]
Description=Keep track of media player activity
[Service]
Type=oneshot
ExecStart=/usr/bin/playerctld daemon
[Install]
WantedBy=default.target
systemctl --user daemon-reload
systemctl --user start playerctld.service
systemctl --user enable playerctld.service
sudo systemctl stop irexec
sudo systemctl disable irexec
[Unit]
Documentation=man:irexec(1)
Documentation=http://lirc.org/html/configure.html
Documentation=http://lirc.org/html/configure.html#lircrc_format
Description=Handle events from IR remotes decoded by lircd(8)
After=network.target
Wants=lirc.service
Requires=dbus.service
[Service]
Type=simple
ExecStart=/usr/bin/irexec
Restart=on-failure
SuccessExitStatus=3 4
RestartForceExitStatus=3 4
[Install]
WantedBy=default.target
systemctl --user daemon-reload
systemctl --user start irexec
systemctl --user enable irexec
##
# playerctl LIRC key bindings
# send play/pause/next/prev to the last active player
# require playerctl installed and running playerctld daemon
##
# last active player cycle pause KEY_PAUSE
begin
remote = EBODA_DVD_black
prog = irexec
button = KEY_PAUSE
config = playerctl play-pause
end
# last active player cycle pause KEY_PLAY
begin
remote = EBODA_DVD_black
prog = irexec
button = KEY_PLAY
config = playerctl play-pause
end
# last active player playlist-next KEY_RIGHT
begin
remote = EBODA_DVD_black
prog = irexec
button = KEY_RIGHT
config = playerctl next
end
# last active player playlist-prev KEY_RIGHT
begin
remote = EBODA_DVD_black
prog = irexec
button = KEY_LEFT
config = playerctl previous
end
sudo systemctl daemon-reload && sudo systemctl restart lirc && systemctl --user daemon-reload && systemctl --user restart irexec && systemctl --user restart playerctld && pulseaudio -k
Been 10+ days since keep configuring LIRC and halfway there already, easy-peasy!
Which one are you using?
[OSS and ALSA, vlc and mpg123]