Merge pull request #1445 from GrantMoyer/keyboard_state_errors
Improve keyboard_state error messages
This commit is contained in:
commit
5e7ba0c9e3
|
@ -24,8 +24,6 @@ class KeyboardState : public AModule {
|
||||||
auto update() -> void;
|
auto update() -> void;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static auto openDevice(const std::string&) -> std::pair<int, libevdev*>;
|
|
||||||
|
|
||||||
Gtk::Box box_;
|
Gtk::Box box_;
|
||||||
Gtk::Label numlock_label_;
|
Gtk::Label numlock_label_;
|
||||||
Gtk::Label capslock_label_;
|
Gtk::Label capslock_label_;
|
||||||
|
|
|
@ -8,6 +8,8 @@ waybar - keyboard-state module
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
|
You must be a member of the input group to use this module.
|
||||||
|
|
||||||
# CONFIGURATION
|
# CONFIGURATION
|
||||||
|
|
||||||
*interval*: ++
|
*interval*: ++
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#include "modules/keyboard_state.hpp"
|
#include "modules/keyboard_state.hpp"
|
||||||
|
#include <errno.h>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
@ -8,6 +10,69 @@ extern "C" {
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class errno_error : public std::runtime_error {
|
||||||
|
public:
|
||||||
|
int code;
|
||||||
|
errno_error(int code, const std::string& msg)
|
||||||
|
: std::runtime_error(getErrorMsg(code, msg.c_str())),
|
||||||
|
code(code) {}
|
||||||
|
errno_error(int code, const char* msg)
|
||||||
|
: std::runtime_error(getErrorMsg(code, msg)),
|
||||||
|
code(code) {}
|
||||||
|
private:
|
||||||
|
static auto getErrorMsg(int err, const char* msg) -> std::string {
|
||||||
|
std::string error_msg{msg};
|
||||||
|
error_msg += ": ";
|
||||||
|
|
||||||
|
#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 32)
|
||||||
|
// strerrorname_np gets the error code's name; it's nice to have, but it's a recent GNU extension
|
||||||
|
const auto errno_name = strerrorname_np(err);
|
||||||
|
error_msg += errno_name;
|
||||||
|
error_msg += " ";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const auto errno_str = strerror(err);
|
||||||
|
error_msg += errno_str;
|
||||||
|
|
||||||
|
return error_msg;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto openFile(const std::string& path, int flags) -> int {
|
||||||
|
int fd = open(path.c_str(), flags);
|
||||||
|
if (fd < 0) {
|
||||||
|
if (errno == EACCES) {
|
||||||
|
throw errno_error(errno, "Can't open " + path + " (are you in the input group?)");
|
||||||
|
} else {
|
||||||
|
throw errno_error(errno, "Can't open " + path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto closeFile(int fd) -> void {
|
||||||
|
int res = close(fd);
|
||||||
|
if (res < 0) {
|
||||||
|
throw errno_error(errno, "Can't close file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto openDevice(int fd) -> libevdev* {
|
||||||
|
libevdev* dev;
|
||||||
|
int err = libevdev_new_from_fd(fd, &dev);
|
||||||
|
if (err < 0) {
|
||||||
|
throw errno_error(-err, "Can't create libevdev device");
|
||||||
|
}
|
||||||
|
return dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto supportsLockStates(const libevdev* dev) -> bool {
|
||||||
|
return libevdev_has_event_type(dev, EV_LED)
|
||||||
|
&& 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);
|
||||||
|
}
|
||||||
|
|
||||||
waybar::modules::KeyboardState::KeyboardState(const std::string& id, const Bar& bar, const Json::Value& config)
|
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),
|
box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0),
|
||||||
|
@ -48,26 +113,36 @@ waybar::modules::KeyboardState::KeyboardState(const std::string& id, const Bar&
|
||||||
|
|
||||||
if (config_["device-path"].isString()) {
|
if (config_["device-path"].isString()) {
|
||||||
std::string dev_path = config_["device-path"].asString();
|
std::string dev_path = config_["device-path"].asString();
|
||||||
std::tie(fd_, dev_) = openDevice(dev_path);
|
fd_ = openFile(dev_path, O_NONBLOCK | O_CLOEXEC | O_RDONLY);
|
||||||
|
dev_ = openDevice(fd_);
|
||||||
} else {
|
} else {
|
||||||
DIR* dev_dir = opendir("/dev/input");
|
DIR* dev_dir = opendir("/dev/input");
|
||||||
if (dev_dir == nullptr) {
|
if (dev_dir == nullptr) {
|
||||||
throw std::runtime_error("Failed to open /dev/input");
|
throw errno_error(errno, "Failed to open /dev/input");
|
||||||
}
|
}
|
||||||
dirent *ep;
|
dirent *ep;
|
||||||
while ((ep = readdir(dev_dir))) {
|
while ((ep = readdir(dev_dir))) {
|
||||||
if (ep->d_type != DT_CHR) continue;
|
if (ep->d_type != DT_CHR) continue;
|
||||||
std::string dev_path = std::string("/dev/input/") + ep->d_name;
|
std::string dev_path = std::string("/dev/input/") + ep->d_name;
|
||||||
|
int fd = openFile(dev_path.c_str(), O_NONBLOCK | O_CLOEXEC | O_RDONLY);
|
||||||
try {
|
try {
|
||||||
std::tie(fd_, dev_) = openDevice(dev_path);
|
auto dev = openDevice(fd);
|
||||||
spdlog::info("Found device {} at '{}'", libevdev_get_name(dev_), dev_path);
|
if (supportsLockStates(dev)) {
|
||||||
break;
|
spdlog::info("Found device {} at '{}'", libevdev_get_name(dev), dev_path);
|
||||||
} catch (const std::runtime_error& e) {
|
fd_ = fd;
|
||||||
continue;
|
dev_ = dev;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (const errno_error& e) {
|
||||||
|
// ENOTTY just means the device isn't an evdev device, skip it
|
||||||
|
if (e.code != ENOTTY) {
|
||||||
|
spdlog::warn(e.what());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
closeFile(fd);
|
||||||
}
|
}
|
||||||
if (dev_ == nullptr) {
|
if (dev_ == nullptr) {
|
||||||
throw std::runtime_error("Failed to find keyboard device");
|
throw errno_error(errno, "Failed to find keyboard device");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,35 +154,13 @@ waybar::modules::KeyboardState::KeyboardState(const std::string& id, const Bar&
|
||||||
|
|
||||||
waybar::modules::KeyboardState::~KeyboardState() {
|
waybar::modules::KeyboardState::~KeyboardState() {
|
||||||
libevdev_free(dev_);
|
libevdev_free(dev_);
|
||||||
int err = close(fd_);
|
try {
|
||||||
if (err < 0) {
|
closeFile(fd_);
|
||||||
// Not much we can do, so ignore it.
|
} catch (const std::runtime_error& e) {
|
||||||
|
spdlog::warn(e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto waybar::modules::KeyboardState::openDevice(const std::string& path) -> std::pair<int, libevdev*> {
|
|
||||||
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 {
|
auto waybar::modules::KeyboardState::update() -> void {
|
||||||
int err = LIBEVDEV_READ_STATUS_SUCCESS;
|
int err = LIBEVDEV_READ_STATUS_SUCCESS;
|
||||||
while (err == LIBEVDEV_READ_STATUS_SUCCESS) {
|
while (err == LIBEVDEV_READ_STATUS_SUCCESS) {
|
||||||
|
@ -117,8 +170,8 @@ auto waybar::modules::KeyboardState::update() -> void {
|
||||||
err = libevdev_next_event(dev_, LIBEVDEV_READ_FLAG_SYNC, &ev);
|
err = libevdev_next_event(dev_, LIBEVDEV_READ_FLAG_SYNC, &ev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (err != -EAGAIN) {
|
if (-err != EAGAIN) {
|
||||||
throw std::runtime_error("Failed to sync evdev device");
|
throw errno_error(-err, "Failed to sync evdev device");
|
||||||
}
|
}
|
||||||
|
|
||||||
int numl = libevdev_get_event_value(dev_, EV_LED, LED_NUML);
|
int numl = libevdev_get_event_value(dev_, EV_LED, LED_NUML);
|
||||||
|
|
Loading…
Reference in New Issue