keyboard emulation LinuxCNC - Page 1
Forum section: electronics / general

author: Jester
author_rank: Frequent Contributor
timestamp: July 03, 2024, 11:23:44 am
content: If I send keyboard characters via an Arduino board with a USB port to a Linux machines USB port, will the LinuxOS assume the characters are coming from a keyboard and act accordingly?If it's not that simple, what is required to make LinuxCNC think the Arduino is a keyboard?Thanks in advance.

author: Bicurico
author_rank: Super Contributor
timestamp: July 03, 2024, 02:27:38 pm
content: There are ready to go devices called RubberDuck, if I am not mistaken, which simulate a keyboard to execute predefined scripts.The Flipper Zero does it, too.Even if this is not the solution you want, you can peek into the F0 source code to see how it is done.

author: ralphrmartin
author_rank: Frequent Contributor
timestamp: July 03, 2024, 06:55:22 pm
content: It is most easily done using an Arduino with HID capabilities like the Leonardo.An example is given here:https://www.okdo.com/project/arduino-hid/

author: ledtester
author_rank: Super Contributor
timestamp: July 03, 2024, 09:30:13 pm
content: Arduino Unos and Nanos will present themselves to a computer as a USB serial device. You could then use a program such as:https://www.232key.com/which will continually read the serial port and inject the input into the kernal as keystrokes. For Linux have a look at the inputattach utility:https://wiki.archlinux.org/title/Serial_input_device_to_kernel_inputOther Arduinos can present themselves as a USB "human interface device" (HID) -- i.e. a keyboard / mouse / trackpad / etc.See:https://www.arduino.cc/reference/en/language/functions/usb/keyboard/for more info and library code.

author: Ian.M
author_rank: Super Contributor
timestamp: July 03, 2024, 11:32:23 pm
content: Yes you need an Arduino with a USB capable MCU on it. For AVR Arduinos, that's normally anything with an ATmega32U4, e.g. Leonardo or Pro Micro. Look at the example sketch 09.USB Keyboard.Genuine Arduino Uno R3 and Mega2560 boards have an ATmega16U2 programmed as a USB <=> UART bridge, which can be reprogrammed usingHoodLoader2to run sketches on it with USB support, e.g. to emulate a HID keyboard, but the ATmega16U2 has very little I/O apart from serial comms with the main MCU, so you'll probably end up with the extra complexity of two sketches, one on the main MCU to generate the key codes when triggered and pass them via UART to the ATmega16U2 running the HID Keyboard emulation sketch. There is Hoodloader2 HID-Bridge example you can base it on.Most generic clone Uno R3 and Mega2560 boards use various dedicated USB <=> UART bridge ICs that cant be reprogrammed as a general MCU, so cant use HoodLoader2.

author: Jester
author_rank: Frequent Contributor
timestamp: July 04, 2024, 07:44:22 am
content: Thanks for all the responses.I should have mentioned in my original post that I'm using a MKRZero (native USB port) for software development. Looks like the MKRZero supports the Arduino keyboard.h driver, so this appears like it might be pretty easy to implement.Quote from: ralphrmartin on July 03, 2024, 06:55:22 pmI'm going to start by adding keyboard.h and play with it a bit. I read that you can't be completely negligent and have your code spewing endless data towards the machine that it is connected to however in my case that should not be a problem as I'm using a handful of custom buttons to initiate so it will be coded to only send when a button is pressed.I'm away to the racesThanks for all the responses.

author: DiTBho
author_rank: Super Contributor
timestamp: July 21, 2024, 10:59:55 am
content: Is there anything forps/2?Edit: typo

