Giter Club home page Giter Club logo

uinput's Introduction

Uinput License: MIT Build Status codecov PkgGoDev Go Report Card

This package provides pure go wrapper functions for the LINUX uinput device, which allows to create virtual input devices in userspace. At the moment this package offers a virtual keyboard implementation as well as a virtual mouse device,gamepad, a touch pad device & a dial device.

The keyboard can be used to either send single key presses or hold down a specified key and release it later (useful for building game controllers). The mouse device issues relative positional change events to the x and y axis of the mouse pointer and may also fire click events (left and right click). For implementing things like region selects via a virtual mouse pointer, press and release functions for the mouse device are also included.

The touch pad, on the other hand can be used to move the mouse cursor to the specified position on the screen and to issue left and right clicks. Note that you'll need to specify the region size of your screen first though (happens during device creation).

Dial devices support triggering rotation events, like turns on a volume knob.

Please note that you will need to make sure to have the necessary rights to write to uinput. You can either chmod your uinput device, or add a rule in /etc/udev/rules.d to allow your user's group or a dedicated group to write to the device. You may use the following two commands to add the necessary rights for you current user to a file called 99-$USER.rules (where $USER is your current user's name):


echo KERNEL==\"uinput\", GROUP=\"$USER\", MODE:=\"0660\" | sudo tee /etc/udev/rules.d/99-$USER.rules
sudo udevadm trigger

Installation

Simply check out the repository and use the commands

go build && go install
The package will then be installed to your local respository, along with the package documentation. The documentation contains more details on the usage of this package.

Alternatively, if you'd like to use a specific version/tag of this library, you may use the gopkg.in service. To get v.1.x.x (latest stable v1), simply enter this on your command line:

go get gopkg.in/bendahl/uinput.v1

To import this version in your code use:

import "gopkg.in/bendahl/uinput.v1"

You may then refer to it as "uinput" in your code. For further details see: https://gopkg.in/bendahl/uinput.v1

Thanks to gopkg.in for offering this great service!

Usage

The following section explains some common ways to use this lib.

Using the virtual keyboard device:

package main

import "github.com/bendahl/uinput"
// alternatively (to use specific version), use this:
//import "gopkg.in/bendahl/uinput.v1"

func main() {
	// initialize keyboard and check for possible errors
	keyboard, err := uinput.CreateKeyboard("/dev/uinput", []byte("testkeyboard"))
	if err != nil {
		return
	}
	// always do this after the initialization in order to guarantee that the device will be properly closed
	defer keyboard.Close()

	// prints "a"
	keyboard.KeyPress(uinput.KeyA)

	// prints "A"
	// Note that you could use caps lock instead of using shift with KeyDown and KeyUp
	keyboard.KeyDown(uinput.KeyLeftshift)
	keyboard.KeyPress(uinput.KeyA)
	keyboard.KeyUp(uinput.KeyLeftshift)

	// prints "00000"
	for i := 0; i < 5; i++ {
		keyboard.KeyPress(uinput.Key0)
	}
}

Using the virtual mouse device:

package main

import "github.com/bendahl/uinput"
// alternatively (to use specific version), use this:
//import "gopkg.in/bendahl/uinput.v1"

func main() {
	// initialize mouse and check for possible errors
	mouse, err := uinput.CreateMouse("/dev/uinput", []byte("testmouse"))
	if err != nil {
		return
	}
	// always do this after the initialization in order to guarantee that the device will be properly closed
	defer mouse.Close()

	// mouse pointer will be moved up by 10 pixels
	mouse.MoveUp(10)
	// mouse pointer will be moved to the right by 10 pixels
	mouse.MoveRight(10)
	// mouse pointer will be moved down by 10 pixels
	mouse.MoveDown(10)
	// mouse pointer will be moved to the left by 10 pixels (we're back to where we started)
	mouse.MoveLeft(10)
        // move the mouse pointer by 100 pixels on the x and y axes (right and down in this case) 
        mouse.Move(100, 100)

	// click left
	mouse.LeftClick()
	// click right (depending on context a context menu may appear)
	mouse.RightClick()
	// click middle (usually the scroll wheel)
	mouse.MiddleClick()

	// hold down left mouse button
	mouse.LeftPress()
	// move mouse pointer down by 100 pixels while holding down the left key
	mouse.MoveDown(100)
	// release the left mouse button
	mouse.LeftRelease()

	// wheel up
	mouse.Wheel(false, 1)
	// wheel down
	mouse.Wheel(false, -1)
	// horizontal wheel left
	mouse.Wheel(true, 1)
	// horizontal wheel right
	mouse.Wheel(true, -1)
}

