Cannot get a RPi Zero to emulate _both_ a USB Keyboard _and_ Mouse - keyboard

I am trying to get my RPi Zero W to emulate a keyboard and mouse. I can get it to emulate a keyboard or a mouse successfully, but not both at the same time.
I followed the instructions at iStickToIt and Key Mime Pi to successfully emulate a keyboard. Alternatively I followed the instructions here to successfully emulate a mouse. Both work fine on their own. However I don't know how to emulate both mouse and keyboard at once.
I thought that perhaps I just needed to combine the information and define 2 functions for the 1 USB gadget, creating /dev/hidg0 and /dev/hidg1, but only the 1st one works. Below is my combined code - you can see that the Report Length and Report Descriptor is different for keyboard and mouse. But only /dev/hidg0 works (keyboard).
Can you suggest where I am going wrong?
#!/usr/bin/env bash
# Adapted from https://github.com/girst/hardpass-sendHID/blob/master/README.md
# Exit on first error.
set -e
# Treat undefined environment variables as errors.
set -u
modprobe libcomposite
cd /sys/kernel/config/usb_gadget/
mkdir -p g1
cd g1
echo 0x1d6b > idVendor # Linux Foundation
echo 0x0104 > idProduct # Multifunction Composite Gadget
echo 0x0100 > bcdDevice # v1.0.0
echo 0x0200 > bcdUSB # USB2
STRINGS_DIR="strings/0x409"
mkdir -p "$STRINGS_DIR"
echo "82bc64754ca7384d7c90" > "${STRINGS_DIR}/serialnumber"
echo "Anykey" > "${STRINGS_DIR}/manufacturer"
echo "Generic USB Keyboard" > "${STRINGS_DIR}/product"
# -- Function 1: Keyboard -----------------------------------------------
FUNCTIONS_DIR="functions/hid.usb0"
mkdir -p "$FUNCTIONS_DIR"
echo 1 > "${FUNCTIONS_DIR}/protocol"
echo 0 > "${FUNCTIONS_DIR}/subclass" # No subclass
echo 8 > "${FUNCTIONS_DIR}/report_length"
# Write the report descriptor
# Source: https://www.kernel.org/doc/html/latest/usb/gadget_hid.html
echo -ne \\x05\\x01\\x09\\x06\\xa1\\x01\\x05\\x07\\x19\\xe0\\x29\\xe7\\x15\\x00\\x25\\x01\\x75\\x01\\x95\\x08\\x81\\x02\\x95\\x01\\x75\\x08\\x81\\x03\\x95\\x05\\x75\\x01\\x05\\x08\\x19\\x01\\x29\\x05\\x91\\x02\\x95\\x01\\x75\\x03\\x91\\x03\\x95\\x06\\x75\\x08\\x15\\x00\\x25\\x65\\x05\\x07\\x19\\x00\\x29\\x65\\x81\\x00\\xc0 > "${FUNCTIONS_DIR}/report_desc"
CONFIG_INDEX=1
CONFIGS_DIR="configs/c.${CONFIG_INDEX}"
mkdir -p "$CONFIGS_DIR"
echo 250 > "${CONFIGS_DIR}/MaxPower"
CONFIGS_STRINGS_DIR="${CONFIGS_DIR}/strings/0x409"
mkdir -p "$CONFIGS_STRINGS_DIR"
echo "Config ${CONFIG_INDEX}: ECM network" > "${CONFIGS_STRINGS_DIR}/configuration"
ln -s "$FUNCTIONS_DIR" "${CONFIGS_DIR}/"
# -- Function 2: Mouse --------------------------------------------------
FUNCTIONS_DIR="functions/hid.usb1"
mkdir -p "$FUNCTIONS_DIR"
echo 1 > "${FUNCTIONS_DIR}/protocol"
echo 0 > "${FUNCTIONS_DIR}/subclass" # No subclass
echo 3 > "${FUNCTIONS_DIR}/report_length"
# Write the report descriptor
# Source: https://www.kernel.org/doc/html/latest/usb/gadget_hid.html
echo -ne \\x05\\x01\\x09\\x02\\xa1\\x01\\x09\\x01\\xa1\\x00\\x05\\x09\\x19\\x01\\x29\\x03\\x15\\x00\\x25\\x01\\x95\\x03\\x75\\x01\\x81\\x02\\x95\\x01\\x75\\x05\\x81\\x03\\x05\\x01\\x09\\x30\\x09\\x31\\x15\\x81\\x25\\x7f\\x75\\x08\\x95\\x02\\x81\\x06\\xc0\\xc0 > "${FUNCTIONS_DIR}/report_desc"
CONFIG_INDEX=2
CONFIGS_DIR="configs/c.${CONFIG_INDEX}"
mkdir -p "$CONFIGS_DIR"
echo 250 > "${CONFIGS_DIR}/MaxPower"
CONFIGS_STRINGS_DIR="${CONFIGS_DIR}/strings/0x409"
mkdir -p "$CONFIGS_STRINGS_DIR"
echo "Config ${CONFIG_INDEX}: ECM network" > "${CONFIGS_STRINGS_DIR}/configuration"
ln -s "$FUNCTIONS_DIR" "${CONFIGS_DIR}/"
ls /sys/class/udc > UDC
chmod 777 /dev/hidg0
chmod 777 /dev/hidg1

