From 6dfa31fb1778da2989a28179304f9e1ccf1e3e4e Mon Sep 17 00:00:00 2001 From: Grant Moyer Date: Sun, 7 Feb 2021 15:05:11 -0500 Subject: [PATCH 1/9] Basic keyboard state module --- README.md | 2 + include/factory.hpp | 3 ++ include/modules/keyboard_state.hpp | 31 +++++++++++++ meson.build | 7 +++ meson_options.txt | 1 + src/factory.cpp | 5 ++ src/modules/keyboard_state.cpp | 73 ++++++++++++++++++++++++++++++ 7 files changed, 122 insertions(+) create mode 100644 include/modules/keyboard_state.hpp create mode 100644 src/modules/keyboard_state.cpp diff --git a/README.md b/README.md index b104adec..37c0cfc7 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,7 @@ libappindicator-gtk3 [Tray module] libdbusmenu-gtk3 [Tray module] libmpdclient [MPD module] libsndio [sndio module] +libevdev [KeyboardState module] ``` **Build dependencies** @@ -86,6 +87,7 @@ sudo apt install \ clang-tidy \ gobject-introspection \ libdbusmenu-gtk3-dev \ + libevdev-dev \ libfmt-dev \ libgirepository1.0-dev \ libgtk-3-dev \ diff --git a/include/factory.hpp b/include/factory.hpp index 1cae68c9..4b9f32aa 100644 --- a/include/factory.hpp +++ b/include/factory.hpp @@ -38,6 +38,9 @@ #ifdef HAVE_LIBUDEV #include "modules/backlight.hpp" #endif +#ifdef HAVE_LIBEVDEV +#include "modules/keyboard_state.hpp" +#endif #ifdef HAVE_LIBPULSE #include "modules/pulseaudio.hpp" #endif diff --git a/include/modules/keyboard_state.hpp b/include/modules/keyboard_state.hpp new file mode 100644 index 00000000..99ed602b --- /dev/null +++ b/include/modules/keyboard_state.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include +#if FMT_VERSION < 60000 +#include +#else +#include +#endif +#include "ALabel.hpp" +#include "util/sleeper_thread.hpp" + +extern "C" { +#include +} + +namespace waybar::modules { + +class KeyboardState : public ALabel { + public: + KeyboardState(const std::string&, const Json::Value&); + ~KeyboardState(); + auto update() -> void; + + private: + std::string dev_path_; + int fd_; + libevdev* dev_; + util::SleeperThread thread_; +}; + +} // namespace waybar::modules diff --git a/meson.build b/meson.build index e80448e0..7ac6fd6a 100644 --- a/meson.build +++ b/meson.build @@ -94,6 +94,7 @@ libnl = dependency('libnl-3.0', required: get_option('libnl')) libnlgen = dependency('libnl-genl-3.0', required: get_option('libnl')) libpulse = dependency('libpulse', required: get_option('pulseaudio')) libudev = dependency('libudev', required: get_option('libudev')) +libevdev = dependency('libevdev', required: get_option('libevdev')) libmpdclient = dependency('libmpdclient', required: get_option('mpd')) libsndio = compiler.find_library('sndio', required: get_option('sndio')) @@ -215,6 +216,11 @@ if libudev.found() and (is_linux or libepoll.found()) src_files += 'src/modules/backlight.cpp' endif +if libevdev.found() and (is_linux or libepoll.found()) + add_project_arguments('-DHAVE_LIBEVDEV', language: 'cpp') + src_files += 'src/modules/keyboard_state.cpp' +endif + if libmpdclient.found() add_project_arguments('-DHAVE_LIBMPDCLIENT', language: 'cpp') src_files += 'src/modules/mpd/mpd.cpp' @@ -270,6 +276,7 @@ executable( libudev, libepoll, libmpdclient, + libevdev, gtk_layer_shell, libsndio, tz_dep diff --git a/meson_options.txt b/meson_options.txt index cb5581b3..fefb3dc3 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,6 +1,7 @@ option('libcxx', type : 'boolean', value : false, description : 'Build with Clang\'s libc++ instead of libstdc++ on Linux.') option('libnl', type: 'feature', value: 'auto', description: 'Enable libnl support for network related features') option('libudev', type: 'feature', value: 'auto', description: 'Enable libudev support for udev related features') +option('libevdev', type: 'feature', value: 'auto', description: 'Enable libevdev support for evdev related features') option('pulseaudio', type: 'feature', value: 'auto', description: 'Enable support for pulseaudio') option('systemd', type: 'feature', value: 'auto', description: 'Install systemd user service unit') option('dbusmenu-gtk', type: 'feature', value: 'auto', description: 'Enable support for tray') diff --git a/src/factory.cpp b/src/factory.cpp index 1f907894..cab23079 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -70,6 +70,11 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const { return new waybar::modules::Backlight(id, config_[name]); } #endif +#ifdef HAVE_LIBEVDEV + if (ref == "keyboard_state") { + return new waybar::modules::KeyboardState(id, config_[name]); + } +#endif #ifdef HAVE_LIBPULSE if (ref == "pulseaudio") { return new waybar::modules::Pulseaudio(id, config_[name]); diff --git a/src/modules/keyboard_state.cpp b/src/modules/keyboard_state.cpp new file mode 100644 index 00000000..ea9ae577 --- /dev/null +++ b/src/modules/keyboard_state.cpp @@ -0,0 +1,73 @@ +#include "modules/keyboard_state.hpp" +#include + +extern "C" { +#include +#include +#include +} + +waybar::modules::KeyboardState::KeyboardState(const std::string& id, const Json::Value& config) + : ALabel(config, "keyboard_state", id, "{temperatureC}", 1) { + if (config_["device-path"].isString()) { + dev_path_ = config_["device-path"].asString(); + } else { + dev_path_ = ""; + } + + fd_ = open(dev_path_.c_str(), O_NONBLOCK | O_CLOEXEC | O_RDONLY); + if (fd_ < 0) { + throw std::runtime_error("Can't open " + dev_path_); + } + int err = libevdev_new_from_fd(fd_, &dev_); + if (err < 0) { + throw std::runtime_error("Can't create libevdev device"); + } + if (!libevdev_has_event_type(dev_, EV_LED)) { + throw std::runtime_error("Device doesn't support LED events"); + } + if (!libevdev_has_event_code(dev_, EV_LED, LED_NUML) || !libevdev_has_event_code(dev_, EV_LED, LED_CAPSL)) { + throw std::runtime_error("Device doesn't support num lock or caps lock events"); + } + + thread_ = [this] { + dp.emit(); + thread_.sleep_for(interval_); + }; +} + +waybar::modules::KeyboardState::~KeyboardState() { + libevdev_free(dev_); + int err = close(fd_); + if (err < 0) { + // Not much we can do, so ignore it. + } +} + +auto waybar::modules::KeyboardState::update() -> void { + int err = LIBEVDEV_READ_STATUS_SUCCESS; + while (err == LIBEVDEV_READ_STATUS_SUCCESS) { + input_event ev; + err = libevdev_next_event(dev_, LIBEVDEV_READ_FLAG_NORMAL, &ev); + while (err == LIBEVDEV_READ_STATUS_SYNC) { + err = libevdev_next_event(dev_, LIBEVDEV_READ_FLAG_SYNC, &ev); + } + } + if (err != -EAGAIN) { + throw std::runtime_error("Failed to sync evdev device"); + } + + int numl = libevdev_get_event_value(dev_, EV_LED, LED_NUML); + //int capsl = libevdev_get_event_value(dev_, EV_LED, LED_CAPSL); + + std::string text; + if (numl) { + text = fmt::format(format_, "num lock enabled"); + label_.set_markup(text); + } else { + text = fmt::format(format_, "num lock disabled"); + label_.set_markup(text); + } + + ALabel::update(); +} From 642e28166b784244fda45cc90832b75951969372 Mon Sep 17 00:00:00 2001 From: Grant Moyer Date: Sun, 7 Feb 2021 18:46:39 -0500 Subject: [PATCH 2/9] Add more configuaration --- include/modules/keyboard_state.hpp | 22 ++++++++-- resources/config | 13 +++++- src/factory.cpp | 2 +- src/modules/keyboard_state.cpp | 70 ++++++++++++++++++++++++------ 4 files changed, 89 insertions(+), 18 deletions(-) diff --git a/include/modules/keyboard_state.hpp b/include/modules/keyboard_state.hpp index 99ed602b..0873ad55 100644 --- a/include/modules/keyboard_state.hpp +++ b/include/modules/keyboard_state.hpp @@ -6,8 +6,10 @@ #else #include #endif -#include "ALabel.hpp" +#include "AModule.hpp" +#include "bar.hpp" #include "util/sleeper_thread.hpp" +#include extern "C" { #include @@ -15,16 +17,30 @@ extern "C" { namespace waybar::modules { -class KeyboardState : public ALabel { +class KeyboardState : public AModule { public: - KeyboardState(const std::string&, const Json::Value&); + KeyboardState(const std::string&, const waybar::Bar&, const Json::Value&); ~KeyboardState(); auto update() -> void; private: + const Bar& bar_; + Gtk::Box box_; + Gtk::Label numlock_label_; + Gtk::Label capslock_label_; + Gtk::Label scrolllock_label_; + + std::string numlock_format_; + std::string capslock_format_; + std::string scrolllock_format_; + const std::chrono::seconds interval_; + std::string icon_locked_; + std::string icon_unlocked_; + std::string dev_path_; int fd_; libevdev* dev_; + util::SleeperThread thread_; }; diff --git a/resources/config b/resources/config index 13dc94c1..e7c91c0f 100644 --- a/resources/config +++ b/resources/config @@ -6,7 +6,7 @@ // Choose the order of the modules "modules-left": ["sway/workspaces", "sway/mode", "custom/media"], "modules-center": ["sway/window"], - "modules-right": ["mpd", "idle_inhibitor", "pulseaudio", "network", "cpu", "memory", "temperature", "backlight", "sway/language", "battery", "battery#bat2", "clock", "tray"], + "modules-right": ["keyboard_state", "mpd", "idle_inhibitor", "pulseaudio", "network", "cpu", "memory", "temperature", "backlight", "sway/language", "battery", "battery#bat2", "clock", "tray"], // Modules configuration // "sway/workspaces": { // "disable-scroll": true, @@ -23,6 +23,16 @@ // "default": "" // } // }, + "keyboard_state": { + "numlock": true, + "format": "{name} {icon}", + "format-icons": { + "locked": "", + "unlocked": "" + }, + "capslock": true, + "device-path": "/dev/input/by-path/platform-i8042-serio-0-event-kbd" + }, "sway/mode": { "format": "{}" }, @@ -145,3 +155,4 @@ // "exec": "$HOME/.config/waybar/mediaplayer.py --player spotify 2> /dev/null" // Filter player based on name } } + diff --git a/src/factory.cpp b/src/factory.cpp index cab23079..6a0147d9 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -72,7 +72,7 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const { #endif #ifdef HAVE_LIBEVDEV if (ref == "keyboard_state") { - return new waybar::modules::KeyboardState(id, config_[name]); + return new waybar::modules::KeyboardState(id, bar_, config_[name]); } #endif #ifdef HAVE_LIBPULSE diff --git a/src/modules/keyboard_state.cpp b/src/modules/keyboard_state.cpp index ea9ae577..b51617f2 100644 --- a/src/modules/keyboard_state.cpp +++ b/src/modules/keyboard_state.cpp @@ -7,8 +7,44 @@ extern "C" { #include } -waybar::modules::KeyboardState::KeyboardState(const std::string& id, const Json::Value& config) - : ALabel(config, "keyboard_state", id, "{temperatureC}", 1) { +waybar::modules::KeyboardState::KeyboardState(const std::string& id, const Bar& bar, const Json::Value& config) + : AModule(config, "keyboard_state", id, false, !config["disable-scroll"].asBool()), + bar_(bar), + box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0), + numlock_label_(""), + capslock_label_(""), + numlock_format_(config_["format"].isString() ? config_["format"].asString() + : config_["format"]["numlock"].isString() ? config_["format"]["numlock"].asString() + : "{name} {icon}"), + capslock_format_(config_["format"].isString() ? config_["format"].asString() + : config_["format"]["capslock"].isString() ? config_["format"]["capslock"].asString() + : "{name} {icon}"), + scrolllock_format_(config_["format"].isString() ? config_["format"].asString() + : config_["format"]["scrolllock"].isString() ? config_["format"]["scrolllock"].asString() + : "{name} {icon}"), + interval_(std::chrono::seconds(config_["interval"].isUInt() ? config_["interval"].asUInt() : 1)), + icon_locked_(config_["format-icons"]["locked"].isString() + ? config_["format-icons"]["locked"].asString() + : "locked"), + icon_unlocked_(config_["format-icons"]["unlocked"].isString() + ? config_["format-icons"]["unlocked"].asString() + : "unlocked") + { + box_.set_name("keyboard_state"); + if (config_["numlock"].asBool()) { + box_.pack_end(numlock_label_, false, false, 0); + } + if (config_["capslock"].asBool()) { + box_.pack_end(capslock_label_, false, false, 0); + } + if (config_["scrolllock"].asBool()) { + box_.pack_end(scrolllock_label_, false, false, 0); + } + if (!id.empty()) { + box_.get_style_context()->add_class(id); + } + event_box_.add(box_); + if (config_["device-path"].isString()) { dev_path_ = config_["device-path"].asString(); } else { @@ -26,8 +62,10 @@ waybar::modules::KeyboardState::KeyboardState(const std::string& id, const Json: if (!libevdev_has_event_type(dev_, EV_LED)) { throw std::runtime_error("Device doesn't support LED events"); } - if (!libevdev_has_event_code(dev_, EV_LED, LED_NUML) || !libevdev_has_event_code(dev_, EV_LED, LED_CAPSL)) { - throw std::runtime_error("Device doesn't support num lock or caps lock events"); + if (!libevdev_has_event_code(dev_, EV_LED, LED_NUML) + || !libevdev_has_event_code(dev_, EV_LED, LED_CAPSL) + || !libevdev_has_event_code(dev_, EV_LED, LED_SCROLLL)) { + throw std::runtime_error("Device doesn't support num lock, caps lock, or scroll lock events"); } thread_ = [this] { @@ -58,16 +96,22 @@ auto waybar::modules::KeyboardState::update() -> void { } int numl = libevdev_get_event_value(dev_, EV_LED, LED_NUML); - //int capsl = libevdev_get_event_value(dev_, EV_LED, LED_CAPSL); + int capsl = libevdev_get_event_value(dev_, EV_LED, LED_CAPSL); + int scrolll = libevdev_get_event_value(dev_, EV_LED, LED_SCROLLL); std::string text; - if (numl) { - text = fmt::format(format_, "num lock enabled"); - label_.set_markup(text); - } else { - text = fmt::format(format_, "num lock disabled"); - label_.set_markup(text); - } + text = fmt::format(numlock_format_, + fmt::arg("icon", numl ? icon_locked_ : icon_unlocked_), + fmt::arg("name", "Num")); + numlock_label_.set_markup(text); + text = fmt::format(capslock_format_, + fmt::arg("icon", capsl ? icon_locked_ : icon_unlocked_), + fmt::arg("name", "Caps")); + capslock_label_.set_markup(text); + text = fmt::format(scrolllock_format_, + fmt::arg("icon", scrolll ? icon_locked_ : icon_unlocked_), + fmt::arg("name", "Scroll")); + scrolllock_label_.set_markup(text); - ALabel::update(); + AModule::update(); } From 40e6360722acc32ea1b266f361666a4cc64d9608 Mon Sep 17 00:00:00 2001 From: Grant Moyer Date: Sun, 7 Feb 2021 18:57:12 -0500 Subject: [PATCH 3/9] Update css class when locked/unlocked --- src/modules/keyboard_state.cpp | 35 +++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/src/modules/keyboard_state.cpp b/src/modules/keyboard_state.cpp index b51617f2..516502f9 100644 --- a/src/modules/keyboard_state.cpp +++ b/src/modules/keyboard_state.cpp @@ -99,19 +99,28 @@ auto waybar::modules::KeyboardState::update() -> void { int capsl = libevdev_get_event_value(dev_, EV_LED, LED_CAPSL); int scrolll = libevdev_get_event_value(dev_, EV_LED, LED_SCROLLL); - std::string text; - text = fmt::format(numlock_format_, - fmt::arg("icon", numl ? icon_locked_ : icon_unlocked_), - fmt::arg("name", "Num")); - numlock_label_.set_markup(text); - text = fmt::format(capslock_format_, - fmt::arg("icon", capsl ? icon_locked_ : icon_unlocked_), - fmt::arg("name", "Caps")); - capslock_label_.set_markup(text); - text = fmt::format(scrolllock_format_, - fmt::arg("icon", scrolll ? icon_locked_ : icon_unlocked_), - fmt::arg("name", "Scroll")); - scrolllock_label_.set_markup(text); + struct { + bool state; + Gtk::Label& label; + const std::string& format; + const char* name; + } label_states[] = { + {(bool) numl, numlock_label_, numlock_format_, "Num"}, + {(bool) capsl, capslock_label_, capslock_format_, "Caps"}, + {(bool) scrolll, scrolllock_label_, scrolllock_format_, "Scroll"}, + }; + for (auto& label_state : label_states) { + std::string text; + text = fmt::format(label_state.format, + fmt::arg("icon", label_state.state ? icon_locked_ : icon_unlocked_), + fmt::arg("name", label_state.name)); + label_state.label.set_markup(text); + if (label_state.state) { + label_state.label.get_style_context()->add_class("locked"); + } else { + label_state.label.get_style_context()->remove_class("locked"); + } + } AModule::update(); } From 6fdbc27998e16daafa637427c6ecddc53abc31ce Mon Sep 17 00:00:00 2001 From: Grant Moyer Date: Sun, 7 Feb 2021 19:06:55 -0500 Subject: [PATCH 4/9] Add default style --- resources/config | 2 +- resources/style.css | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/resources/config b/resources/config index e7c91c0f..a83edf1c 100644 --- a/resources/config +++ b/resources/config @@ -6,7 +6,7 @@ // Choose the order of the modules "modules-left": ["sway/workspaces", "sway/mode", "custom/media"], "modules-center": ["sway/window"], - "modules-right": ["keyboard_state", "mpd", "idle_inhibitor", "pulseaudio", "network", "cpu", "memory", "temperature", "backlight", "sway/language", "battery", "battery#bat2", "clock", "tray"], + "modules-right": ["mpd", "idle_inhibitor", "pulseaudio", "network", "cpu", "memory", "temperature", "backlight", "keyboard_state", "sway/language", "battery", "battery#bat2", "clock", "tray"], // Modules configuration // "sway/workspaces": { // "disable-scroll": true, diff --git a/resources/style.css b/resources/style.css index 63ea871c..c1ac5ad1 100644 --- a/resources/style.css +++ b/resources/style.css @@ -228,3 +228,19 @@ label:focus { margin: 0 5px; min-width: 16px; } + +#keyboard_state { + background: #97e1ad; + color: #000000; + padding: 0 0px; + margin: 0 5px; + min-width: 16px; +} + +#keyboard_state > label { + padding: 0 5px; +} + +#keyboard_state > label.locked { + background: rgba(0, 0, 0, 0.2); +} From 08e886ebc681849e7b241db71ad7e76a9d0dec43 Mon Sep 17 00:00:00 2001 From: Grant Moyer Date: Sun, 7 Feb 2021 21:05:34 -0500 Subject: [PATCH 5/9] Search for device automatically if none given --- include/modules/keyboard_state.hpp | 3 +- resources/config | 5 +-- src/modules/keyboard_state.cpp | 69 +++++++++++++++++++++--------- 3 files changed, 52 insertions(+), 25 deletions(-) diff --git a/include/modules/keyboard_state.hpp b/include/modules/keyboard_state.hpp index 0873ad55..d6d98de2 100644 --- a/include/modules/keyboard_state.hpp +++ b/include/modules/keyboard_state.hpp @@ -24,6 +24,8 @@ class KeyboardState : public AModule { auto update() -> void; private: + static auto openDevice(const std::string&) -> std::pair; + const Bar& bar_; Gtk::Box box_; Gtk::Label numlock_label_; @@ -37,7 +39,6 @@ class KeyboardState : public AModule { std::string icon_locked_; std::string icon_unlocked_; - std::string dev_path_; int fd_; libevdev* dev_; diff --git a/resources/config b/resources/config index a83edf1c..465f6949 100644 --- a/resources/config +++ b/resources/config @@ -25,13 +25,12 @@ // }, "keyboard_state": { "numlock": true, + "capslock": true, "format": "{name} {icon}", "format-icons": { "locked": "", "unlocked": "" - }, - "capslock": true, - "device-path": "/dev/input/by-path/platform-i8042-serio-0-event-kbd" + } }, "sway/mode": { "format": "{}" diff --git a/src/modules/keyboard_state.cpp b/src/modules/keyboard_state.cpp index 516502f9..9a7802f4 100644 --- a/src/modules/keyboard_state.cpp +++ b/src/modules/keyboard_state.cpp @@ -1,5 +1,6 @@ #include "modules/keyboard_state.hpp" #include +#include extern "C" { #include @@ -28,8 +29,9 @@ waybar::modules::KeyboardState::KeyboardState(const std::string& id, const Bar& : "locked"), icon_unlocked_(config_["format-icons"]["unlocked"].isString() ? config_["format-icons"]["unlocked"].asString() - : "unlocked") - { + : "unlocked"), + fd_(0), + dev_(nullptr) { box_.set_name("keyboard_state"); if (config_["numlock"].asBool()) { box_.pack_end(numlock_label_, false, false, 0); @@ -46,26 +48,28 @@ waybar::modules::KeyboardState::KeyboardState(const std::string& id, const Bar& event_box_.add(box_); if (config_["device-path"].isString()) { - dev_path_ = config_["device-path"].asString(); + std::string dev_path = config_["device-path"].asString(); + std::tie(fd_, dev_) = openDevice(dev_path); } else { - dev_path_ = ""; - } - - fd_ = open(dev_path_.c_str(), O_NONBLOCK | O_CLOEXEC | O_RDONLY); - if (fd_ < 0) { - throw std::runtime_error("Can't open " + dev_path_); - } - int err = libevdev_new_from_fd(fd_, &dev_); - if (err < 0) { - throw std::runtime_error("Can't create libevdev device"); - } - if (!libevdev_has_event_type(dev_, EV_LED)) { - throw std::runtime_error("Device doesn't support LED events"); - } - if (!libevdev_has_event_code(dev_, EV_LED, LED_NUML) - || !libevdev_has_event_code(dev_, EV_LED, LED_CAPSL) - || !libevdev_has_event_code(dev_, EV_LED, LED_SCROLLL)) { - throw std::runtime_error("Device doesn't support num lock, caps lock, or scroll lock events"); + DIR* dev_dir = opendir("/dev/input"); + if (dev_dir == nullptr) { + throw std::runtime_error("Failed to open /dev/input"); + } + dirent *ep; + while ((ep = readdir(dev_dir))) { + if (ep->d_type != DT_CHR) continue; + std::string dev_path = std::string("/dev/input/") + ep->d_name; + try { + std::tie(fd_, dev_) = openDevice(dev_path); + spdlog::info("Found device {} at '{}'", libevdev_get_name(dev_), dev_path); + break; + } catch (const std::runtime_error& e) { + continue; + } + } + if (dev_ == nullptr) { + throw std::runtime_error("Failed to find keyboard device"); + } } thread_ = [this] { @@ -82,6 +86,29 @@ waybar::modules::KeyboardState::~KeyboardState() { } } +auto waybar::modules::KeyboardState::openDevice(const std::string& path) -> std::pair { + int fd = open(path.c_str(), O_NONBLOCK | O_CLOEXEC | O_RDONLY); + if (fd < 0) { + throw std::runtime_error("Can't open " + path); + } + + libevdev* dev; + int err = libevdev_new_from_fd(fd, &dev); + if (err < 0) { + throw std::runtime_error("Can't create libevdev device"); + } + if (!libevdev_has_event_type(dev, EV_LED)) { + throw std::runtime_error("Device doesn't support LED events"); + } + if (!libevdev_has_event_code(dev, EV_LED, LED_NUML) + || !libevdev_has_event_code(dev, EV_LED, LED_CAPSL) + || !libevdev_has_event_code(dev, EV_LED, LED_SCROLLL)) { + throw std::runtime_error("Device doesn't support num lock, caps lock, or scroll lock events"); + } + + return std::make_pair(fd, dev); +} + auto waybar::modules::KeyboardState::update() -> void { int err = LIBEVDEV_READ_STATUS_SUCCESS; while (err == LIBEVDEV_READ_STATUS_SUCCESS) { From 99138ffdcd6e3620a9952d7ca1ceb7b0fc5edfb1 Mon Sep 17 00:00:00 2001 From: Grant Moyer Date: Thu, 15 Apr 2021 17:41:15 -0400 Subject: [PATCH 6/9] Add man page for keyboard_state module --- man/waybar-keyboard-state.5.scd | 80 +++++++++++++++++++++++++++++++++ man/waybar.5.scd.in | 1 + meson.build | 1 + 3 files changed, 82 insertions(+) create mode 100644 man/waybar-keyboard-state.5.scd diff --git a/man/waybar-keyboard-state.5.scd b/man/waybar-keyboard-state.5.scd new file mode 100644 index 00000000..8e9ca5eb --- /dev/null +++ b/man/waybar-keyboard-state.5.scd @@ -0,0 +1,80 @@ +waybar-keyboard-state(5) + +# NAME + +waybar - keyboard_state module + +# DESCRIPTION + +The *keyboard_state* module displays the state of number lock, caps lock, and scroll lock. + +# CONFIGURATION + +*interval*: ++ + typeof: integer ++ + default: 1 ++ + The interval, in seconds, to poll the keyboard state. + +*format*: ++ + typeof: string|object ++ + default: {name} {icon} ++ + The format, how information should be displayed. If a string, the same format is used for all keyboard states. If an object, the fields "numlock", "capslock", and "scrolllock" each specify the format for the corresponding state. Any unspecified states use the default format. + +*format-icons*: ++ + typeof: object ++ + default: {"locked": "locked", "unlocked": "unlocked"} ++ + Based on the keyboard state, the corresponding icon gets selected. The same set of icons is used for number, caps, and scroll lock, but the icon is selected from the set independently for each. See *icons*. + +*numlock*: ++ + typeof: bool ++ + default: false ++ + Display the number lock state. + +*capslock*: ++ + typeof: bool ++ + default: false ++ + Display the caps lock state. + +*scrolllock*: ++ + typeof: bool ++ + default: false ++ + Display the scroll lock state. + +*device-path*: ++ + typeof: string ++ + default: chooses first valid input device ++ + Which libevdev input device to show the state of. Libevdev devices can be found in /dev/input. The device should support number lock, caps lock, and scroll lock events. + +# FORMAT REPLACEMENTS + +*{name}*: Caps, Num, or Scroll. + +*{icon}*: Icon, as defined in *format-icons*. + +# ICONS + +The following *format-icons* can be set. + +- *locked*: Will be shown when the keyboard state is locked. Default "locked". +- *unlocked*: Will be shown when the keyboard state is not locked. Default "unlocked" + +# EXAMPLE: + +``` +"keyboard_state": { + "numlock": true, + "capslock": true, + "format": "{name} {icon}", + "format-icons": { + "locked": "", + "unlocked": "" + } +} +``` + +# STYLE + +- *#keyboard_state* +- *#keyboard_state label* +- *#keyboard_state label.locked* + diff --git a/man/waybar.5.scd.in b/man/waybar.5.scd.in index 0168de38..9dc6925f 100644 --- a/man/waybar.5.scd.in +++ b/man/waybar.5.scd.in @@ -208,6 +208,7 @@ Valid options for the "rotate" property are: 0, 90, 180 and 270. - *waybar-custom(5)* - *waybar-disk(5)* - *waybar-idle-inhibitor(5)* +- *waybar-keyboard-state(5)* - *waybar-memory(5)* - *waybar-mpd(5)* - *waybar-network(5)* diff --git a/meson.build b/meson.build index 7ac6fd6a..f3b50f7b 100644 --- a/meson.build +++ b/meson.build @@ -317,6 +317,7 @@ if scdoc.found() 'waybar-custom.5.scd', 'waybar-disk.5.scd', 'waybar-idle-inhibitor.5.scd', + 'waybar-keyboard-state.5.scd', 'waybar-memory.5.scd', 'waybar-mpd.5.scd', 'waybar-network.5.scd', From 9880c6929f64284aa088a8a662ac3c636176b685 Mon Sep 17 00:00:00 2001 From: Grant Moyer Date: Tue, 20 Jul 2021 21:24:43 -0400 Subject: [PATCH 7/9] Install libevdev in FreeBSD workflow --- .github/workflows/freebsd.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/freebsd.yml b/.github/workflows/freebsd.yml index 2fde6107..f02c9b57 100644 --- a/.github/workflows/freebsd.yml +++ b/.github/workflows/freebsd.yml @@ -15,8 +15,9 @@ jobs: export CPPFLAGS=-isystem/usr/local/include LDFLAGS=-L/usr/local/lib # sndio sed -i '' 's/quarterly/latest/' /etc/pkg/FreeBSD.conf pkg install -y git # subprojects/date - pkg install -y gtk-layer-shell gtkmm30 jsoncpp libdbusmenu sndio \ - libfmt libmpdclient libudev-devd meson pkgconf pulseaudio scdoc spdlog + pkg install -y evdev-proto gtk-layer-shell gtkmm30 jsoncpp libdbusmenu \ + libevdev libfmt libmpdclient libudev-devd meson pkgconf pulseaudio \ + scdoc sndio spdlog run: | meson build -Dman-pages=enabled ninja -C build From 311c5779ea7729474343490817974a6c89d6fe0c Mon Sep 17 00:00:00 2001 From: Grant Moyer Date: Tue, 20 Jul 2021 23:01:39 -0400 Subject: [PATCH 8/9] Remove unused variable --- include/modules/keyboard_state.hpp | 1 - src/modules/keyboard_state.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/include/modules/keyboard_state.hpp b/include/modules/keyboard_state.hpp index d6d98de2..1793bfe8 100644 --- a/include/modules/keyboard_state.hpp +++ b/include/modules/keyboard_state.hpp @@ -26,7 +26,6 @@ class KeyboardState : public AModule { private: static auto openDevice(const std::string&) -> std::pair; - const Bar& bar_; Gtk::Box box_; Gtk::Label numlock_label_; Gtk::Label capslock_label_; diff --git a/src/modules/keyboard_state.cpp b/src/modules/keyboard_state.cpp index 9a7802f4..ca72144a 100644 --- a/src/modules/keyboard_state.cpp +++ b/src/modules/keyboard_state.cpp @@ -10,7 +10,6 @@ extern "C" { waybar::modules::KeyboardState::KeyboardState(const std::string& id, const Bar& bar, const Json::Value& config) : AModule(config, "keyboard_state", id, false, !config["disable-scroll"].asBool()), - bar_(bar), box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0), numlock_label_(""), capslock_label_(""), From 88a5f713ed2c98034dbdd547d184e56a3071c5c8 Mon Sep 17 00:00:00 2001 From: Grant Moyer Date: Fri, 23 Jul 2021 09:45:07 -0400 Subject: [PATCH 9/9] Prefer keyboard-state over keyboard_state --- man/waybar-keyboard-state.5.scd | 12 ++++++------ resources/config | 4 ++-- resources/style.css | 6 +++--- src/factory.cpp | 2 +- src/modules/keyboard_state.cpp | 4 ++-- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/man/waybar-keyboard-state.5.scd b/man/waybar-keyboard-state.5.scd index 8e9ca5eb..1d7c3a83 100644 --- a/man/waybar-keyboard-state.5.scd +++ b/man/waybar-keyboard-state.5.scd @@ -2,11 +2,11 @@ waybar-keyboard-state(5) # NAME -waybar - keyboard_state module +waybar - keyboard-state module # DESCRIPTION -The *keyboard_state* module displays the state of number lock, caps lock, and scroll lock. +The *keyboard-state* module displays the state of number lock, caps lock, and scroll lock. # CONFIGURATION @@ -61,7 +61,7 @@ The following *format-icons* can be set. # EXAMPLE: ``` -"keyboard_state": { +"keyboard-state": { "numlock": true, "capslock": true, "format": "{name} {icon}", @@ -74,7 +74,7 @@ The following *format-icons* can be set. # STYLE -- *#keyboard_state* -- *#keyboard_state label* -- *#keyboard_state label.locked* +- *#keyboard-state* +- *#keyboard-state label* +- *#keyboard-state label.locked* diff --git a/resources/config b/resources/config index 465f6949..87f24c04 100644 --- a/resources/config +++ b/resources/config @@ -6,7 +6,7 @@ // Choose the order of the modules "modules-left": ["sway/workspaces", "sway/mode", "custom/media"], "modules-center": ["sway/window"], - "modules-right": ["mpd", "idle_inhibitor", "pulseaudio", "network", "cpu", "memory", "temperature", "backlight", "keyboard_state", "sway/language", "battery", "battery#bat2", "clock", "tray"], + "modules-right": ["mpd", "idle_inhibitor", "pulseaudio", "network", "cpu", "memory", "temperature", "backlight", "keyboard-state", "sway/language", "battery", "battery#bat2", "clock", "tray"], // Modules configuration // "sway/workspaces": { // "disable-scroll": true, @@ -23,7 +23,7 @@ // "default": "" // } // }, - "keyboard_state": { + "keyboard-state": { "numlock": true, "capslock": true, "format": "{name} {icon}", diff --git a/resources/style.css b/resources/style.css index c1ac5ad1..b585e5f1 100644 --- a/resources/style.css +++ b/resources/style.css @@ -229,7 +229,7 @@ label:focus { min-width: 16px; } -#keyboard_state { +#keyboard-state { background: #97e1ad; color: #000000; padding: 0 0px; @@ -237,10 +237,10 @@ label:focus { min-width: 16px; } -#keyboard_state > label { +#keyboard-state > label { padding: 0 5px; } -#keyboard_state > label.locked { +#keyboard-state > label.locked { background: rgba(0, 0, 0, 0.2); } diff --git a/src/factory.cpp b/src/factory.cpp index 6a0147d9..98363545 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -71,7 +71,7 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const { } #endif #ifdef HAVE_LIBEVDEV - if (ref == "keyboard_state") { + if (ref == "keyboard-state") { return new waybar::modules::KeyboardState(id, bar_, config_[name]); } #endif diff --git a/src/modules/keyboard_state.cpp b/src/modules/keyboard_state.cpp index ca72144a..2b6eb2d9 100644 --- a/src/modules/keyboard_state.cpp +++ b/src/modules/keyboard_state.cpp @@ -9,7 +9,7 @@ extern "C" { } waybar::modules::KeyboardState::KeyboardState(const std::string& id, const Bar& bar, const Json::Value& config) - : AModule(config, "keyboard_state", id, false, !config["disable-scroll"].asBool()), + : AModule(config, "keyboard-state", id, false, !config["disable-scroll"].asBool()), box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0), numlock_label_(""), capslock_label_(""), @@ -31,7 +31,7 @@ waybar::modules::KeyboardState::KeyboardState(const std::string& id, const Bar& : "unlocked"), fd_(0), dev_(nullptr) { - box_.set_name("keyboard_state"); + box_.set_name("keyboard-state"); if (config_["numlock"].asBool()) { box_.pack_end(numlock_label_, false, false, 0); }