The VirtualDevice interface provides a flexible way to define and control virtual input devices on Linux. Below is a detailed guide on how to use it for various operations.
These methods allow you to configure the virtual device before registration.
| Action | Description |
|---|---|
WithPath |
Sets the file path for the virtual device. Default is /dev/uinput. |
WithMode |
Sets the file mode for the device file. Default is 0660. |
WithQueueLen |
Configures the event queue length. Default is 1024. |
WithBusType |
Sets the device bus type (e.g., linux.BUS_USB). |
WithVendor |
Sets the vendor ID of the virtual device. (e.g. sdl.USB_VENDOR_MICROSOFT, 0x1234). |
WithProduct |
Sets the product ID of the virtual device. (e.g. sdl.USB_PRODUCT_XBOX_ONE_S, 0x1234). |
WithVersion |
Sets the version number for the virtual device. (e.g. 0x01). |
WithName |
Sets the name of the virtual device. |
WithKeys |
Specifies the keys supported by the device. (e.g. []linux.Key{linux.KEY_A, linux.KEY_B, linux.KEY_C}). |
WithButtons |
Specifies the buttons supported by the device. (e.g. []linux.Button{linux.BTN_LEFT, linux.BTN_RIGHT}). |
WithAbsAxes |
Configures the absolute axes for the device. |
WithRelAxes |
Configures the relative axes for the device. |
WithRepeat |
Configures key repeat delay and period. |
WithLEDs |
Specifies the LEDs supported by the device. (e.g. []linux.Led{linux.LED_NUML, linux.LED_CAPSL). |
WithProperties |
Sets device-specific properties (e.g., linux.INPUT_PROP_BUTTONPAD). |
WithMiscEvents |
Specifies the miscellaneous events (e.g., linux.MSC_SCAN). |
These methods manage the virtual device's lifecycle.
| Action | Description |
|---|---|
Register |
Registers the virtual device with the system. Must be called before sending events. |
Unregister |
Unregisters the virtual device, cleaning up resources. |
These methods send or manipulate input events.
| Action | Description |
|---|---|
Send |
Sends a raw input event of the specified type, code, and value. |
Sync |
Sends a synchronization event (e.g., linux.SYN_MT_REPORT). |
SyncReport |
Sends a default synchronization event (linux.SYN_REPORT). |
PressKey |
Simulates a key press event. |
ReleaseKey |
Simulates a key release event. |
PressButton |
Simulates a button press event. |
ReleaseButton |
Simulates a button release event. |
SendAbsoluteEvent |
Sends an absolute axis event with the specified axis and value. |
SendRelativeEvent |
Sends a relative axis event with the specified axis and value. |
SetLed |
Toggles the state of an LED on the virtual device. |
SendMiscEvent |
Sends a miscellaneous event (e.g., linux.MSC_SCAN). |
Use the With... methods to configure your virtual device. These methods allow chaining for easy and clear initialization.
Example:
device := virtual_device.NewVirtualDevice().
WithVendor(sdl.USB_VENDOR_LOGITECH).
WithProduct(0xc22d).
WithVersion(0x111).
WithName("Logitech G510 Gaming Keyboard"),
WithKeys([]linux.Key{linux.KEY_A, linux.KEY_B, linux.KEY_C}).
WithLEDs([]linux.Led{linux.LED_CAPSL})After configuration, call Register() to create the virtual device
err := device.Register()
if err != nil {
log.Fatalf("Failed to register virtual device: %v", err)
}The VirtualDevice interface allows you to send various types of input events, simulating actions like key presses, mouse movements, and more.
Simulate pressing and releasing keyboard keys:
device.PressKey(linux.KEY_A) // Simulate pressing the "A" key
device.ReleaseKey(linux.KEY_A) // Simulate releasing the "A" keySimulate pressing and releasing mouse or gamepad buttons:
device.PressButton(linux.BTN_LEFT) // Simulate pressing the left mouse button
device.ReleaseButton(linux.BTN_LEFT) // Simulate releasing the left mouse buttonUsed for devices like joysticks, touchpads, or drawing tablets. Send specific positions on an axis:
device.SendAbsoluteEvent(linux.ABS_X, 512) // Move to the middle of the X-axis
device.SendAbsoluteEvent(linux.ABS_Y, 256) // Move to a lower position on the Y-axisUsed for devices like mice. Send relative movements instead of absolute positions:
device.SendRelativeEvent(linux.REL_X, 10) // Move cursor 10 units to the right
device.SendRelativeEvent(linux.REL_Y, -5) // Move cursor 5 units upControl the state of LEDs, such as Caps Lock or Num Lock:
device.SetLed(linux.LED_CAPSL, true) // Turn on the Caps Lock LED
device.SetLed(linux.LED_CAPSL, false) // Turn off the Caps Lock LEDSend miscellaneous events, including raw scan codes, to simulate hardware-level key events:
device.SendMiscEvent(linux.MSC_SCAN, 0x1E) // Send the scan code for the "A" keyAfter sending input events, it’s important to synchronize them to ensure the input subsystem processes them correctly. Synchronization informs the system that a complete input report has been sent.
Synchronize a specific event type (e.g., SYN_MT_REPORT) to signal that the current event sequence is complete:
device.Sync(linux.SYN_MT_REPORT)Synchronize all pending input events. This is often used after sending a batch of input events to ensure they are processed together:
device.SyncReport()Why Synchronization is Important?
Synchronization ensures that all input events sent to the system are properly interpreted and applied. Without synchronization, the system may ignore or misinterpret events, especially when sending multiple inputs in rapid succession.
When the device is no longer needed, unregister it to release system resources:
err := device.Unregister()
if err != nil {
log.Fatalf("Failed to unregister virtual device: %v", err)
}Here’s how to simulate typing a string using a virtual keyboard:
package main
import (
"fmt"
virtual_device "github.com/jbdemonte/virtual-device"
"github.com/jbdemonte/virtual-device/linux"
)
func main() {
device := virtual_device.NewVirtualDevice().
WithBusType(linux.BUS_USB).
WithVendor(0xDEAD).
WithProduct(0xBABE).
WithVersion(0x01).
WithName("Virtual Keyboard").
WithKeys([]linux.Key{linux.KEY_A, linux.KEY_B, linux.KEY_C})
device.Register()
defer device.Unregister()
device.PressKey(linux.KEY_B)
device.ReleaseKey(linux.KEY_B)
}