I have found the answer to my own question. The mistake is in the 2 lines which say:
ln -s "$FUNCTIONS_DIR" "${CONFIGS_DIR}/"
Having set up 2 functions directories, they should both be linked into the same config directory and not 2 different config directories as I have done. So in my example one function directory was linked into "configs/c.1" and the other was linked into "configs/c.2", whereas they should both have been linked into "configs/c.1".
You can see a working report descriptor for both mouse and keyboard in the code for TinyPilot here. Note that this uses a slightly different mouse message format from my example above.
When you have set it up correctly use /dev/hidg0 for the keyboard and /dev/hidg1 for the mouse.
(With thanks to Michael Lynch, whose open-source RPi KVM project TinyPilot can be referred to here and here.)

Related

Accessing GPIO on OrangePI PC Plus ( H3 ) on Armbian 3.4.113 and newer

how to access GPIO on Armbian 3.4.113 on OrangePi PC plus ( SoC H3 ) now that the old method using gpio-sunxi and editing the .fex-file is obsolete ( want to share this ... )
The general proceeding is described in https://linux-sunxi.org/GPIO
The GPIO pins are accessed via the sysfs file system. For enabling a specific pin it has to be exported into /sys/class/gpio/export
for pin PA1 the command would be echo 1 > sys/class/gpio/export. The pin number is calculated by the following formula :
(position of letter in alphabet - 1) * 32 + pin number
PA1 has pin number ('A' is the 1st letter ) 1, PB2 has pin number 34 ('B' is 2nd letter ), PG7 has pin number 199( 'G' is 7th letter (7-1)*32+7=199 )
the positions on the physical header are different again, cf. the graphic below
so for enabling PG7 that is pin 40 on the physical header can be used
echo 199 > sys/class/gpio/export
source of image : https://orange314.com/Hardware
normally the echo command like echo "199" sys/class/gpio/export gives a Permission denied error
an easy solution are the following:
To do a one-off manipulation of a GPIO pin, you have to start a
separate shell as a superuser first, then use echo. For instance to
turn pin A10 on:
$ sudo sh
# echo 10 > /sys/class/gpio/export
# echo out > /sys/class/gpio/gpio10/direction
# echo 1 > /sys/class/gpio/gpio10/value
Or you can use tee to avoid creating a subshell:
$ echo 10 | sudo tee /sys/class/gpio/export
$ echo out | sudo tee /sys/class/gpio/gpio10/direction
$ echo 1 | sudo tee /sys/class/gpio/gpio10/value
source: https://forum.armbian.com/index.php?/topic/4052-problem-using-gpio-pins-on-legacy-kernel/
An alternative would be to create a new group and change the group of the /sys/class/gpio directory to this new group :
you can create a group called gpio, add the user to it, export the gpio
etc as follows:
sudo groupadd gpio
sudo usermod -aG gpio <myusername>
su <myusername>
sudo chgrp gpio /sys/class/gpio/export
sudo chgrp gpio /sys/class/gpio/unexport
sudo chmod 775 /sys/class/gpio/export
sudo chmod 775 /sys/class/gpio/unexport
This gives your user the ability to export and un-export.
Once you export the pins you can chgrp and chmod them as well (don't
forget their contents) and use them as usual.
echo "18" > /sys/class/gpio/export
chgrp -HR /sys/class/gpio/gpio18
chmod -R 775 /sys/class/gpio/gpio18
Now your user has access to the first GPIO pin 18.
source : https://www.raspberrypi.org/forums/viewtopic.php?t=5185
when executing the echo with permissions a new directory appears in /sys/class/gpio i.e. for PA2 ( which is pin number 2 and number 22 on the physical header ) it is /sys/class/gpio/gpio2
to configure pin number 2 you have to write specific values to the files in /sys/class/gpio/gpio2
for i.e. setting pin 2 to output and 'high' write
echo "out" > /sys/class/gpio/gpio2/direction
echo "1" > /sys/class/gpio/gpio2/value
when shutting down GPIO the pins should be unexported with i.e.
echo 2 > /sys/class/gpio/unexport for pin 2 ( PA2, number 22 on the physical header )
An alternative for accessing GPIO is using python, however for the H3 based boards the WiringOP is not available yet