Using the virtual touch pad device:

package main

import "github.com/bendahl/uinput"
// alternatively (to use specific version), use this:
//import "gopkg.in/bendahl/uinput.v1"

func main() {
	// initialization of the touch device requires to set the screen boundaries
	// min and max values for x and y axis need to be set (usually, 0 should be a sane lower bound)
	touch, err := uinput.CreateTouchPad("/dev/uinput", []byte("testpad"), 0, 800, 0, 600)
	if err != nil {
		return
	}
	// always do this after the initialization in order to guarantee that the device will be properly closed
	defer touch.Close()

	// move pointer to the position 300, 200
	touch.MoveTo(300, 200)
	// press the left mouse key, holding it down
	touch.LeftPress()
	// move pointer to position 400, 400
	touch.MoveTo(400, 400)
	// release the left mouse key
	touch.LeftRelease()
	// create a single tab using a finger and immediately release
	touch.TouchDown()
	touch.TouchUp()

}

Using the virtual dial device:

package main

import "github.com/bendahl/uinput"
// alternatively (to use specific version), use this:
//import "gopkg.in/bendahl/uinput.v1"

func main() {
	// initialize dial and check for possible errors
	dial, err := uinput.CreateDial("/dev/uinput", []byte("testdial"))
	if err != nil {
		return
	}
	// always do this after the initialization in order to guarantee that the device will be properly closed
	defer dial.Close()

	// turn dial left
	dial.Turn(-1)
	// turn dial right
	dial.Turn(1)
}

License

The package falls under the MIT license. Please see the "LICENSE" file for details.

Current Status

2018-03-31: I am happy to announce that v1.0.0 is finally out! Go ahead and use this library in your own projects! Feedback is always welcome.

2019-03-24: Release v1.0.1 fixes a positioning issue that affects the touchpad. See issue #11 for details (positioning works now, but a (possibly) better solution is under investigation).

2019-07-24: Don't panic! As of version v1.0.2 the uinput library will provide an error instead of raising a panic in case of a faulty initialization. See pull request #12 for details (many thanks to muesli for the contribution).

2019-09-15: Add single touch event (resistive)

2019-12-31: Release v1.1.0 introduces yet another cool feature: Mouse wheel support. Thanks to muesli for this contribution!

2020-01-07: Release v1.2.0 introduces dial device support. Thanks again to muesli!

2020-11-15: Release v1.4.0 introduces a new Move(x, y) function to the mouse device along with a little cleanup and additional tests. Thanks robpre and MetalBlueberry for your valuable input!

2021-03-25: Release v1.4.1 fixes a keyboard issue that may affect android systems. See issue #24 for details.

2022-01-09: Release v1.5.0 introduces middle button support for the mouse. Thanks so much to @jbensmann for the great work! Also, thank you @djsavvy for the thorough review!

2022-02-11: Release v1.5.1 finally fixes the MoveTo(x, y) function of the touch pad device. Big shout out to @mafredri for this find! Thank you so much!

2022-09-01: Release v1.6.0 adds a new gamepad device. Thanks @gitautas for providing the implementation and thanks to @AndrusGerman for the inspiration! Also, thanks to @sheharyaar there is now a new function FetchSyspath() that returns the syspath to the device file.

2023-04-27: Release 1.6.1 fixes uinput functionality on Wayland. Thanks to @gslandtreter for this fix and for pointing out the relevant piece of documentation!

2023-05-10: Release 1.6.2 fixes uinput an issue introduced in version 1.6.1 that will break backward compatibility. The change will be reverted for now. Options to improve compatibility with newer systems are being evaluated. Thanks to @wenfer for the hint!

