[简体中文 | English]
A cross-platform C++ HID (Human Interface Device) input simulation and event listening library, supporting keyboard and mouse.
This library has other language binding.
| Language | Repository URL |
|---|---|
| C | HID Tool C |
| Python | HID Tool Python |
- Keyboard Module: Global keyboard event listening, keyboard input simulation
- Mouse Module: Global mouse event listening, mouse input simulation (move, click, wheel, drag)
- Cross-platform support: Windows, macOS, Linux
- C++11 compatible
- Supports static / shared library builds
- Singleton pattern, thread-safe
| Platform | Status | Notes |
|---|---|---|
| Windows | ✅ | If it is necessary to normally monitor the events of high-privilege processes, administrator privileges are required |
| macOS | ✅ | Requires Accessibility permissions (event listening and simulation features) |
| Linux | ✅ | Requires administrator privileges (access to input & uinput character devices) |
macOS Note: Due to macOS API design, all simulation functions cannot determine whether execution was successful. Even if
trueis returned, the action may have no effect. You typically need to grant Accessibility permissions to the application.
- CMake >= 3.26
- C++11 compiler
- macOS: CoreFoundation, Carbon, CoreGraphics (found automatically by CMake)
- Linux: pthreads
git clone https://github.com/JaderoChan/hidtool.git
cd hidtool
cmake -B build [options]
cmake --build build| Option | Default | Description | Notes |
|---|---|---|---|
HIDTOOL_BUILD_WITH_KEYBOARD |
ON |
Build keyboard module | - |
HIDTOOL_BUILD_WITH_MOUSE |
ON |
Build mouse module | - |
HIDTOOL_BUILD_SHARED |
OFF |
Build as shared library | - |
HIDTOOL_BUILD_EXAMPLE |
ON (top-level) |
Build example programs | - |
HIDTOOL_FORCE_IN_PIXEL |
ON |
Force APIs related to mouse pointer position to be operated in physical pixel units | Winodws 10+ only |
# Default static library build
cmake -B build -DCMAKE_BUILD_TYPE=Release
# Build shared library
cmake -B build -DCMAKE_BUILD_TYPE=Release -DHIDTOOL_BUILD_SHARED=ON
# Build keyboard module only
cmake -B build -DHIDTOOL_BUILD_WITH_MOUSE=OFFcmake --install build --prefix /your/install/pathfind_package(hidtool REQUIRED)
target_link_libraries(your_target PRIVATE hidtool)add_subdirectory(hidtool)
target_link_libraries(your_target PRIVATE hidtool)#include <hidtool/hidtool.hpp> // Include all modulesIndividual module headers can also be included separately:
#include <hidtool/keyboard/keyboard_hooker.hpp>
#include <hidtool/keyboard/keyboard_simulator.hpp>
#include <hidtool/mouse/mouse_hooker.hpp>
#include <hidtool/mouse/mouse_simulator.hpp>// Check whether the current environment supports submodules for the specified HID type
bool isHidTypeSupported(HidType hidType) noexcept;using KeyboardHooker;
// Event handler callback type
// Return true: propagate event normally; Return false: block event propagation to other programs
// using KeyboardEventHandler = bool (*)(const KeyboardEvent&, void* userData);
using KeyboardEventHandler;
KeyboardHooker& hooker = KeyboardHooker::getInstance();
// Set event handler callback
hooker.setEventHandler([](const KeyboardEvent& event, void* userData) -> bool
{
if (event.type == KeyboardEvent::ET_PRESS)
{
// Handle key press event
}
return true; // Continue propagating event
});
hooker.run(); // Start listening
hooker.stop(); // Stop listening
hooker.isRunning();Note: Do not call
KeyboardHookermember functions inside the event handler callback.
using KeyboardSimulator;
using KeyboardKey;
KeyboardSimulator& sim = KeyboardSimulator::getInstance();
sim.initialize();
// Using KeyboardKey enum
sim.pressKey(KBDKEY_A);
sim.releaseKey(KBDKEY_A);
sim.clickKey(KBDKEY_ENTER); // pressKey + releaseKey
// Using platform native key values
sim.pressKey(0x41u); // Windows VK_A
// Send key combination (Ctrl+C)
sim.pressKey(KBDKEY_CTRL);
sim.clickKey(KBDKEY_C);
sim.releaseKey(KBDKEY_CTRL);
// Batch send events
KeyboardEvent events[] =
{
KeyboardEvent::createPressEvent(KBDKEY_A),
KeyboardEvent::createReleaseEvent(KBDKEY_A)
};
sim.sendEvent(events, 2);
sim.destroy();The library defines a cross-platform key value enum KeyboardKey that can be converted to and from platform native key values:
// KeyboardKey -> platform native key value (Win: VK_*, macOS: kVK_*, Linux: KEY_*)
int32_t nativeKey = keyboardKeyToNativeKey(KBDKEY_A);
// Platform native key value -> KeyboardKey
KeyboardKey key = keyboardKeyFromNativeKey(0x41u);Common key values:
| Enum | Description |
|---|---|
KBDKEY_0 ~ KBDKEY_9 |
Number keys |
KBDKEY_A ~ KBDKEY_Z |
Letter keys |
KBDKEY_F1 ~ KBDKEY_F24 |
Function keys |
KBDKEY_NUMPAD_0 ~ KBDKEY_NUMPAD_9 |
Numpad digit keys |
KBDKEY_CTRL / KBDKEY_CTRL_LEFT / KBDKEY_CTRL_RIGHT |
Ctrl key |
KBDKEY_SHIFT / KBDKEY_SHIFT_LEFT / KBDKEY_SHIFT_RIGHT |
Shift key |
KBDKEY_ALT / KBDKEY_ALT_LEFT / KBDKEY_ALT_RIGHT |
Alt key (alias KBDKEY_OPTION) |
KBDKEY_META / KBDKEY_META_LEFT / KBDKEY_META_RIGHT |
Win/Command key |
KBDKEY_ENTER / KBDKEY_RETURN |
Enter key |
KBDKEY_ESCAPE / KBDKEY_ESC |
Escape key |
KBDKEY_SPACE |
Space key |
KBDKEY_BACKSPACE |
Backspace key |
KBDKEY_TAB |
Tab key |
KBDKEY_LEFT / KBDKEY_RIGHT / KBDKEY_UP / KBDKEY_DOWN |
Arrow keys |
using MouseHooker;
MouseHooker& hooker = MouseHooker::getInstance();
hooker.setEventHandler([](const MouseEvent& event, void* userData) -> bool
{
switch (event.type)
{
case MouseEvent::ET_ABS_MOVE:
// event.absPos.x, event.absPos.y
break;
case MouseEvent::ET_REL_MOVE:
// event.relPos.x, event.relPos.y
break;
case MouseEvent::ET_WHEEL:
// event.wheelDelta (unit 120, positive = away from user, negative = toward user)
break;
case MouseEvent::ET_DRAG:
// event.drag.pos, event.drag.button
break;
case MouseEvent::ET_PRESS:
case MouseEvent::ET_RELEASE:
// event.button
break;
default:
break;
}
return true;
});
hooker.run();
hooker.stop();Note: Do not call
MouseHookermember functions inside the event handler callback.
using MouseSimulator;
using AbsolutePos;
using RelativePos;
using MouseButton;
MouseSimulator& sim = MouseSimulator::getInstance();
sim.initialize();
// Move mouse (absolute coordinates, based on virtual screen space)
sim.moveTo(AbsolutePos(100, 200));
// Move mouse (relative offset)
sim.moveBy(RelativePos(10, -5));
// Scroll wheel (unit 120, positive = up, negative = down)
sim.wheel(120); // Scroll up one notch
sim.wheel(-120); // Scroll down one notch
// Mouse buttons (at current position)
sim.pressButton(MSBTN_LEFT);
sim.releaseButton(MSBTN_LEFT);
sim.clickButton(MSBTN_LEFT);
sim.doubleClickButton(MSBTN_LEFT);
// Mouse operations at a specified position
sim.clickButton(AbsolutePos(500, 300), MSBTN_LEFT);
sim.wheel(AbsolutePos(500, 300), 120);
// Drag (from current position to target position)
sim.dragCombo(AbsolutePos(800, 400));
// Drag (specify start and end positions)
sim.dragCombo(AbsolutePos(100, 100), AbsolutePos(800, 400), MSBTN_LEFT);
sim.destroy();macOS Note: Drag operations must use the
dragCombo()function or the combination ofpressButton()+dragTo()+releaseButton()to produce.dragTo()same asmoveTo()on other platforms.
The coordinate range of the emitted mouse absolute movement event can be obtained through the following method. Coordinates beyond this range will be clamped.
// Get the absolute coordinate range for the current environment.
AbsolutePosRange range = MouseSimulator::getAbsoluteMoveRange();
// Windows/macOS: virtual screen space range
// Linux: always {0, 65535, 0, 65535}| Enum | Description |
|---|---|
MSBTN_LEFT |
Left button |
MSBTN_RIGHT |
Right button |
MSBTN_MIDDLE |
Middle button |
MSBTN_BACK |
Back button |
MSBTN_FORWARD |
Forward button |
#include <hidtool/hidtool.hpp>
int main()
{
auto& kbdHooker = KeyboardHooker::getInstance();
mouseSimulator.initialize();
kbdHooker.setEventHandler([](const KeyboardEvent& event) -> bool
{
// When F1 is pressed, left-click at (500, 300)
if (event.type == KeyboardEvent::ET_PRESS &&
event.nativeKey == keyboardKeyToNativeKey(KBDKEY_F1))
{
MouseSimulator::getInstance()
.clickButton(AbsolutePos(500, 300), MSBTN_LEFT);
}
return true;
});
kbdHooker.run();
// Main thread waiting...
kbdHooker.stop();
mouseSimulator.destroy();
return 0;
}Listen for keyboard and mouse events and print event information.
Move the mouse around the circle/ellipse inside the screen as the trajectory.
Double-click of the left mouse button at the specified position by pressing the designated key.
This project is open-sourced under the MIT License.
Copyright (c) 2026 頔珞JaderoChan