How to - multiple dropbox instances in Linux?

After looking around online it seems pretty easy to have multiple dropbox accounts running. All you have to do is change an environmental variable and then run dropbox. However, I've tried editing the .desktop file (see .desktop file specification) so the Exec line is changed from this:
Exec=dropbox start -i
which is the default, to this:
Exec=env "HOME\=/home/reg/.dropbox-alt" dropbox start -i
which from everything I have read should work. I've also tried all the variations of escaping and quoting like:
Exec=env HOME\=/home/reg/.dropbox-alt dropbox start -i
Exec=env "HOME=/home/reg/.dropbox-alt" dropbox start -i
Exec=env HOME=/home/reg/.dropbox-alt dropbox start -i
and nothing seems to launch dropbox. However if I try the same line in bash it tries to launch but falls short but that's only because dropbox is looking for a GUI. That being the case I would have thought that doing the above in the .desktop file would work but I get nothing at all happening.
I'm doing this without any dropbox instances running already so it cannot be that dropbox is looking for other instances and stopping itself from loading another instance.
If I try this in the .desktop file:
Exec=env dropbox start -i
It will launch dropbox but now it's the default instance which has no benefit.
Can anyone tell me what I'm missing to make this work?
Open a terminal and paste the following commands:
$ mkdir "$HOME"/.dropbox-alt
$ ln -s "$HOME/.Xauthority" "$HOME/.dropbox-alt/"
$ HOME="$HOME/.dropbox-alt"
$ /home/$USER/.dropbox-dist/dropboxd
Dropbox setup wizard window will appear. Finish the setup similarly as described in Method -1
start Dropbox from terminal
$ /home/$USER/.dropbox-dist/dropboxd
start Alternate-Dropbox from terminal
$ HOME="$HOME/.dropbox-alt" && /home/$USER/.dropbox-dist/dropboxd
Note:
You can create a small script with the above commands to start Dropbox.
One can put the script at startup. Don't forget to give the script execution permission.
chmod +x /path/to/script
I have tested the second method. Hope it will be useful.
#!/bin/bash
HOME_DIR=$HOME
DROPBOXES=("$HOME/.dropboxes/personal" "$HOME/.dropboxes/business")
function start_dropbox() {
HOME=$HOME_DIR
local flag
local home_dir
local OPTIND;
local verbose=0
local wait=0
while getopts p:vw opt; do
case $opt in
p) home_dir="$(echo $OPTARG | sed 's:/*$::')/" ;;
v) verbose=1 ;;
w) wait=1 ;;
*) ;;
esac
done
shift $((OPTIND-1))
# Test if the process is already running
local pid=$(ps aux|grep "${home_dir}.dropbox-dist"|grep -v 'grep'|tr -s ' '| cut -d' ' -f 2)
if [ -n "$pid" ]
then
echo "Process already running with home dir. of: $home_dir"
return 8 # Process already running
fi
# Create home directory if it doesn't exist
if [ ! -e "$home_dir" ]
then
if mkdir -p "$home_dir";
then
echo "Created directory: $home_dir"
else
echo "Failed to create directory: $home_dir"
return 9 # Failed
fi
fi
# Set up so works with GUI from command line
xauthority="${home_dir}.Xauthority"
if [ ! -e "$xauthority" ]
then
ln -s "$HOME/.Xauthority" "$xauthority"
fi
HOME="$home_dir"
# Start the dropbox daemon
if [[ $verbose -gt 0 ]]; then
echo '~/.dropbox-dist/dropboxd & '$home_dir
fi
~/.dropbox-dist/dropboxd &
if [[ $wait -eq 0 ]]; then
sleep 2 # Give each instance time to startup completely before starting another one
else
read -n 1 -s -p 'Press any key to continue.'
echo
fi
}
function start_dropboxes() {
local dropbox
for dropbox in "${DROPBOXES[#]}"
do
start_dropbox $# -p "$dropbox"
done
}
#
# For testing & setup we can choose just one to startup
#
while getopts f:wv opt; do
case $opt in
f) start_dropbox -p "${DROPBOXES[$OPTARG]}" # NOTE: bash array indexes start at 0.
exit ;;
*) ;;
esac
done
OPTIND=1
start_dropboxes $#
Not being able to install multiple instances of same software on a single machine is a typical case of what is called as Software Conflict where two such instances would compete for resources such as memory, peripheral device, register, network port, etc.
However, we could use a container-based virtualization technology called as Docker to run multiple instances of a software on the same machine in loosely isolated environments called as Containers.
The best part of this solution is that it would work on any platform, as containers are meant to portable.
I recently wrote a blog on it, explaining steps to containerise dropbox instances using docker.