2023-11-22: Release 1.7.0 adds support for multitouch devices! Thanks to @SnoutBug for this addition! See issue #37 for details.

TODO

The current API can be considered stable and the overall functionality (as originally envisioned) is complete. Testing on x86_64 and ARM platforms (specifically the RaspberryPi) has been successful. If you'd like to use this library on a different platform that supports Linux, feel free to test it and share the results. This would be greatly appreciated.

  • Create Tests for the uinput package
  • Migrate code from C to GO
  • Implement relative input
  • Implement absolute input
  • Test on different platforms
    • x86_64
    • ARMv6 (RaspberryPi)
  • Implement functions to allow mouse button up and down events (for region selects)
  • Move CI pipeline

uinput's People

Contributors

bendahl avatar ghthor avatar gitautas avatar gslandtreter avatar muesli avatar robpre avatar sheharyaar avatar sleeplessy avatar snoutbug avatar wanjohiryan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

uinput's Issues

Mouse move function

I've noticed that in the last commit you prevent Move* functions from accepting negative values. I understand the reason and I agree.

The problem is that when you calculate mouse movement, usually the left/right or up/down movements are represented as negative/positive values. With this change, you force the users to do something like this

func horizontalMove(value int32) {
 if > 0 {
  MoveRight(value)
 }else{
  MoveLeft(-value)
 }
}

So, I wonder if it could be possible to have a generic method to move the cursor based on x,y coordinates no matter the direction.

func Move(x, y int32) error

Touchpad: Positioning cursor in upper left corner (x=0;y=0) requires workaround

After running some tests it seems as if positioning the cursor in the upper left corner cannot be achieved by setting both, x and y coordinates to 0. If any of the two is set to any other number, however, positioning works - unfortunately not positioning the cursor on x=0;y=0, of course. Using a negative number for either one (or both) of these values yields the desired result of positioning the cursor in the upper left corner. Tests using evtest reveal that no events are detected when 0 is set as a coordinate value for x and y. An equivalent C program shows the same behavior, which rules out any possible issues related to internal datatype representations or the like.

Important note to library users: If you need the touchpad functionality you should be safe when using the latest version (either Master or v1.0.1), as this version contains a fix/workaround. The issue is under investigation, however.

Keyboard layouts?

Hello, sorry if this isn't the place to ask but I'm not sure how to deal with keyboard layouts.
Someone showed me my program that uses this library types gobbledygook when you have a non-us keyboard layout set.
I found I could fix it in X by finding the virtual keyboard device ID with xinput -list and running setxkbmap -device <ID> us.

Is it possible to have the virtual keyboard device always set to the us layout?
I'd hope this would be at the linux/uinput level rather than be X specific but I don't know my stuff.

Thank you, I've really appreciated this library

Missing key codes in inputdefs.go

Hello,

there is an unclosed comment in inputdefs.go on line 226. I think this is caused by a multiline comment in the original include/linux/input-event-codes.h - this effectively comments out the consts following that line.

Fix ist trivial:
-- KeySwitchvideomode = 227 /*CycleBetweenAvailableVideo
++ KeySwitchvideomode = 227 /*CycleBetweenAvailableVideo outputs (Monitor/LCD/TV-out/etc) */

But nonetheless: Thank you for that great tool, Works like a charm! :-)

[Question] How change keyboard layout in uinput ?

Hello,
I have a question sometime I need to write in french with this lib and its seems to not work with azerty layout and accent like "é" or other not record if I change layout manualy in my sytem to querty it work without accent so

My question is how can I made work for it ?

In my default configuration which is azerty if I type "z" it will be show "w" and accent like "é" not showed

Have tried on dotool and ydotool who that use this lib and same issue its lib who didn't work with other layout or its config or something.

Ty for the lib

Add a usage example

It is generally a good practice to include at least one or two working example of a library usage ;)

Issue with Example

I've created a virtual keyboard

I can see the input device in /sys/devices/virtual/input

as input7

The key presses don't seem to be registered.

From what I can tell it's not showing up in xinput -list

Looking at input7 directory in /sys/devices/virtual/input I could see a directory event4

Using evtest I can see the keyboard events are being generated successfully.