author: Nominal Animal
author_rank: Super Contributor
timestamp: July 22, 2024, 12:00:56 am
content: With anything Linux, the easiest is to implement an USB HID or PS/2 keyboard in hardware, whichever the Linux-based host already uses. If you use a previously unused interface type, you may need to install the missing kernel modules (or, in the case of an optimized monolithic kernel, recompile a kernel with the necessary features enabled).The easiest way to implement new keyboard/mouse/trackpad/joystick/gamepad-like HID devices I know of currently, is to use aTeensy 4.0(or, if you happen to have one, aTeensy LCor aTeensy 3.2, which are no longer produced due to chipageddon and resulting IC availability and price issues) and theTeensyduino add-on to Arduino environmentprogramming. It has a native USB interface, and you can select the type of your device from the Arduino IDE menu (Tools>USB typein Arduino 1.8.x), including Serial, Raw HID, Keyboard, Keyboard + Touch, Keyboard + Mouse + Touch, Keyboard + Mouse + Joystick, Serial + Keyboard + Mouse + Joystick, Flight Sim Controls, or Flight Sim Controls + Joystick. For the ones with Keyboard, you can choose the keyboard layout (Tools>Keyboard layout) from a selection of some common ones. Then, your sketch only needs to examine the input pin states on the microcontroller, perhaps with software debouncing, and the exposedKeyboardobject to emit the keypresses – there is even a "send a sequence of keypresses" available which implements the necessary interstroke delays. It's a pity Teensy LC are no longer available; they were perfect for this kind of purpose –– similar to how ATmega32U4 and ATUSB1286 were earlier, among Atmel AVRs, both in hardware, price, and ease of development using free open source tools. (In Teensies, only the bootloader (on the AVR chip in Teensy 2.x, on the dedicated boot chip in Teensy LC/3.x/4.x) and board files are proprietary; the Arduino core and support files are open source, and evenkey schematicsare available. One can even design their own Teensy-like boards, as PJRC is happy to sell pre-programmed Teensybootloader chips, and thus take advantage of the Arduino+Teensyduino software environment for rapid development and experimentation.)All human interface device inputs are handled by theLinux Input Subsystem. There are Linux kernel drivers for e.g. GPIO pin matrix keypads that do the same, but you can also use theuinputmodule to synthesize a human interface device using userspace software (privileges are only needed during opening of the/dev/uinputdevice and instantiating the new device node); the syntheticuinputdevices behave exactly like USB HID hardware devices would. An application could theoretically distinguish between the two, but no userspace program I've ever seen the sources of actually try to, at all: there is no need to. It all Just Works.On the userspace application side, LinuxCNC uses the input event character devices directly (see e.g.lib/python/linux_event.pyin theLinuxCNC sources).This means that you need to implement either a real USB HID device, a PS/2 keyboard device (if the host exposes a PS/2 hardware interface), a kernel driver (for e.g. matrix keypads), or use a Linuxuinputuserspace service/daemon to convert other input formats like serial ports to HID events.The Input Subsystem splits HID devices into generic event devices, mice, and joysticks. I recommend using theEvent userspace API, and therefore the/dev/input/eventNcharacter devices (as named by/sys/class/input/eventN/device/namepseudofiles). Normally, all keyboard devices' events are forwarded to the currently active TTY by the kernel. For multi-seat support, a session manager grabs the corresponding keyboard and mouse character devices: if you use theEVIOCGRABioctl on the opened file descriptor, reading the events from the character device consumes them and causes them to no longer be forwarded/copied. Thus, if you want, you can easily write an userspace service that monitors HID devices, and grabs specific ones, consuming/translating/mapping their events to synthetic ones emitted viauinput, and thus showing up as a completely new hardware HID device. While this is easy, using a microcontroller with native USB support and USB HID library support is obviously easier.I personally am interested in using the cheap WCH CH552G/CH554G (currently < 0.90€ in singles at LCSC, USD $0.94 at JLCPCB assembly) for USB HID device experiments. One can usech55xduinoArduino add-on to program it in C (via the free and open sourceSDCCC compiler), and uploaded using Python, pyusb, and the chprog.py tool included in ch55xduino. There are other options too though, including for PlatformIO and even bare hardware development, mostly using SDCC C compiler since the MCU is based on MCS51 (enhanced 8051). Not only are the CH55x MCU's cheap, but they are easy to use, too, because they don't need an external crystal for USB 1.1 Low-Speed (1 Mbit/s) or Full-Speed (12 Mbit/s) communications; only a couple of 100nF/0.1µF bypass capacitors and maybe a 1-47µF bulk bypass capacitor, and optionally a switch and a 10kOhm resistor for switching it to bootloader mode when connecting to a host for reflashing the firmware using the built-in USB bootloader. Very, very easy!If CH55x for HID interests you, I recommend you check out Stefan Wagner's (wagiminator)CH552G MacroPad Plus, which has a rotary encoder with 12 programmable RGB LEDs, and 6 buttons with a programmable RGB LED each. Both the hardware design files and the software needed are licensed underCC-BY-SA 3.0, making it perfect for learning from.I use Linux myself, and developing and experimenting with this kind of device is real easy for me. For testing a new USB HID device, all I need to do is program it and plug it in, and it should Just Work. I can useevtestto examine the events it generates, or Wireshark (or similar tools) to examine the exact USB HID packets it generates (and their timing). As the Linux input subsystem was designed along the same lines as USB HID events, I've found it very easy to deal with both, with onlytimingcausing occasional issues on the microcontroller side (if and only if the "keyboard" interface does not examine and enforce the packet frequency set by the host) – an USB HID device cannot inject keypresses faster than a superfast robot tapping on an actual keyboard would.The same applies to most TV boxes, routers, NAS, and other appliances, as they too tend to be based on either Linux or Android (Android kernel being a derivative of the Linux kernel), and use the exact same input subsystem. Very useful for novel gadgets, for example if you create your own Kodi TV box, and want to experiment with gesture control of your TV. I'm happy to provide more detailed information (likethis, still perfectly valid over a decade later; this isthatstable of an interface), even down to examples (likethis one, which 2D transforms touch events and virtual button presses to input events). However, I'm of very little to no use if you develop on Windows, unless you use a virtual machine running some flavour of Linux in it, for example Linux Mint. (WSL/WSL2 is a translation layer, and is not sufficient/compatible enough for Linux-specific systems-level programming like this.)Apologies for the long post: I had lots to say.

