Inputty


bzar

A Commando
Joined
Sep 22, 2008
Messages
4,500
Location
Finland
Website
Visit site
During the weekend I made a small doodad that might be of use to some of the developers here. Maybe others too, who knows?

I call the contraption inputty and it's in some barely usable state in github.

The point of inputty is to read evdev events and/or create uinput devices. It's all quite easily configurable using a QML file. You just describe the input and output devices with elements and wire them together using Qt's signal/slot system and tiny sparkles of JavaScript.

I actually made this to fake Pyra's input events on my desktop by wiring a gamepad to produce them, but it can be used for all sorts of stuff, like faking pyra controls on a devboard, faking pandora controls on a desktop, making three joysticks function as a keyboard or simulate an analog nub with your mouse.

I haven't added support for all input event types yet so no blinking LEDs using your last touch screen tap position as input, but it's just boilerplate handling that needs adding. If anyone has an actual use case for those I can add them.

The interface is currently a built-in QML file, but I intend to make this more of a tool to run such QML files. The current file (at the time I'm writing this, at least) shows a list of input devices available on the system and lets the user pick one. That device is then interpreted like a game pad (namely a WiiU pro controller I used while making it) and used to create pandora's game controls as input devices. Works on PNDManager, at least :)

I'm a bit surprised how well this worked :D
 
Last edited by a moderator:
This sounds really cool! I'd love to give this a whirl, unfortunately, I don't run Linux on my desktop.
 
I'm not familiar with QML or especially with JS, but looking at the files of those types in github the syntax is not too complicated. Examples of how to use it for certain use cases would help though, as while the syntax is clear, the semantics can be less so.
 
I'm not familiar with QML or especially with JS, but looking at the files of those types in github the syntax is not too complicated. Examples of how to use it for certain use cases would help though, as while the syntax is clear, the semantics can be less so.
What kind of examples are you looking for?  For QML in general the official documentation provided examples, though centered around graphical stuff, are quite comprehensive. For information on the event and device descriptions see uinput/evdev documentation. I've tried to model the device descriptions to be quite close to what actually moves inside linux event system. The input/output event element names map directly (as far as they're implemented in inputty) to event types in <linux/input.h>. The codes are the exact values of the event codes in the same header (I've processed the header's #defines into a JS library for convenience). The values are the ones carried with the events without any processing as well (though interpreted from signed 32-bit integers to JS number type when they pass through it).

If you have a specific example in mind that could make the system easier to understand I can, within reason, try to make a QML file that implements it. I intend to make one for mapping wiimotes into keyboard events for my own use.
 
Last edited by a moderator:
Well, I was a little bemused by 'You just describe the input and output devices with elements and wire them together using Qt's signal/slot system and tiny sparkles of JavaScript.' to start with. Which files do I need to modify to do this? Which contains the input devices, which the output devices, and which the relation between the two?

However, digging into github I assume inputcodes.js defines the function to convert between key names and key codes, and main.qml converts between those codes and pandora-related symbols, but I haven't found where those symbols are defined yet. I may just be misunderstanding QML there, as as I say I'm rather green when it comes to that. I could read the docs you've linked, but I tend to find I'm more productive if I just dive in first and look up the docs when I get stuck.

I should probably just build it and see what it does. From the look of it it's already set to convert from a gamepad to the pandora buttons, which should be useful for a few people as is.
 
Pandora game buttons and nubs are defined as three devices called "gpio-keys", "nub0" and "nub1". Libpnd searches through the available input devices looking for devices with these names. These devices generate event codes as listed in pandorawiki. In inputty's current main.qml these three devices are created with separate OutputDevice elements and output events are defined for each button and axis with OKey and OAbs elements. The event codes for these are fetched from the inputty-provided inputcodes.js library which is imported under the name Codes to the QML file.

Each OAbs, ORel and OKey (the three output event types defined so far) have values ("value" for OAbs and ORel, "pressed" for OKey) that when changed get sent to their parent device. What actually triggers that change is up to rest of the QML. Instead of an InputDevice you could add a Timer element there to toggle a button.

The gamepad is defined as an InputDevice. It needs a "path" property set to know which /dev/input/event* file to read. In the current main.qml this is selected by the user from a ListView defined near the bottom of the file. The list is populated from another inputty-provided element called EvdevDeviceListModel that monitors the current /dev/input/event* files and maintains a list of them associated with the reported device names. As devices appear/disappear that model gets updated and the ListView along with it. When the user clicks an entry the MouseArea is activated, setting the clicked device is set as the selected item on the list, which triggers a property value change in the InputDevice's path, triggering listening of that device.

An InputDevice needs its event types defined as well, so IAbs, IRel, IKey are used to do just that. Each of these input event elements have a value property (again, "pressed" or "value") that can be monitored  (by setting a handler to their "changed" signal) to react to their state changes. When someone, for instance presses the "A" button on the gamepad, and event is sent to the kernel, comes out of the /dev/input/event* pipe, caught by inputty and interpreted as a change to the relevant InputDevice's relevant input event element's value. Updating the value causes a "changed" signal to emit, which is then used to react to the press inside the QML file.

All you need to modify is the QML file. Well, a QML file. My current develop version no longer has a default one, but gets the QML file's path as a command line argument. For doing just about anything with the supported event types there's no need to touch any of the C++ or C code.
 
Last edited by a moderator:
Here's a bit more complex example. It monitors the system for connected wiimotes (by device name) and updates devices.wiimotes list of device paths accordingly. As the list changes the refresh function is called to populate the container element with suitable InputDevice/OutputDevice pairs, creating keyboard mappings for all the wiimotes in order of connection. The application also shows nice wiimote images in its main window to indicate how many wiimotes are found and configured. I use this on my HTPC.

If anyone wants to know about specific mechanics in this example I'll be glad to explain them :)

Also, the inputty main executable is now a tool that takes a path to a QML file as its argument.
 
Last edited by a moderator:
I made a simpler, non-GUI application using inputty as an example to some potential users. It listens to the first keyboard it finds (by name) and creates a new virtual keyboard that inputs an "x" after every "f" the user presses :p


import QtQuick 2.0
import EvdevDeviceListModel 1.0
import IODevices 1.0
import "qrc:/inputcodes.js" as Codes

Item {
InputDevice {
path: devices.path
IKey {
id: keyf
code: Codes.get("KEY_F")
}
}
OutputDevice {
name: "Fakeboard"
product: 1
vendor: 1
version: 1

OKey {
code: Codes.get("KEY_X")
pressed: keyf.pressed
}
}
EvdevDeviceListModel {
id: devices
property string path: getPath()
function getPath() {
for(var i = 0; i < devices.length; ++i) {
var device = devices.get(i);
console.log("Device " + device.name + " at " + device.path);
if(/.*keyboard.*/.test(device.name)) {
console.log("^ selected");
return device.path;
}
}
return "";
}
}
}

keyboard_fun.qml
 
Back
Top