Ubuntu sound/network/USB trouble after suspend , how to restart

I had a lengthy problem with Ubuntu 14.04 with Lenovo S20-30: after resuming suspended session some things break:
USB stops recognizing devices
due to this the webcam and bluetooth stop working
NetworkManager goes to sleep and no internet connections are made
Sound stops or hangs up in false "Headphones" mode,
or "Dummy" output is shown in Settings->Sound
This is a summary of many different answers (from the stack and others) on this topic which worked consistently for me:
to restart USB run in terminal as root e.g. in a scipt:
#!/bin/bash
for I in $(ls /sys/bus/pci/drivers/xhci_hcd/|grep : ) ; do
echo $I
sudo echo $I > /sys/bus/pci/drivers/xhci_hcd/unbind
sudo echo $I > /sys/bus/pci/drivers/xhci_hcd/bind
done
to wake up (resume) NetworkManager as normal user
#!/bin/bash
nmcli nm sleep false
to restart the sound as root
#!/bin/bash
pulseaudio -k ; sudo modprobe -fr snd_hda_intel; sudo modprobe snd-hda-intel
this solves the common message which came up upon restart:
modprobe: FATAL: Module snd_hda_intel is in use.
Adapting the answer by IljaBek into an automate one. Place the following script in a new file called:
/etc/pm/sleep.d/20_usb_unbind_bind
#!/bin/sh
# Action script to ubind then bind USB devices after sleep
#
case "${1}" in
hibernate)
# nothing
;;
resume|thaw)
for I in $(ls /sys/bus/pci/drivers/xhci_hcd/|grep : ) ; do
echo $I > /sys/bus/pci/drivers/xhci_hcd/unbind
echo $I > /sys/bus/pci/drivers/xhci_hcd/bind
done
;;
esac
Make the file executable with sudo chmod 755 /etc/pm/sleep.d/20_usb_unbind_bind

Bash tool to put an icon on taskbar?

