From patchwork Sun Mar 26 16:48:12 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marcos Paulo de Souza X-Patchwork-Id: 9645073 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 14FEE601D7 for ; Sun, 26 Mar 2017 16:50:18 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 05C8D27F9F for ; Sun, 26 Mar 2017 16:50:18 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id EEDEC281C3; Sun, 26 Mar 2017 16:50:17 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.3 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, RCVD_IN_SORBS_SPAM, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 20FCC28066 for ; Sun, 26 Mar 2017 16:50:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751467AbdCZQt5 (ORCPT ); Sun, 26 Mar 2017 12:49:57 -0400 Received: from mail-qk0-f193.google.com ([209.85.220.193]:33471 "EHLO mail-qk0-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751464AbdCZQtz (ORCPT ); Sun, 26 Mar 2017 12:49:55 -0400 Received: by mail-qk0-f193.google.com with SMTP id p22so4862542qka.0; Sun, 26 Mar 2017 09:49:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=0rrkfttmf3sbuLHf7/Vqd9WVbaWQXylyPY70fGTRvBc=; b=QJsxANrxfvO8ZpM942IPA7ymypM6xK/oXjKLr9jaLH0KGQoolGvnvNBmG2F1Zh/wWf hePIOF7scSJOGcG8nQ1/KRdtW83ugZNKbO2+wGtIz6oJiFFDwqgTnfyl25GsLqa0ne/3 X2HnF4Rx7uvHDgyzosjJJGujYE5qPCOCBkCIJyTAYOzlJMd0hmbbHMAhFjvTuhbEGgpy eo/FhUfRiRK6wikNfRx963gUrxgDepPsQRPQF1p2C0xrwzsVxe6W1OSbOPKfzSHCn3yw tBsOg6QY90AeeKS79pZ3f/nqwZ+7ZyNfW0Yze2GmcX4R5W/JqII2RbnjTJrmXCPVMZyu Fz5g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=0rrkfttmf3sbuLHf7/Vqd9WVbaWQXylyPY70fGTRvBc=; b=ceeP3nwqyVx6dhTT/xDH4K9bSmZLDYoQ9l4E9Tevp47T6r1cmaAwlFMVKwW8wUWJej 9pIb5zZVKGEJa+y5ZplIxBL0B/NI3N6InxGQpt/DXJCKAb7b+6dTgTDDUtCpFeMhBYsY yQD5ZNSuEbNVY5P80gglg3sILMNyW0No9MsjEs2/BlHA9etroh7GBlFWFo/4/0I86Uft r4cvAHwi0phzVHdt+ddaEPlKp1WqZWZ4mCuxSldcztQ3KT4eaRjTYbK4YHWM8+NUhSbr 4RVLxZY2N71Af4/hkJ1A1Z4A8G59NFWAsspcy7+bh/NtLO+LXOPqVwlyp6E5ISxQ7YRY UxLg== X-Gm-Message-State: AFeK/H1r5lqY+R1ccPvUr9rOYKJCpS2w+hFkezJP87sWOjmcVl6enMdHJdEa7csb7OEndA== X-Received: by 10.55.22.218 with SMTP id 87mr16699679qkw.87.1490546983909; Sun, 26 Mar 2017 09:49:43 -0700 (PDT) Received: from xfiles.domain.name (187-7-46-166.bnut3700.dsl.brasiltelecom.net.br. [187.7.46.166]) by smtp.gmail.com with ESMTPSA id s28sm6123239qts.65.2017.03.26.09.49.41 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 26 Mar 2017 09:49:43 -0700 (PDT) From: Marcos Paulo de Souza To: corbet@lwn.net, linux-doc@vger.kernel.org, dmitry.torokhov@gmail.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, peter.hutterer@who-t.net Cc: Marcos Paulo de Souza Subject: [PATCH v3] Documentation: Input: Add uinput documentation Date: Sun, 26 Mar 2017 13:48:12 -0300 Message-Id: <20170326164821.10928-2-marcos.souza.org@gmail.com> X-Mailer: git-send-email 2.9.3 In-Reply-To: <20170326164821.10928-1-marcos.souza.org@gmail.com> References: <20170326164821.10928-1-marcos.souza.org@gmail.com> Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Signed-off-by: Marcos Paulo de Souza --- v2 -> v3: Changes in libevdev's description (suggested by Peter) Added uinput version check when using the old interface (suggested by Peter) Removed section numbers from sections, sphinx creates these indexes (suggestion by Jon) v1 -> v2: Changes all over the place, including better descriptions (suggested by Peter) Added comments about the need of a sleep call (suggested by Peter) Documentation/input/uinput.rst | 207 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 Documentation/input/uinput.rst diff --git a/Documentation/input/uinput.rst b/Documentation/input/uinput.rst new file mode 100644 index 0000000..f606989 --- /dev/null +++ b/Documentation/input/uinput.rst @@ -0,0 +1,207 @@ +============= +uinput module +============= + +Introduction +============ + +uinput is a kernel module that makes it possible to emulate input devices from +userspace. By writing to the module's /dev/uinput (or /dev/input/uinput), a +process can create a virtual device with specific capabilities. +Once created, the process can send events through that virtual device. + +Interface +========= + +:: + + linux/uinput.h + +The uinput header defines ioctls to create, setup and destroy virtual devices. + +libevdev +======== + +libevdev is a wrapper library for evdev devices that provides interfaces to +create uinput devices and send events. libevdev is less error-prone than +accessing uinput directly and should be considered for new software + +For examples and more information about libevdev: +https://www.freedesktop.org/software/libevdev/doc/latest/ + +Examples +======== + +Keyboard events +--------------- + +This first example shows how to create a new virtual device and how to send a +key event. All default imports and error handlers were removed for the sake of +simplicity. + +.. code-block:: c + + #include + + int fd; + + void emit(int type, int code, int val) + { + struct input_event ie; + + ie.type = type; + ie.code = code; + ie.value = val; + /* below timestamp values are ignored */ + ie.time.tv_sec = 0; + ie.time.tv_usec = 0; + + write(fd, &ie, sizeof(ie)); + } + + int main() { + struct uinput_setup usetup; + + fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK); + + /* the ioctls below enables the to be created device to key + * events, in this case the space key + */ + ioctl(fd, UI_SET_EVBIT, EV_KEY); + ioctl(fd, UI_SET_KEYBIT, KEY_SPACE); + + memset(&usetup, 0, sizeof(usetup)); + usetup.id.bustype = BUS_USB; + usetup.id.vendor = 0x1234; /* sample vendor */ + usetup.id.product = 0x5678; /* sample product */ + strcpy(usetup.name, "Example device"); + + ioctl(fd, UI_DEV_SETUP, &usetup); + ioctl(fd, UI_DEV_CREATE); + + /* + * On UI_DEV_CREATE the kernel creates the device nodes for this device. + * Insert a pause so that userspace has time to detect, initialize the + * new device, and can start to listen to events from this device + */ + sleep(1); + + /* key press, report the event, send key release, and report again */ + emit(EV_KEY, KEY_SPACE, 1); + emit(EV_SYN, SYN_REPORT, 0); + emit(EV_KEY, KEY_SPACE, 0); + emit(EV_SYN, SYN_REPORT, 0); + + ioctl(fd, UI_DEV_DESTROY); + close(fd); + + return 0; + } + +Mouse movements +--------------- + +This example shows how to create a virtual device that behaves like a physical +mouse. + +.. code-block:: c + + #include + + /* emit function is identical to of the first example */ + + struct uinput_setup usetup; + int i = 50; + + fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK); + + /* enable mouse button left and relative events */ + ioctl(fd, UI_SET_EVBIT, EV_KEY); + ioctl(fd, UI_SET_KEYBIT, BTN_LEFT); + + ioctl(fd, UI_SET_EVBIT, EV_REL); + ioctl(fd, UI_SET_RELBIT, REL_X); + ioctl(fd, UI_SET_RELBIT, REL_Y); + + memset(&usetup, 0, sizeof(usetup)); + usetup.id.bustype = BUS_USB; + usetup.id.vendor = 0x1234; /* sample vendor */ + usetup.id.product = 0x5678; /* sample product */ + strcpy(usetup.name, "Example device"); + + ioctl(fd, UI_DEV_SETUP, &usetup); + ioctl(fd, UI_DEV_CREATE); + + /* + * On UI_DEV_CREATE the kernel creates the device nodes for this device. + * Insert a pause so that userspace has time to detect, initialize the + * new device, and can start to listen to events from this device + */ + sleep(1); + + /* moves the mouse diagonally, 5 units per axis */ + while (i--) { + emit(EV_REL, REL_X, 5); + emit(EV_REL, REL_Y, 5); + emit(EV_SYN, SYN_REPORT, 0); + usleep(15000); + } + + ioctl(fd, UI_DEV_DESTROY); + close(fd); + + return 0; + +uinput old interface +-------------------- + +Before uinput version 5, there wasn't a proper ioctl to setup a virtual device. +In this case, the user neesa to fill a different struct and call write o the +uinput file descriptor to configure the new uinput device. + +.. code-block:: c + + #include + + /* emit function is identical to of the first example */ + + struct uinput_user_dev uud; + int version; + + fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK); + ioctl(fd, UI_GET_VERSION, &version); + + if (version < 5) { + /* + * the ioctls below enables the to be created device to key + * events, in this case the space key + */ + ioctl(fd, UI_SET_EVBIT, EV_KEY); + ioctl(fd, UI_SET_KEYBIT, KEY_SPACE); + + memset(&uud, 0, sizeof(uud)); + snprintf(uud.name, UINPUT_MAX_NAME_SIZE, "uinput old interface"); + write(fd, &uud, sizeof(uud)); + + ioctl(fd, UI_DEV_CREATE); + + /* + * On UI_DEV_CREATE the kernel creates the device nodes for this device. + * Insert a pause so that userspace has time to detect, initialize the + * new device, and can start to listen to events from this device + */ + sleep(1); + + /* key press, report the event, send key release, and report again */ + emit(EV_KEY, KEY_SPACE, 1); + emit(EV_SYN, SYN_REPORT, 0); + emit(EV_KEY, KEY_SPACE, 0); + emit(EV_SYN, SYN_REPORT, 0); + + ioctl(fd, UI_DEV_DESTROY); + } + + close(fd); + + return 0; +