author: Nominal Animal
author_rank: Super Contributor
timestamp: July 22, 2024, 01:31:12 am
content: Quote from: DiTBho on July 21, 2024, 10:59:55 amDo you meanPS/2, as in the port used for keyboards and mice before USB HID became ubiquitous?PS/2 port has 5V logic levels, a dedicated 5V supply pin you can draw up to 275mA from, a clock line, and a data line, both clock and data being open collector with pull-ups to 5V. The nominal clock frequency is between 10 kHz and 16.7 kHz, but the host can pull the clock line low similar to I²C/SMBus clock stretching. The data format is similar to various serial protocols: 1 start bit, 8 data bits, 1 odd parity bit, 1 stop bit, and an additional acknowledge bit for host-to-device transfers. It is very simple to bit-bang on a microcontroller, especially if one implements the simpler version that ignores host commands/messages/retransmit requests and parity checking, like old IBM AT keyboards did.Linux PS/2 keyboard and mouse drivers interface to the Linux Input Subsystem exactly the same way as generic USB HID devices do; the reports are just converted to input events by the driver used. (Note that the/dev/input/micedoes the inverse: it is always present, and provides the events from all mouse and touch devices in one of the PS/2 formats, selectable via an ioctl. This is for easy support of some very old software and hot-plugging mice. X, Wayland, and other environments and session managers –– and LinuxCNC –– use the event character devices instead.) From userspace, even when using the event device interface like LinuxCNC does, it does not matter whether the events were generated by an USB HID device or a PS/2 keyboard or mouse; they will look pretty much the same in any case. ("Pretty much" instead of "exactly" because driver-specific translation or configuration settings like keyboard mappings can sometimes (depending on the driver!) be used for minor adjustments, for example to support different keymaps and keyboard layouts. For USB HID devices, this is usually done at the userspace level, for example X or Wayland or the widget toolkit, though.For LinuxCNC, this means that if the host has PS/2 hardware, you only need to ensure the linux kernel used has a compatible PS/2 keyboard driver enabled or loaded. For SBCs, this is typically part of the platform driver. (Even on x86 and x86-64, many touchpads and laptop keyboards still use PS/2 interface, so the needed drivers tend to be enabled/loaded more often than not.)For interfacing an existing PS/2 keyboard to a host providing only an USB connector, you could use a WCH CH55x, and bit-bang the PS/2 interface. (For the clock pin, you'll want to use a pin that supports an interrupt on the falling edge, to detect when the host wants to send some data.)For interfacing an USB keyboard to a host providing only PS/2 ports, you could use a Teensy 4.0 or 4.1 (with an USB host port) and a voltage level translator like TXS0102, or a WCH CH554G/CH554T/CH559T (which do have USB host port support) at 5V logic level.For interfacing to PS/2 keyboards using any microcontroller in the Arduino environment, see thePS2Keyboard Arduino librarydeveloped by Paul Stoffregen, the author of the Teensy development boards, but note that it only supports a single instance of the PS/2 keyboard object. For CH55x, you'd need to port the C++ code to C for the SDCC compiler, but it's rather straightforward.For creating a custom keyboard/mouse device with a PS/2 interface, any reasonable microcontroller will do; the data clock rate is quite low, anything between 10 kHz and 16.7 kHz will do. If you can, pick one that can use 5V logic levels, and supports interrupt on the falling edge of the clock pin; otherwise you'll need a bidirectional voltage translator for both clock and data. I would personally consider WCH CH554T or CH559T MCUs (which have both USB host support and 5V logic levels on GPIO pins), so that both USB and PS/2 interfaces could be supported with the same hardware, leaving about 12 GPIO pins for the button matrix. (If you need more than 36 buttons you can get with a 6×6 matrix, use a separate counter or serial-to-parallel IC and N×8 matrix.)For the CH55xT-based solutions, I recommend taking a look at Wagiminator's CH55xTdevelopment boardsandGitHub sources and examples.

author: DiTBho
author_rank: Super Contributor
timestamp: July 22, 2024, 07:21:12 am
content: Quote from: Nominal Animal on July 22, 2024, 01:31:12 amYup, typo.I am only curious about existing similar projects or products.