Event: time 1624187132.489135, type 1 (EV_KEY), code 45 (KEY_X), value 1
Event: time 1624187132.489135, -------------- SYN_REPORT ------------
Event: time 1624187134.489502, type 1 (EV_KEY), code 45 (KEY_X), value 0
Event: time 1624187134.489502, -------------- SYN_REPORT ------------
Event: time 1624187134.681998, type 1 (EV_KEY), code 45 (KEY_X), value 1
Event: time 1624187134.681998, -------------- SYN_REPORT ------------
Event: time 1624187136.682230, type 1 (EV_KEY), code 45 (KEY_X), value 0
Event: time 1624187136.682230, -------------- SYN_REPORT ------------
Event: time 1624187136.682537, type 1 (EV_KEY), code 45 (KEY_X), value 1
Event: time 1624187136.682537, -------------- SYN_REPORT ------------
Event: time 1624187138.683337, type 1 (EV_KEY), code 45 (KEY_X), value 0
Event: time 1624187138.683337, -------------- SYN_REPORT ------------
Event: time 1624187138.683697, type 1 (EV_KEY), code 45 (KEY_X), value 1
Event: time 1624187138.683697, -------------- SYN_REPORT ------------
Event: time 1624187140.684101, type 1 (EV_KEY), code 45 (KEY_X), value 0
Event: time 1624187140.684101, -------------- SYN_REPORT ------------
Event: time 1624187144.894104, type 1 (EV_KEY), code 45 (KEY_X), value 1
Event: time 1624187144.894104, -------------- SYN_REPORT ------------
Event: time 1624187146.895425, type 1 (EV_KEY), code 45 (KEY_X), value 0
Event: time 1624187146.895425, -------------- SYN_REPORT ------------

But they're not being passed to xwindows - I'm thinking of trying to add it manually but am I doing something wrong or missing something simple :)

Looking at dmesg I can see the input being created

input: testkeyboard as /devices/virtual/input/input7

Thank you!

I just wanted to say thank you, this library was exactly what I was looking for.
I wrote a program called dotool which is pretty much the library as a command,
and used it for my voice input program.
The examples are great and it just worked.

Many thanks

John

Absolute movement not working.

Your examples and code suggest that one should be able to move the cursor to an exact location by using a touchpad but I am unable to get this to work. In fact touchpad.MoveTo does nothing for me but the clicks work fine and if I make a mouse instead, the relative movements work too.
I am curious if a touchpad is even capable of absolute movement this way. When I dump the events of my own touchpad with libinput for example, they are basically the same as a mouse, only relative movement values are given in the events.
Can absolute movement be done with this or am I stuck having to use robotgo for movement? Which from what I can tell is importing some C just to do the absolute movement. I would like to use one or the other but robotgo's clicking doesn't work right for me either... Go figure..

GNU/Linux on arm platform works

Tested on a self-made board with a personal hacked kernel (though i haven't edit the udev part),cross-compiling using the official go compiler with GOARCH=arm,it works perfect.But it seems to be blocked for about 3 seconds if send key events through a muiltithreaded client...need more test huh.

Keyboard issue on PrimeOS

Hi, I am working on PrimeOS which based on android x86. Using the stable v1 uinput.v1 version. It works nice while using mouse input.

But there is an issue when using keyboard input. Calling on keyboard.KeyPress only works on kernel but not application.

according to Android Source Site, Once i thought maybe something wrong with HID so that application could capture the input from virtual device.

After read a lot about linux drivers and some research, i got wrong way again....

Finially, i try to modify this code in keyboard.go file

for i := 0; i < keyMax; i++ {

change keyMax to 249, the number is the biggest number defined in keycodes.go.

It works.

I think maybe keyMax define too big (0x2ff), and cover some code in some system.

Hope this will help some people.

Thanks.

Compatibility with Wayland/new systems

It appears that on some more recent systems the uinput initialization does not work as expected (see #34). This was pointed out by @gslandtreter. The issue appeared on a system using Wayland. However, it should also be investigated whether the kernel version is a factor here. Once the root cause is confirmed this should be fixed in a backward-compatible manner, if possible without breaking the existing API.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.