├── Makefile ├── README.md ├── step-1-enumerating-devices.cpp ├── step-2-find-by-name.cpp ├── step-3-grab-and-dump.cpp ├── step-4-process-key.cpp ├── step-5-group-capabilities.cpp ├── step-6-virtual-mouse-clicks.cpp └── step-7-virtual-mouse-movement.cpp /Makefile: -------------------------------------------------------------------------------- 1 | all : step-1 step-2 step-3 step-4 step-5 step-6 step-7 2 | 3 | step-1 : step-1-enumerating-devices.cpp 4 | g++ -o $@ $^ `pkg-config --cflags --libs libevdev` -pthread 5 | step-2 : step-2-find-by-name.cpp 6 | g++ -o $@ $^ `pkg-config --cflags --libs libevdev` -pthread 7 | step-3 : step-3-grab-and-dump.cpp 8 | g++ -o $@ $^ `pkg-config --cflags --libs libevdev` -pthread 9 | step-4 : step-4-process-key.cpp 10 | g++ -o $@ $^ `pkg-config --cflags --libs libevdev` -pthread 11 | step-5 : step-5-group-capabilities.cpp 12 | g++ -o $@ $^ `pkg-config --cflags --libs libevdev` -pthread 13 | step-6 : step-6-virtual-mouse-clicks.cpp 14 | g++ -o $@ $^ `pkg-config --cflags --libs libevdev` -pthread 15 | step-7 : step-7-virtual-mouse-movement.cpp 16 | g++ -o $@ $^ `pkg-config --cflags --libs libevdev` -pthread -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Turning a Keyboard into a Mouse with Libevdev 2 | 3 | Code for [this blog post](https://suricrasia.online/blog/turning-a-keyboard-into/) 4 | 5 | ![CC0 license badge](https://licensebuttons.net/p/zero/1.0/88x31.png) -------------------------------------------------------------------------------- /step-1-enumerating-devices.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | struct libevdev *dev = nullptr; 9 | 10 | for (int i = 0;; i++) { 11 | std::string path = "/dev/input/event" + std::to_string(i); 12 | int fd = open(path.c_str(), O_RDWR|O_CLOEXEC); 13 | if (fd == -1) { 14 | break; // no more character devices 15 | } 16 | if (libevdev_new_from_fd(fd, &dev) == 0) { 17 | std::string phys = libevdev_get_phys(dev); 18 | std::string name = libevdev_get_name(dev); 19 | 20 | std::cout << path << std::endl; 21 | std::cout << "- phys: " << phys << std::endl; 22 | std::cout << "- name: " << name << std::endl; 23 | std::cout << std::endl; 24 | 25 | libevdev_free(dev); 26 | dev = nullptr; 27 | } 28 | close(fd); 29 | } 30 | return 0; 31 | } -------------------------------------------------------------------------------- /step-2-find-by-name.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | struct libevdev* find_device_by_name(const std::string& requested_name) { 8 | struct libevdev *dev = nullptr; 9 | 10 | for (int i = 0;; i++) { 11 | std::string path = "/dev/input/event" + std::to_string(i); 12 | int fd = open(path.c_str(), O_RDWR|O_CLOEXEC); 13 | if (fd == -1) { 14 | break; // no more character devices 15 | } 16 | if (libevdev_new_from_fd(fd, &dev) == 0) { 17 | std::string name = libevdev_get_name(dev); 18 | if (name == requested_name) { 19 | return dev; 20 | } 21 | libevdev_free(dev); 22 | dev = nullptr; 23 | } 24 | close(fd); 25 | } 26 | 27 | return nullptr; 28 | } 29 | 30 | int main() { 31 | struct libevdev *dev = find_device_by_name("Usb KeyBoard Usb KeyBoard"); 32 | 33 | if (dev == nullptr) { 34 | std::cerr << "Couldn't find device!" << std::endl; 35 | return -1; 36 | } 37 | 38 | libevdev_free(dev); 39 | return 0; 40 | } -------------------------------------------------------------------------------- /step-3-grab-and-dump.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | struct libevdev* find_device_by_name(const std::string& requested_name) { 8 | struct libevdev *dev = nullptr; 9 | 10 | for (int i = 0;; i++) { 11 | std::string path = "/dev/input/event" + std::to_string(i); 12 | int fd = open(path.c_str(), O_RDWR|O_CLOEXEC); 13 | if (fd == -1) { 14 | break; // no more character devices 15 | } 16 | if (libevdev_new_from_fd(fd, &dev) == 0) { 17 | std::string name = libevdev_get_name(dev); 18 | if (name == requested_name) { 19 | return dev; 20 | } 21 | libevdev_free(dev); 22 | dev = nullptr; 23 | } 24 | close(fd); 25 | } 26 | 27 | return nullptr; 28 | } 29 | 30 | void process_events(struct libevdev *dev) { 31 | 32 | struct input_event ev = {}; 33 | int status = 0; 34 | auto is_error = [](int v) { return v < 0 && v != -EAGAIN; }; 35 | auto has_next_event = [](int v) { return v >= 0; }; 36 | const auto flags = LIBEVDEV_READ_FLAG_NORMAL | LIBEVDEV_READ_FLAG_BLOCKING; 37 | 38 | while (status = libevdev_next_event(dev, flags, &ev), !is_error(status)) { 39 | if (!has_next_event(status)) continue; 40 | 41 | std::cout << "Got input_event"; 42 | std::cout << " type=" << ev.type; 43 | std::cout << " code=" << ev.code; 44 | std::cout << " value=" << ev.value << std::endl; 45 | } 46 | } 47 | 48 | int main() { 49 | struct libevdev *dev = find_device_by_name("Usb KeyBoard Usb KeyBoard"); 50 | 51 | if (dev == nullptr) { 52 | std::cerr << "Couldn't find device!" << std::endl; 53 | return -1; 54 | } 55 | 56 | libevdev_grab(dev, LIBEVDEV_GRAB); 57 | 58 | process_events(dev); 59 | 60 | libevdev_free(dev); 61 | return 0; 62 | } -------------------------------------------------------------------------------- /step-4-process-key.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | struct libevdev* find_device_by_name(const std::string& requested_name) { 8 | struct libevdev *dev = nullptr; 9 | 10 | for (int i = 0;; i++) { 11 | std::string path = "/dev/input/event" + std::to_string(i); 12 | int fd = open(path.c_str(), O_RDWR|O_CLOEXEC); 13 | if (fd == -1) { 14 | break; // no more character devices 15 | } 16 | if (libevdev_new_from_fd(fd, &dev) == 0) { 17 | std::string name = libevdev_get_name(dev); 18 | if (name == requested_name) { 19 | return dev; 20 | } 21 | libevdev_free(dev); 22 | dev = nullptr; 23 | } 24 | close(fd); 25 | } 26 | 27 | return nullptr; 28 | } 29 | 30 | void process_key(int code, bool is_down) { 31 | std::cout << "scancode= " << code << " is_down=" << is_down << std::endl; 32 | } 33 | 34 | void process_events(struct libevdev *dev) { 35 | struct input_event ev = {}; 36 | int status = 0; 37 | auto is_error = [](int v) { return v < 0 && v != -EAGAIN; }; 38 | auto has_next_event = [](int v) { return v >= 0; }; 39 | const auto flags = LIBEVDEV_READ_FLAG_NORMAL | LIBEVDEV_READ_FLAG_BLOCKING; 40 | 41 | while (status = libevdev_next_event(dev, flags, &ev), !is_error(status)) { 42 | if (!has_next_event(status)) continue; 43 | 44 | if (ev.type == 1) { 45 | bool is_up = ev.value == 0; 46 | bool is_down = ev.value == 1; 47 | if (is_down || is_up) { // excludes autorepeat 48 | process_key(ev.code, is_down); 49 | } 50 | } 51 | } 52 | } 53 | 54 | int main() { 55 | struct libevdev *dev = find_device_by_name("Usb KeyBoard Usb KeyBoard"); 56 | 57 | if (dev == nullptr) { 58 | std::cerr << "Couldn't find device!" << std::endl; 59 | return -1; 60 | } 61 | 62 | libevdev_grab(dev, LIBEVDEV_GRAB); 63 | 64 | process_events(dev); 65 | 66 | libevdev_free(dev); 67 | return 0; 68 | } -------------------------------------------------------------------------------- /step-5-group-capabilities.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | struct libevdev* find_device_by_name(const std::string& requested_name) { 9 | struct libevdev *dev = nullptr; 10 | 11 | for (int i = 0;; i++) { 12 | std::string path = "/dev/input/event" + std::to_string(i); 13 | int fd = open(path.c_str(), O_RDWR|O_CLOEXEC); 14 | if (fd == -1) { 15 | break; // no more character devices 16 | } 17 | if (libevdev_new_from_fd(fd, &dev) == 0) { 18 | std::string name = libevdev_get_name(dev); 19 | if (name == requested_name) { 20 | return dev; 21 | } 22 | libevdev_free(dev); 23 | dev = nullptr; 24 | } 25 | close(fd); 26 | } 27 | 28 | return nullptr; 29 | } 30 | 31 | void process_key(int code, bool is_down) { 32 | std::cout << "scancode= " << code << " is_down=" << is_down << std::endl; 33 | 34 | if (is_down && code == 69) { 35 | system("xterm &"); 36 | } 37 | } 38 | 39 | void process_events(struct libevdev *dev) { 40 | struct input_event ev = {}; 41 | int status = 0; 42 | auto is_error = [](int v) { return v < 0 && v != -EAGAIN; }; 43 | auto has_next_event = [](int v) { return v >= 0; }; 44 | const auto flags = LIBEVDEV_READ_FLAG_NORMAL | LIBEVDEV_READ_FLAG_BLOCKING; 45 | 46 | while (status = libevdev_next_event(dev, flags, &ev), !is_error(status)) { 47 | if (!has_next_event(status)) continue; 48 | 49 | if (ev.type == 1) { 50 | bool is_up = ev.value == 0; 51 | bool is_down = ev.value == 1; 52 | if (is_down || is_up) { // excludes autorepeat 53 | process_key(ev.code, is_down); 54 | } 55 | } 56 | } 57 | } 58 | 59 | int main() { 60 | auto grp = getgrnam("input"); 61 | if (grp == nullptr) { 62 | std::cerr << "getgrnam(\"input\") failed" << std::endl; 63 | return -1; 64 | } 65 | int oldgid = getgid(); 66 | if (setgid(grp->gr_gid) < 0) { 67 | std::cerr << "couldn't change group to input!" << std::endl; 68 | return -1; 69 | } 70 | 71 | struct libevdev *dev = find_device_by_name("Usb KeyBoard Usb KeyBoard"); 72 | 73 | if (dev == nullptr) { 74 | std::cerr << "Couldn't find device!" << std::endl; 75 | return -1; 76 | } 77 | 78 | //drop back into old permissions 79 | if (setgid(oldgid) < 0) { 80 | std::cerr << "couldn't switch back to old group!" << std::endl; 81 | return -1; 82 | } 83 | 84 | libevdev_grab(dev, LIBEVDEV_GRAB); 85 | 86 | process_events(dev); 87 | 88 | libevdev_free(dev); 89 | return 0; 90 | } -------------------------------------------------------------------------------- /step-6-virtual-mouse-clicks.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | class VirtualMouse { 11 | public: 12 | struct libevdev_uinput* m_uinput = nullptr; 13 | std::mutex m_mouseMutex; 14 | public: 15 | VirtualMouse() {} 16 | ~VirtualMouse() { 17 | libevdev_uinput_destroy(m_uinput); 18 | } 19 | 20 | int Init() { 21 | struct libevdev* dev = libevdev_new(); 22 | libevdev_set_name(dev, "Virtual Mouse"); 23 | 24 | libevdev_enable_property(dev, INPUT_PROP_POINTER); 25 | 26 | libevdev_enable_event_type(dev, EV_REL); 27 | libevdev_enable_event_code(dev, EV_REL, REL_X, nullptr); 28 | libevdev_enable_event_code(dev, EV_REL, REL_Y, nullptr); 29 | libevdev_enable_event_code(dev, EV_REL, REL_WHEEL, nullptr); 30 | 31 | libevdev_enable_event_type(dev, EV_KEY); 32 | libevdev_enable_event_code(dev, EV_KEY, BTN_LEFT, nullptr); 33 | libevdev_enable_event_code(dev, EV_KEY, BTN_RIGHT, nullptr); 34 | libevdev_enable_event_code(dev, EV_KEY, BTN_MIDDLE, nullptr); 35 | 36 | int r = libevdev_uinput_create_from_device(dev, LIBEVDEV_UINPUT_OPEN_MANAGED, &m_uinput); 37 | libevdev_free(dev); 38 | return r; 39 | } 40 | 41 | void Move(int rx, int ry) { 42 | std::lock_guard guard(m_mouseMutex); 43 | libevdev_uinput_write_event(m_uinput, EV_REL, REL_X, rx); 44 | libevdev_uinput_write_event(m_uinput, EV_REL, REL_Y, ry); 45 | libevdev_uinput_write_event(m_uinput, EV_SYN, SYN_REPORT, 0); 46 | } 47 | 48 | void Scroll(int rs) { 49 | std::lock_guard guard(m_mouseMutex); 50 | libevdev_uinput_write_event(m_uinput, EV_REL, REL_WHEEL, rs); 51 | libevdev_uinput_write_event(m_uinput, EV_SYN, SYN_REPORT, 0); 52 | } 53 | 54 | void Click(int btn, bool isDown) { 55 | std::lock_guard guard(m_mouseMutex); 56 | libevdev_uinput_write_event(m_uinput, EV_KEY, btn, isDown); 57 | libevdev_uinput_write_event(m_uinput, EV_SYN, SYN_REPORT, 0); 58 | } 59 | }; 60 | 61 | VirtualMouse g_mouse; 62 | 63 | struct libevdev* find_device_by_name(const std::string& requested_name) { 64 | struct libevdev *dev = nullptr; 65 | 66 | for (int i = 0;; i++) { 67 | std::string path = "/dev/input/event" + std::to_string(i); 68 | int fd = open(path.c_str(), O_RDWR|O_CLOEXEC); 69 | if (fd == -1) { 70 | break; // no more character devices 71 | } 72 | if (libevdev_new_from_fd(fd, &dev) == 0) { 73 | std::string name = libevdev_get_name(dev); 74 | if (name == requested_name) { 75 | return dev; 76 | } 77 | libevdev_free(dev); 78 | dev = nullptr; 79 | } 80 | close(fd); 81 | } 82 | 83 | return nullptr; 84 | } 85 | 86 | void process_key(int code, bool is_down) { 87 | if (code == 82) g_mouse.Click(BTN_LEFT, is_down); 88 | if (code == 96) g_mouse.Click(BTN_RIGHT, is_down); 89 | if (code == 83) g_mouse.Click(BTN_MIDDLE, is_down); 90 | } 91 | 92 | void process_events(struct libevdev *dev) { 93 | struct input_event ev = {}; 94 | int status = 0; 95 | auto is_error = [](int v) { return v < 0 && v != -EAGAIN; }; 96 | auto has_next_event = [](int v) { return v >= 0; }; 97 | const auto flags = LIBEVDEV_READ_FLAG_NORMAL | LIBEVDEV_READ_FLAG_BLOCKING; 98 | 99 | while (status = libevdev_next_event(dev, flags, &ev), !is_error(status)) { 100 | if (!has_next_event(status)) continue; 101 | 102 | if (ev.type == 1) { 103 | bool is_up = ev.value == 0; 104 | bool is_down = ev.value == 1; 105 | if (is_down || is_up) { // excludes autorepeat 106 | process_key(ev.code, is_down); 107 | } 108 | } 109 | } 110 | } 111 | 112 | int main() { 113 | auto grp = getgrnam("input"); 114 | if (grp == nullptr) { 115 | std::cerr << "getgrnam(\"input\") failed" << std::endl; 116 | return -1; 117 | } 118 | int oldgid = getgid(); 119 | if (setgid(grp->gr_gid) < 0) { 120 | std::cerr << "couldn't change group to input!" << std::endl; 121 | return -1; 122 | } 123 | 124 | struct libevdev *dev = find_device_by_name("Usb KeyBoard Usb KeyBoard"); 125 | 126 | if (dev == nullptr) { 127 | std::cerr << "Couldn't find device!" << std::endl; 128 | return -1; 129 | } 130 | 131 | // must init mouse before we drop permissions 132 | if (g_mouse.Init() != 0) { 133 | std::cerr << "couldn't init mouse!" << std::endl; 134 | return -1; 135 | } 136 | 137 | //drop back into old permissions 138 | if (setgid(oldgid) < 0) { 139 | std::cerr << "couldn't switch back to old group!" << std::endl; 140 | return -1; 141 | } 142 | 143 | libevdev_grab(dev, LIBEVDEV_GRAB); 144 | 145 | process_events(dev); 146 | 147 | libevdev_free(dev); 148 | return 0; 149 | } -------------------------------------------------------------------------------- /step-7-virtual-mouse-movement.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | class VirtualMouse { 16 | public: 17 | struct libevdev_uinput* m_uinput = nullptr; 18 | std::mutex m_mouseMutex; 19 | public: 20 | VirtualMouse() {} 21 | ~VirtualMouse() { 22 | libevdev_uinput_destroy(m_uinput); 23 | } 24 | 25 | int Init() { 26 | struct libevdev* dev = libevdev_new(); 27 | libevdev_set_name(dev, "Virtual Mouse"); 28 | 29 | libevdev_enable_property(dev, INPUT_PROP_POINTER); 30 | 31 | libevdev_enable_event_type(dev, EV_REL); 32 | libevdev_enable_event_code(dev, EV_REL, REL_X, nullptr); 33 | libevdev_enable_event_code(dev, EV_REL, REL_Y, nullptr); 34 | libevdev_enable_event_code(dev, EV_REL, REL_WHEEL, nullptr); 35 | 36 | libevdev_enable_event_type(dev, EV_KEY); 37 | libevdev_enable_event_code(dev, EV_KEY, BTN_LEFT, nullptr); 38 | libevdev_enable_event_code(dev, EV_KEY, BTN_RIGHT, nullptr); 39 | libevdev_enable_event_code(dev, EV_KEY, BTN_MIDDLE, nullptr); 40 | 41 | int r = libevdev_uinput_create_from_device(dev, LIBEVDEV_UINPUT_OPEN_MANAGED, &m_uinput); 42 | libevdev_free(dev); 43 | return r; 44 | } 45 | 46 | void Move(int rx, int ry) { 47 | std::lock_guard guard(m_mouseMutex); 48 | libevdev_uinput_write_event(m_uinput, EV_REL, REL_X, rx); 49 | libevdev_uinput_write_event(m_uinput, EV_REL, REL_Y, ry); 50 | libevdev_uinput_write_event(m_uinput, EV_SYN, SYN_REPORT, 0); 51 | } 52 | 53 | void Scroll(int rs) { 54 | std::lock_guard guard(m_mouseMutex); 55 | libevdev_uinput_write_event(m_uinput, EV_REL, REL_WHEEL, rs); 56 | libevdev_uinput_write_event(m_uinput, EV_SYN, SYN_REPORT, 0); 57 | } 58 | 59 | void Click(int btn, bool isDown) { 60 | std::lock_guard guard(m_mouseMutex); 61 | libevdev_uinput_write_event(m_uinput, EV_KEY, btn, isDown); 62 | libevdev_uinput_write_event(m_uinput, EV_SYN, SYN_REPORT, 0); 63 | } 64 | }; 65 | 66 | VirtualMouse g_mouse; 67 | 68 | struct libevdev* find_device_by_name(const std::string& requested_name) { 69 | struct libevdev *dev = nullptr; 70 | 71 | for (int i = 0;; i++) { 72 | std::string path = "/dev/input/event" + std::to_string(i); 73 | int fd = open(path.c_str(), O_RDWR|O_CLOEXEC); 74 | if (fd == -1) { 75 | break; // no more character devices 76 | } 77 | if (libevdev_new_from_fd(fd, &dev) == 0) { 78 | std::string name = libevdev_get_name(dev); 79 | if (name == requested_name) { 80 | return dev; 81 | } 82 | libevdev_free(dev); 83 | dev = nullptr; 84 | } 85 | close(fd); 86 | } 87 | 88 | return nullptr; 89 | } 90 | 91 | std::set g_pressedKeys; 92 | std::mutex g_pressed_keys_mutex; 93 | 94 | void process_key(int code, bool is_down) { 95 | std::lock_guard guard(g_pressed_keys_mutex); 96 | if (is_down) { 97 | g_pressedKeys.insert(code); 98 | } else { 99 | g_pressedKeys.erase(code); 100 | } 101 | 102 | if (code == 82) g_mouse.Click(BTN_LEFT, is_down); 103 | if (code == 96) g_mouse.Click(BTN_RIGHT, is_down); 104 | if (code == 83) g_mouse.Click(BTN_MIDDLE, is_down); 105 | } 106 | 107 | void process_events(struct libevdev *dev) { 108 | struct input_event ev = {}; 109 | int status = 0; 110 | auto is_error = [](int v) { return v < 0 && v != -EAGAIN; }; 111 | auto has_next_event = [](int v) { return v >= 0; }; 112 | const auto flags = LIBEVDEV_READ_FLAG_NORMAL | LIBEVDEV_READ_FLAG_BLOCKING; 113 | 114 | while (status = libevdev_next_event(dev, flags, &ev), !is_error(status)) { 115 | if (!has_next_event(status)) continue; 116 | 117 | if (ev.type == 1) { 118 | bool is_up = ev.value == 0; 119 | bool is_down = ev.value == 1; 120 | if (is_down || is_up) { // excludes autorepeat 121 | process_key(ev.code, is_down); 122 | } 123 | } 124 | } 125 | } 126 | 127 | std::atomic_bool g_run_mouse_thread; 128 | void mouse_thread_fn(void*) { 129 | float rx = 0; 130 | float ry = 0; 131 | const float friction = 0.85; 132 | const float accel = 1.2/friction; 133 | while (g_run_mouse_thread) { 134 | float dx = 0; 135 | float dy = 0; 136 | 137 | float rs = 0; 138 | 139 | { 140 | std::lock_guard guard(g_pressed_keys_mutex); 141 | if (g_pressedKeys.count(77) > 0) rx += accel; 142 | if (g_pressedKeys.count(75) > 0) rx -= accel; 143 | if (g_pressedKeys.count(76) > 0) ry += accel; 144 | if (g_pressedKeys.count(72) > 0) ry -= accel; 145 | 146 | if (g_pressedKeys.count(78) > 0) rs += 1; 147 | if (g_pressedKeys.count(14) > 0) rs -= 1; 148 | } 149 | 150 | // resize movement vector to be length 1 151 | if (fabs(dx)+fabs(dy) > accel) { 152 | dx *= .7; 153 | dy *= .7; 154 | } 155 | 156 | rx += dx; 157 | ry += dy; 158 | rx *= friction; 159 | ry *= friction; 160 | 161 | if (fabs(rx)+fabs(ry) > 0) { 162 | g_mouse.Move(rx, ry); 163 | } 164 | if (fabs(rs) > 0) { 165 | g_mouse.Scroll(rs); 166 | } 167 | std::this_thread::sleep_for(std::chrono::milliseconds(10)); 168 | } 169 | } 170 | 171 | int main() { 172 | auto grp = getgrnam("input"); 173 | if (grp == nullptr) { 174 | std::cerr << "getgrnam(\"input\") failed" << std::endl; 175 | return -1; 176 | } 177 | int oldgid = getgid(); 178 | if (setgid(grp->gr_gid) < 0) { 179 | std::cerr << "couldn't change group to input!" << std::endl; 180 | return -1; 181 | } 182 | 183 | struct libevdev *dev = find_device_by_name("Usb KeyBoard Usb KeyBoard"); 184 | 185 | if (dev == nullptr) { 186 | std::cerr << "Couldn't find device!" << std::endl; 187 | return -1; 188 | } 189 | 190 | // must init mouse before we drop permissions 191 | if (g_mouse.Init() != 0) { 192 | std::cerr << "couldn't init mouse!" << std::endl; 193 | return -1; 194 | } 195 | 196 | //drop back into old permissions 197 | if (setgid(oldgid) < 0) { 198 | std::cerr << "couldn't switch back to old group!" << std::endl; 199 | return -1; 200 | } 201 | 202 | g_run_mouse_thread = true; 203 | std::thread mouse_thread(mouse_thread_fn, nullptr); 204 | 205 | libevdev_grab(dev, LIBEVDEV_GRAB); 206 | 207 | process_events(dev); 208 | 209 | libevdev_free(dev); 210 | 211 | g_run_mouse_thread = false; 212 | mouse_thread.join(); 213 | 214 | return 0; 215 | } --------------------------------------------------------------------------------