forked from bendahl/uinput
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Split device logic up into separate source files.
- Loading branch information
Showing
8 changed files
with
623 additions
and
570 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package uinput | ||
|
||
import ( | ||
"io" | ||
"os" | ||
"fmt" | ||
) | ||
|
||
// A Keyboard is an key event output device. It is used to | ||
// enable a program to simulate HID keyboard input events. | ||
type Keyboard interface { | ||
// KeyPress will cause the key to be pressed and immediately released. | ||
KeyPress(key int) error | ||
|
||
// KeyDown will send a keypress event to an existing keyboard device. | ||
// The key can be any of the predefined keycodes from uinputdefs. | ||
// Note that the key will be "held down" until "KeyUp" is called. | ||
KeyDown(key int) error | ||
|
||
// KeyUp will send a keyrelease event to an existing keyboard device. | ||
// The key can be any of the predefined keycodes from uinputdefs. | ||
KeyUp(key int) error | ||
|
||
io.Closer | ||
} | ||
|
||
type vKeyboard struct { | ||
name []byte | ||
deviceFile *os.File | ||
} | ||
|
||
// CreateKeyboard will create a new keyboard using the given uinput | ||
// device path of the uinput device. | ||
func CreateKeyboard(path string, name []byte) (Keyboard, error) { | ||
validateDevicePath(path) | ||
validateUinputName(name) | ||
|
||
fd, err := createVKeyboardDevice(path, name) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return vKeyboard{name: name, deviceFile: fd}, nil | ||
} | ||
|
||
// KeyPress will issue a single key press (push down a key and then immediately release it). | ||
func (vk vKeyboard) KeyPress(key int) error { | ||
err := sendBtnEvent(vk.deviceFile, key, btnStatePressed) | ||
if err != nil { | ||
return fmt.Errorf("Failed to issue the KeyDown event: %v", err) | ||
} | ||
|
||
err = sendBtnEvent(vk.deviceFile, key, btnStateReleased) | ||
if err != nil { | ||
return fmt.Errorf("Failed to issue the KeyUp event: %v", err) | ||
} | ||
|
||
err = syncEvents(vk.deviceFile) | ||
if err != nil { | ||
return fmt.Errorf("sync to device file failed: %v", err) | ||
} | ||
return nil | ||
} | ||
|
||
// KeyDown will send the key code passed (see uinputdefs.go for available keycodes). Note that unless a key release | ||
// event is sent to the device, the key will remain pressed and therefore input will continuously be generated. Therefore, | ||
// do not forget to call "KeyUp" afterwards. | ||
func (vk vKeyboard) KeyDown(key int) error { | ||
err := sendBtnEvent(vk.deviceFile, key, btnStatePressed) | ||
if err != nil { | ||
return fmt.Errorf("Failed to issue the KeyDown event: %v", err) | ||
} | ||
|
||
err = syncEvents(vk.deviceFile) | ||
if err != nil { | ||
return fmt.Errorf("sync to device file failed: %v", err) | ||
} | ||
return nil | ||
} | ||
|
||
// KeyUp will release the given key passed as a parameter (see uinputdefs.go for available keycodes). In most | ||
// cases it is recommended to call this function immediately after the "KeyDown" function in order to only issue a | ||
// single key press. | ||
func (vk vKeyboard) KeyUp(key int) error { | ||
err := sendBtnEvent(vk.deviceFile, key, btnStateReleased) | ||
if err != nil { | ||
return fmt.Errorf("Failed to issue the KeyUp event: %v", err) | ||
} | ||
|
||
err = syncEvents(vk.deviceFile) | ||
if err != nil { | ||
return fmt.Errorf("sync to device file failed: %v", err) | ||
} | ||
return nil | ||
} | ||
|
||
// Close will close the device and free resources. | ||
// It's usually a good idea to use defer to call this function. | ||
func (vk vKeyboard) Close() error { | ||
return closeDevice(vk.deviceFile) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package uinput | ||
|
||
import "testing" | ||
|
||
// This test will confirm that basic key events are working. | ||
// Note that only Key1 is used here, as the purpose of this test is to ensure that the event handling for | ||
// keyboard devices is working. All other keys, defined in uinputdefs should work as well if this test passes. | ||
// Another thing to keep in mind is that there are certain key codes that might not be great candidates for | ||
// unit testing, as they may create unwanted side effects, like logging out the current user, etc... | ||
func TestBasicKeyboard(t *testing.T) { | ||
vk, err := CreateKeyboard("/dev/uinput", []byte("Test Basic Keyboard")) | ||
if err != nil { | ||
t.Fatalf("Failed to create the virtual keyboard. Last error was: %s\n", err) | ||
} | ||
|
||
err = vk.KeyPress(Key1) | ||
if err != nil { | ||
t.Fatalf("Failed to send key press. Last error was: %s\n", err) | ||
} | ||
|
||
err = vk.KeyDown(Key1) | ||
if err != nil { | ||
t.Fatalf("Failed to send key down event. Last error was: %s\n", err) | ||
} | ||
|
||
err = vk.KeyUp(Key1) | ||
if err != nil { | ||
t.Fatalf("Failed to send key up event. Last error was: %s\n", err) | ||
} | ||
|
||
err = vk.Close() | ||
|
||
if err != nil { | ||
t.Fatalf("Failed to close device. Last error was: %s\n", err) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
package uinput | ||
|
||
import ( | ||
"io" | ||
"os" | ||
"fmt" | ||
) | ||
|
||
// A Mouse is a device that will trigger an absolute change event. | ||
// For details see: https://www.kernel.org/doc/Documentation/input/event-codes.txt | ||
type Mouse interface { | ||
// MoveLeft will move the mouse cursor left by the given number of pixel. | ||
MoveLeft(pixel int32) error | ||
|
||
// MoveRight will move the mouse cursor right by the given number of pixel. | ||
MoveRight(pixel int32) error | ||
|
||
// MoveUp will move the mouse cursor up by the given number of pixel. | ||
MoveUp(pixel int32) error | ||
|
||
// MoveDown will move the mouse cursor down by the given number of pixel. | ||
MoveDown(pixel int32) error | ||
|
||
// LeftClick will issue a single left click. | ||
LeftClick() error | ||
|
||
// RightClick will issue a right click. | ||
RightClick() error | ||
|
||
// LeftPress will simulate a press of the left mouse button. Note that the button will not be released until | ||
// LeftRelease is invoked. | ||
LeftPress() error | ||
|
||
// LeftRelease will simulate the release of the left mouse button. | ||
LeftRelease() error | ||
|
||
// RightPress will simulate the press of the right mouse button. Note that the button will not be released until | ||
// RightRelease is invoked. | ||
RightPress() error | ||
|
||
// RightRelease will simulate the release of the right mouse button. | ||
RightRelease() error | ||
|
||
io.Closer | ||
} | ||
|
||
type vMouse struct { | ||
name []byte | ||
deviceFile *os.File | ||
} | ||
|
||
// CreateMouse will create a new mouse input device. A mouse is a device that allows relative input. | ||
// Relative input means that all changes to the x and y coordinates of the mouse pointer will be | ||
func CreateMouse(path string, name []byte) (Mouse, error) { | ||
validateDevicePath(path) | ||
validateUinputName(name) | ||
|
||
fd, err := createMouse(path, name) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return vMouse{name: name, deviceFile: fd}, nil | ||
} | ||
|
||
// MoveLeft will move the cursor left by the number of pixel specified. | ||
func (vRel vMouse) MoveLeft(pixel int32) error { | ||
return sendRelEvent(vRel.deviceFile, relX, -pixel) | ||
} | ||
|
||
// MoveRight will move the cursor right by the number of pixel specified. | ||
func (vRel vMouse) MoveRight(pixel int32) error { | ||
return sendRelEvent(vRel.deviceFile, relX, pixel) | ||
} | ||
|
||
// MoveUp will move the cursor up by the number of pixel specified. | ||
func (vRel vMouse) MoveUp(pixel int32) error { | ||
return sendRelEvent(vRel.deviceFile, relY, -pixel) | ||
} | ||
|
||
// MoveDown will move the cursor down by the number of pixel specified. | ||
func (vRel vMouse) MoveDown(pixel int32) error { | ||
return sendRelEvent(vRel.deviceFile, relY, pixel) | ||
} | ||
|
||
// LeftClick will issue a LeftClick. | ||
func (vRel vMouse) LeftClick() error { | ||
err := sendBtnEvent(vRel.deviceFile, evBtnLeft, btnStatePressed) | ||
if err != nil { | ||
return fmt.Errorf("Failed to issue the LeftClick event: %v", err) | ||
} | ||
|
||
err = sendBtnEvent(vRel.deviceFile, evBtnLeft, btnStateReleased) | ||
if err != nil { | ||
return fmt.Errorf("Failed to issue the KeyUp event: %v", err) | ||
} | ||
|
||
err = syncEvents(vRel.deviceFile) | ||
if err != nil { | ||
return fmt.Errorf("sync to device file failed: %v", err) | ||
} | ||
return nil | ||
} | ||
|
||
// RightClick will issue a RightClick | ||
func (vRel vMouse) RightClick() error { | ||
err := sendBtnEvent(vRel.deviceFile, evBtnRight, btnStatePressed) | ||
if err != nil { | ||
return fmt.Errorf("Failed to issue the RightClick event: %v", err) | ||
} | ||
|
||
err = sendBtnEvent(vRel.deviceFile, evBtnRight, btnStateReleased) | ||
if err != nil { | ||
return fmt.Errorf("Failed to issue the KeyUp event: %v", err) | ||
} | ||
|
||
err = syncEvents(vRel.deviceFile) | ||
if err != nil { | ||
return fmt.Errorf("sync to device file failed: %v", err) | ||
} | ||
return nil | ||
} | ||
|
||
// LeftPress will simulate a press of the left mouse button. Note that the button will not be released until | ||
// LeftRelease is invoked. | ||
func (vRel vMouse) LeftPress() error { | ||
err := sendBtnEvent(vRel.deviceFile, evBtnLeft, btnStatePressed) | ||
if err != nil { | ||
return fmt.Errorf("Failed press the left mouse button: %v", err) | ||
} | ||
err = syncEvents(vRel.deviceFile) | ||
if err != nil { | ||
return fmt.Errorf("sync to device file failed: %v", err) | ||
} | ||
return nil | ||
} | ||
|
||
// LeftRelease will simulate the release of the left mouse button. | ||
func (vRel vMouse) LeftRelease() error { | ||
err := sendBtnEvent(vRel.deviceFile, evBtnLeft, btnStateReleased) | ||
if err != nil { | ||
return fmt.Errorf("Failed to release the left mouse button: %v", err) | ||
} | ||
err = syncEvents(vRel.deviceFile) | ||
if err != nil { | ||
return fmt.Errorf("sync to device file failed: %v", err) | ||
} | ||
return nil | ||
} | ||
|
||
// RightPress will simulate the press of the right mouse button. Note that the button will not be released until | ||
// RightRelease is invoked. | ||
func (vRel vMouse) RightPress() error { | ||
err := sendBtnEvent(vRel.deviceFile, evBtnRight, btnStatePressed) | ||
if err != nil { | ||
return fmt.Errorf("Failed to press the right mouse button: %v", err) | ||
} | ||
err = syncEvents(vRel.deviceFile) | ||
if err != nil { | ||
return fmt.Errorf("sync to device file failed: %v", err) | ||
} | ||
return nil | ||
} | ||
|
||
// RightRelease will simulate the release of the right mouse button. | ||
func (vRel vMouse) RightRelease() error { | ||
err := sendBtnEvent(vRel.deviceFile, evBtnRight, btnStateReleased) | ||
if err != nil { | ||
return fmt.Errorf("Failed to release the right mouse button: %v", err) | ||
} | ||
err = syncEvents(vRel.deviceFile) | ||
if err != nil { | ||
return fmt.Errorf("sync to device file failed: %v", err) | ||
} | ||
return nil | ||
} | ||
|
||
// Close closes the device and releases the device. | ||
func (vRel vMouse) Close() error { | ||
return closeDevice(vRel.deviceFile) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package uinput | ||
|
||
import "testing" | ||
|
||
// This test confirms that all basic mouse events are working as expected. | ||
func TestBasicMouseMoves(t *testing.T) { | ||
relDev, err := CreateMouse("/dev/uinput", []byte("Test Basic Mouse")) | ||
if err != nil { | ||
t.Fatalf("Failed to create the virtual mouse. Last error was: %s\n", err) | ||
} | ||
|
||
err = relDev.MoveLeft(100) | ||
if err != nil { | ||
t.Fatalf("Failed to move mouse left. Last error was: %s\n", err) | ||
} | ||
|
||
err = relDev.MoveRight(150) | ||
if err != nil { | ||
t.Fatalf("Failed to move mouse right. Last error was: %s\n", err) | ||
} | ||
|
||
err = relDev.MoveUp(50) | ||
if err != nil { | ||
t.Fatalf("Failed to move mouse up. Last error was: %s\n", err) | ||
} | ||
|
||
err = relDev.MoveDown(100) | ||
if err != nil { | ||
t.Fatalf("Failed to move mouse down. Last error was: %s\n", err) | ||
} | ||
|
||
err = relDev.RightClick() | ||
if err != nil { | ||
t.Fatalf("Failed to perform right click. Last error was: %s\n", err) | ||
} | ||
|
||
err = relDev.LeftClick() | ||
if err != nil { | ||
t.Fatalf("Failed to perform right click. Last error was: %s\n", err) | ||
} | ||
|
||
err = relDev.LeftPress() | ||
if err != nil { | ||
t.Fatalf("Failed to perform left key press. Last error was: %s\n", err) | ||
} | ||
|
||
err = relDev.LeftRelease() | ||
if err != nil { | ||
t.Fatalf("Failed to perform left key release. Last error was: %s\n", err) | ||
} | ||
|
||
err = relDev.RightPress() | ||
if err != nil { | ||
t.Fatalf("Failed to perform right key press. Last error was: %s\n", err) | ||
} | ||
|
||
err = relDev.RightRelease() | ||
if err != nil { | ||
t.Fatalf("Failed to perform right key release. Last error was: %s\n", err) | ||
} | ||
|
||
err = relDev.Close() | ||
if err != nil { | ||
t.Fatalf("Failed to close device. Last error was: %s\n", err) | ||
} | ||
} |
Oops, something went wrong.