From ae1c9f9572df8b4834fe0b809c57673560121581 Mon Sep 17 00:00:00 2001 From: girst Date: Thu, 11 Feb 2016 18:32:11 +0100 Subject: [PATCH] prepare for unicode support --- README.md | 34 +++++++++++++++++++++++++++ main.c | 69 ++++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 90 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 0b7f83f..d34f438 100644 --- a/README.md +++ b/README.md @@ -6,3 +6,37 @@ This is also an entry for [Hackaday.io](https://hackaday.io)'s Pi Zero Contest. ## Hardware I am using a Raspberry Pi Zero, since it has USB-OTG support and a lot of GPIO to interface an OLED screen, a button matrix for input and maybe even an ESP8266 for WiFi. The OLED I am intending to use has an I²C interface and a screen diagonal of .96". + +## using the driver +To use this program, you have to enable the `libcomposite` driver on the Raspberry Pi and create a USB HID gadget. +You can use this bash script: +``` +#!/bin/bash +# this is a stripped down version of https://github.com/ckuethe/usbarmory/wiki/USB-Gadgets - I don't claim any rights + +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 +mkdir -p strings/0x409 +echo "fedcba9876543210" > strings/0x409/serialnumber +echo "girst" > strings/0x409/manufacturer +echo "Hardpass" > strings/0x409/product +N="usb0" +mkdir -p functions/hid.$N +echo 1 > functions/hid.usb0/protocol +echo 1 > functions/hid.usb0/subclass +echo 8 > functions/hid.usb0/report_length +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/hid.usb0/report_desc +C=1 +mkdir -p configs/c.$C/strings/0x409 +echo "Config $C: ECM network" > configs/c.$C/strings/0x409/configuration +echo 250 > configs/c.$C/MaxPower +ln -s functions/hid.$N configs/c.$C/ +ls /sys/class/udc > UDC + +``` diff --git a/main.c b/main.c index 681660b..00157ee 100644 --- a/main.c +++ b/main.c @@ -2,30 +2,39 @@ description: sends a sequence of keystrokes to the hid device. parameters: device file (e.g. /dev/hidg0) - keyboard layout (e.g. en_us; only a limited number are supported and they do not follow unix-naming conventions for convenience) - the string to send (as whitespace is important, the `echo` way of concatenating all parameters is not supported. if your string has white space in it and you are in an interactive session, quote your string. + keyboard layout (1=en_us, 2=de_at, 3=de_at-nodeadkeys) + unicode method: 1=gtk_holddown, 2=gtk_spaceend, 3=windows + the string to send (as whitespace is important, the `echo` way of concatenating all parameters is not supported. if your string has white space in it and you are in an interactive session, quote your string.) */ #include #include #include #include "scancodes.h" +//argv-indices +#define P_EXE 0 //executable name +#define P_DEV 1 //device file +#define P_LAY 2 //layout +#define P_UNI 3//unicode method +#define P_STR 4 //string to type +#define NUM_P P_STR+1 //number of parameters + void send_key (FILE* hid_dev, unsigned short key, unsigned short mod); int main (int argc, char** argv) { - if (argc != 4) { - fprintf (stderr, "Usage: %s \"\"\n", argv[0]); + if (argc != NUM_P) { + fprintf (stderr, "Usage: %s \"\"\n", argv[P_EXE]); return 1; } FILE* hid_dev = fopen ("/dev/hidg0", "w"); - for (int i = 0; i < strlen (argv[3]); i++) { + for (int i = 0; i < strlen (argv[P_STR]); i++) { - char tmp[UTF8_MAX_LENGTH] = {argv[3][i], argv[3][i+1], argv[3][i+2], '\0'}; + char tmp[UTF8_MAX_LENGTH] = {argv[P_STR][i], argv[P_STR][i+1], argv[P_STR][i+2], '\0'}; //TODO: replace by something less stupid - if (argv[3][i] < 128) { // not multi byte + if (argv[P_STR][i] < 128) { // not multi byte tmp[1] = '\0'; } else { // is multi byte - if (argv[3][i] < 0xe0) { + if (argv[P_STR][i] < 0xe0) { i++; //skip next thing tmp[2] = 0; } else { @@ -38,24 +47,58 @@ int main (int argc, char** argv) { fprintf (stderr, "Key Symbol not found.\n"); return 1; } - switch (atoi (argv[2])) { + struct layout* l; + int ignore_deadkey = 0; + switch (atoi (argv[P_LAY])) { case 0: fprintf (stderr, "This keyboard layout is reserved.\n"); return 1; case 1: //en_us - send_key(hid_dev, s->en_us.key, s->en_us.mod); + l = &(s->en_us); break; case 2: //de_at - send_key(hid_dev, s->de_at.key, s->de_at.mod);//, s->de_at.is_dead); + l = &(s->de_at); break; case 3: //de_at-nodeadkeys - send_key(hid_dev, s->de_at.key, s->de_at.mod); + l = &(s->de_at); + ignore_deadkey = 1; break; default: fprintf (stderr, "Unrecognised keyboard layout.\n"); return 1; } - send_key(hid_dev, '\0', '\0'); + if (l->key == 0x00) { + //key does not exist in this layout + fprintf (stderr, "Key not in this layout!\n"); + /*TODO: send unicode sequence + there are different methods to be used for gtk and + winblows. ctrl-shift-u-HEX vs. ctrl-shift-u,HEX,SPACE + vs. alt+NUMPAD vs. alt+'+'+HEX + */ + switch (atoi (argv[P_UNI])) { + case 0: //skip unicode character entry + break; + case 1: //gtk: hold ctrl and shift while entering + //TODO + break; + case 2: //gtk: use space as end marker for unicode + //TODO + case 3: //windows: alt+numpad (decimal) + //TODO + break; + default: + fprintf (stderr, "Unicode Method unknown!\n"); + return 1; + } + } else { + send_key(hid_dev, l->key, l->mod); + send_key(hid_dev, '\0', '\0'); //release all keys + if (l->is_dead && !ignore_deadkey) { + //dead keys need to be pressed twice to show up + send_key(hid_dev, l->key, l->mod); + send_key(hid_dev, '\0', '\0'); //release all keys + } + } } fclose (hid_dev); -- 2.39.3