I am trying to create a tiny application on my Ubuntu machine. What I want to do is put to an icon on my taskbar beside the volume, and internet connectivity options. I understand that there is a notify-send command in bash that I can use, or even switch to Qt but that seems to be an overkill for the problem. Concretely, is there a way to create an icon on Ubuntu taskbar with bash, and change its color or text periodically?
For a very shell friendly way to quickly get tray apps working use yad (specifically yad --notification). It allows you to dynamically change icons, set click event handlers and build a custom context menu. For example:
yad --notification --command='echo hello world' --image=myicon.png
Will echo 'hello world' on click. Or:
yad --notification --command='echo hello world' --image=myicon.png --listen
Will read it's standard input waiting for commands to change icons, change visibility, open menu, trigger action and more.
More advanced example using yad.
Shows how to handle click in the same script and how to change the icon on the click. Also shows how to create a simple update loop and exit cleanly.
# stop on error (always good practice)
set -e
# create a FIFO file, used to manage the I/O redirection from shell
PIPE=$(mktemp -u --tmpdir ${0##*/}.XXXXXXXX)
mkfifo $PIPE
export PIPE
# attach a file descriptor to the file
exec 3<> $PIPE
# add handler to manage process shutdown
function on_exit() {
# send command to yad through pipe
echo "quit" >&3
rm -f $PIPE
}
trap on_exit EXIT
function update_icon() {
exec 3<> $PIPE # just in case
echo "icon:/path/to/some/icon" >&3
}
export -f update_icon
# add handler for tray icon left click
function on_click() {
exec 3<> $PIPE # required
echo "clicked"
echo "icon:/path/to/icon" >&3
update_icon
}
export -f on_click
# add handler for right click menu Quit entry function
on_quit() {
# signal to the script that it should end when this file is created
echo "quit" > ./quit.txt
exec 3<> $PIPE # required
echo "quit" >&3
}
export -f on_quit
# Use a file to indicate a quit command to the script
# Make sure it is gone before we start the program to avoid immediate exit
rm -f quit.txt
# create the notification icon with right click menu and Quit option
yad --notification \
--listen \
--image="/path/to/icon" \
--text="demo tray icon" \
--menu="Quit!bash -c on_quit" \
--no-middle \
--command="bash -c on_click" <&3 &
# allow user to end the loop from icon right click Quit menu option
while [ ! -f "quit.txt" ]; do
#echo "Press [CTRL+C] to stop.."
update_icon
sleep 60
done
# clean up after quit
rm quit.txt
Based on:
https://code.google.com/archive/p/yad/wikis/NotificationIcon.wiki
https://sourceforge.net/p/yad-dialog/wiki/NotificationIcon/
https://groups.google.com/g/yad-common/c/DT8q1vJ-yOQ
I'm not a bash expert, so fixes are welcome.
yad is available for many distros as a standard package. On Debian for example it can be installed by apt install yad.
Take a look at alltray; maybe it's your solution.
From its website:
Description
With AllTray you can dock any application with no native tray icon (like Evolution, Thunderbird, Terminals) into the system tray. A high-light feature is that a click on the "close" button will minimize back to system tray. It works well with Gnome, KDE, XFCE 4*, Fluxbox* and WindowMaker*. Xmms is supported in particular.
Options
These programs follow the usual GNU command line syntax, with long
options starting with two dashes ('-'). A summary of options is
included below.
-h --help | Show summary of options.
-v --version | Show version of program.
-d --debug | Show debug messages.
-s --show | Do not hide window after start.
-i --icon | Use a PNG image as an icon.
-l --large_icons | allow large icons (> 24x24).
-st --sticky | visible on all workspaces.
-x --borderless | Remove windows decorations border, title, frame... from parent.
-m --menu | Add entry "menu text:command" to popdown menu.
-t --title | Show title change for seconds. Probably most usefull for xmms.
-g --geometry | initial position. see man X.
Installation (command in a terminal)
- in Ubuntu:
sudo apt-get install alltray
- in Fedora:
sudo dnf install alltray
Cheers

Detecting the presence/absence of a numeric keypad?

Is it possible to determine whether there is a numeric keypad connected to the system? Desktop keyboards typically have numpads, while laptops typically don't (though they put numpad keys in the normal keyboard, activated with Num Lock). Does the operating system know whether the numpad keys are physically separate? And if so, is that information exposed to programs somehow?
It would be useful to know this to determine appropriate default key-bindings. If it's not available then I'll either have to pick a conservative default (not using the numpad), which means a slightly irritating extra configuration step to get nicer behaviour for people with separate numpads, or I'll have to pick a non-conservative default and irritate the people without numpads...
I don't believe you can query for keyboard capabilities but iirc there is a "numpad" key. ;)
You should be able to query if Num is on or off, but it being off won't be a foolproof way to know that there is no numeric keypad.
What you could probably do is detect keys being pressed on a numpad and subliminaly trick the user into doing so, which would identify said characteristic.
install these packages
sudo apt-get install -y numlockx xdotool x11-utils
then use a script like this
#!/bin/bash
cd
numlockx off &
rm -f s1.sh s2.sh out
echo -e "#\041/bin/bash
sleep 2
xdotool key KP_5 | xev > out
exit 0" >> s1.sh
chmod +x s1.sh
echo -e "#\041/bin/bash
sleep 9
killall -9 xev
sleep 5
xdotool key BackSpace
exit 0" >> s2.sh
chmod +x s2.sh
bash s1.sh &
bash s2.sh
rm -f s1.sh s2.sh
if [[ "$(cat out | grep "keycode 84" | grep "KP_Begin" )" != "" ]]; then
echo "Separated Numpad Detected!"
fi
rm out
exit 0
because KP_Begin is the keycode for the numpad key KP_5 when numlock isn't active, in a real keyboard with a real keypad.
Tested on 3 PCs, one with a separated keypad e 2 without it.

Resources