[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Xorg mit Event-Interface oder sich besser vorher erschiessen



Hallo Allerseits,

das Ganze begann damit, das ich meinem MS-Wireless-Multimedia-Keyboard
aus IRQ-Mangel den PS2-Anschluss wegnehmen musste und es via USB
anschloss. Prompt gingen sämtliche Multimedia- und Zusatzfunktionstasten
nicht mehr:

 keyboard.c: can't emulate rawmode for keycode 252

(Statt 252 kann man beliebige Zahlen oberhalb von 250 einsetzen)

Nach langem herumprobieren (setkeycodes geht NICHT mit USB-Keyboards
weil es auf PS2 aufbaut) bekam ich den Tipp, komplett auf das
Event-Interface umzustellen.

Gesagt, getan. Im Kernel hatte ich CONFIG_INPUT_EVDEV=y schon immer drin,
also statt meines Xfree86 V.4  Xorg für Debian Testing installiert.

Gleichzeitig habe ich aus meinem Kernel atkbd und psmouse
rausgeworfen um sicher zu sein, das auch alles über Event-Interface
und nicht über PS2-Emulation abgewickelt wird. (Vorsicht, geht das
schief sitzt man vor einem Debian ohne Tastatur und Maus, funktionsfähigen
Reserve-Kernel bereithalten!)

In den Grundzügen lief das, ABER:

Auf der Tastatur geht der Less-Key "<>|" gar nicht mehr :-(. Googlen
erbrachte, das dies ein Debian-Bug ist, der leider auch in den letzten
Xorg-Paketen immer noch drin ist.

http://lists.debian.org/debian-x/2005/08/msg00259.html 

Um das zu fixen muss man sich aber die Sources besorgen. Die
debian-Sources zu xorg 6.8.2 habe ich allerdings nicht mit evdev kompliert
bekommen. Also neuer Versuch aus den Quellen von X.org:

Auch da ist erst einmal kein evdev-Support drin. Ich habe diese
Patches eingefügt von

http://dev.gentoo.org/~spyderous/xorg-x11/patchsets/6.8.2/patch/

Und davon braucht man zwingend(!) für evdev:

9000_all_6.7.99.2-lnx-evdev-core-v3.patch
9001_all_4.3.0-lnx-evdev-keyboard-v2.patch
9002_all_6.7.0-lnx-evdev-mouse.patch
9003_all_6.8.2-lnx-evdev-keyboard-dont-grab.patch

Dann muss man 2 Zeilen in
xc/programs/Xserver/hw/xfree86/os-support/linux/lnx_kbd.c
ändern:

um Zeile 580 herum steht da:
switch (ev->code) {
                   case EV_KEY_102ND:  ###diese Anweisung muss weg!

dafür muss ein Stck weiter unten eingefügt werden:
                   case EV_KEY_KPCOMMA:
                   case EV_KEY_COMPOSE:
                   code = KEY_UNKNOWN;
                   break;             
                   case EV_KEY_102ND:    ###diese Zeilen einfgen
                   code = KEY_Less;      ###                     
                   break;                ###
                                                 

Wenn man schon einmal dabei ist, sollte man auch schnell den gcc-4 in
eine Umlaufbahn treten, der mit irgendeinem Update auf testing
plötzlich reingekommen ist (/usr/bin/gcc ist nun ein Softlink auf
gcc-4 statt gcc-3) weil mit ihm weder Kernel noch Xorg durch den
Compiler gehen. Oder man besorgt sich einen gcc-4-patch für Xorg vom
BLFS (X11R6.8.2-src-gcc4-1.patch).

Nun kann man Xorg compilen, installieren und die /etc/X11/Xorg.conf
an evdev anpassen:

Section "InputDevice"
    Identifier  "Keyboard1"
    Driver      "kbd"
    Option      "Protocol"      "evdev"
#siehe cat /proc/bus/input/devices    
    Option      "Dev Phys"      "usb-*/input0"
    Option      "AutoRepeat"    "500 30"
    Option      "XkbRules"      "xorg"
    Option      "XkbModel"      "pc105(microsoftofficepro)"
    Option      "XkbLayout"     "de"
    Option      "XkbVariant"    "nodeadkeys"
    Option      "CoreKeyboard"
EndSection
[...]
Section "InputDevice"
    Identifier  "Mouse1"
    Driver      "mouse"
    Option      "Protocol"      "evdev"
#siehe cat /cat/proc/bus/input/devices    
    Option      "Dev Phys"      "usb-*/input1"
    Option      "SendCoreEvents"     "true"
    Option      "ZAxisMapping"       "4 5"
    Option      "CorePointer"
EndSection
                            
Nun hat man ein Xorg mit USB-Keyboard und Mouse über das
Event-Device. Prima - was bringt das? GAR NICHTS :-(. Der
PS2-Anschluss ist frei, aber die Sondertasten der Tastatur sind
genauso tot wie ehedem :-(.

Also sucht man Programme zusammen, die den Multimedia-Tasten einen
Nutzen geben können: lineakd, xbindkeys, xke, xsendkey, keytouch,
getscancodes usw. usw. Leider funktionieren die auch nicht!

Am weitesten kommt noch evtest aus dem lineakd-Paket. Das gibt
wenigstens schon einmal die Tasten und Codes aus:

[...]
Testing ... (interrupt to exit)
Event: time 1126973961.882093, type 1 (Key), code 28 (Enter), value 0
Event: time 1126973961.882095, -------------- Config Sync
[...]

Den Tasten einen sinnvollen Nutzen geben kann man damit aber auch nicht.

Nach langer Suche bin ich dann mehr durch Zufall hier gelandet:
http://www.frogmouth.net/hid-doco/c537.html. Dort gibt es eine
Doku des HID-Interfaces und auch kleine Beispielprogramme in C. Das
"Example 10 - Read Example" hat mir dann selbst als C-Laie gestattet,
durch minimale Code-Änderungen ein Programm zu erzeugen, das für jede
gedrückte Multimedia-Taste einfach ein Shellscript startet. Druck auf
die Taste mit Code 253 startet "./253.sh". Darin kann man dann so
ziemlich machen, was man will, solange man alles mit "&" am Ende
startet (andernfalls würde das Hauptprogramm hängen bis das Script
beendet ist).

Das Kernprogramm keyboard-read starte ich in der .xsession:
[...]
if [ "$(pgrep keyboard-read)" = "" ]; then
   pushd ~/keyboard
   ./keyboard-read /dev/input/event1 >/dev/null 2>&1 &
   popd                                               
fi
[...]

Unter den Namen eines jeden Tastencodes(.sh) startet nun jeweils ein
Script in das man reinpackt, was man machen will. Wichtig in allen
Scripts ist nur, das sie jeweils mit "&" abgeschlossen werden, damit
sie im Hintergrund weiterlaufen. So sieht bei mir ~/keyboard/ aus:

113.sh ->/home/frank/bin/Xmute*
114.sh ->/home/frank/bin/Xvolume*
115.sh ->/home/frank/bin/Xvolume*
140.sh ->/home/frank/bin/Xcalc*
155.sh ->/home/frank/bin/Xmutt*
164.sh ->/home/frank/bin/Xplay*
171.sh ->/home/frank/bin/Xmedien*
172.sh ->/home/frank/bin/Xbrowser*
247.sh ->/home/frank/bin/Xabmelden*
251.sh ->/home/frank/bin/Xmc*
252.sh ->/home/frank/bin/XShell*
253.sh ->/home/frank/bin/XRootShell*
254.sh ->/home/frank/bin/Xnews*

Bei kleineren Programmen die sich sofort wieder beenden kann man auf
das "&" verzichten. So mache ich das z.B. in Xvolume, was zweimal
aufgerufen wird: mit 115.sh erhöht es die Lautstärke, mit 114.sh
vermindert es sie:

#!/bin/bash
#Xvolume
egal=$0
if [ "$egal" == "./115.sh" ]; then
  aumix -v+1
  elif [ "$egal" == "./114.sh" ]; then
  aumix -v-1                                             
fi

Bei Mutt ginge das z.B. nicht weil man dann die Tasten nicht mehr
abgefragt wrden bis er beendet wird. Darum so:

#!/bin/sh
#Xmutt
/usr/bin/rxvt -fg grey -bg black +sb -geometry 100x40-33+35 -fn
-misc-fixed-medium-r-normal--15-140-75-75-c-90-iso8859-15 -e
/usr/bin/mutt $* &

Fazit: Meine Lösung mag primitiv sein, hat aber den grossen Vorteil
auf dem Event-Device zu funktionieren.

Sorry für den langen Sermon, vieleicht hilft es ja Irgendjemand bevor
er wie ich etliche Tage für nichts und wieder nichts verbrät. Ich
hänge noch die keyboard-read.c an.

Achja: Paralell habe ich auch mit dem Standalone-Evdev-Driver
herumprobiert (https://bugs.freedesktop.org/attachment.cgi?id=1745).

Der benutzt eine andere Syntax in /etc/X11/xorg.conf:
[...]
Section "InputDevice"
    Identifier "Keyboard1"
    Driver     "evdev"
# (cat /proc/bus/input/devices)
    Option      "Device" "/dev/input/event0"
    Option     "XkbRules"      "xorg"
    Option     "XkbModel"      "pc105"
    Option     "XkbLayout"     "de"
    Option     "XkbVariant"    "nodeadkeys"
    Option     "CoreKeyboard"
EndSection
[...]
Section "InputDevice"
    Identifier  "Mouse1"
    Driver      "evdev"
    Option      "Device" "/dev/input/event1" # (cat
#  (cat/proc/bus/input/devices)
    Option      "SendCoreEvents"     "true"
    Option      "ZAxisMapping"       "4 5"
    Option      "CorePointer"
Endsection

Das eigentliche Problem ist aber: Wenn man den für das Keyboard
benutzt ignoriert er alle Schlüsselwörter für die Landesanpassung
(XkbModel, XkbLayout, XkbVariant) und man hat immer ein US-Layout
ohne Sondertasten. Für mich vollkommen unbrauchbar.

Grüße
Frank
-- 
Freie Musik für freie Bürger!
Eine Kampagne des Chaos Computer Clubs (http://www.ccc.de)
/* basierend auf einem Code-Beispiel von                     *  
 * //www.frogmouth.net/hid-doco/c537.html                    *         
 *                                                           *
 * Komplett überarbeitet von Miroslaw Dobrzanski-Neumann     *
 *                                                           *
 * mies eingehackte Case-Schleife von Frank Blatzheim        */

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/input.h>

static char const *PROG = "edevread";

static inline void *ADVANCE (void *p, ptrdiff_t off)
{
	return (char*)p + off;
}

void usage_exit (int code, char const *msg)
{
	FILE *f = code == 0 ? stderr : stdout;
	if (NULL != msg)
	{
		fprintf (f, msg);
		fprintf (f, "\n");
	}

	fprintf (f, "Aufruf\n%s /dev/eventX\n", PROG);
	_exit (code);
}

void perror_exit (char const *msg)
{
	perror (msg);
	_exit (EXIT_FAILURE);
}

void select_function (char const *file)
{
	int fd;
	int ret;
	fd_set readset;
	struct input_event event;
	int                evread = 0;

	fd = open (file, O_RDONLY);
	if (-1 == fd)
		perror_exit ("open");

	while (1)
	{
		FD_ZERO (&readset);
		FD_SET  (fd, &readset);

		ret = select (fd + 1, &readset, NULL, NULL, NULL);
		if (-1 == ret)
		{
			/*
			 * EINTR - interrupted system call
			 * nicht die beste Lösung um auszusteigen
			 * in diesem Demo aber OK
			 */
			if (EINTR == errno)
				break;
			else
				perror_exit ("select");
		}
		if (! FD_ISSET (fd, &readset))
			continue;

		ret = read (fd, ADVANCE (&event, evread), sizeof (event) - evread);
		if (-1 == ret)
			perror_exit ("read");
		evread += ret;
		if (sizeof (event) != evread)
			continue;

/* wenn man diese Auskommentierung in der Zeile darunter entfernt, bekommt    *
 * man wieder eine Ausgabe der Tastencodes und Eventtypen. Gut zu Testzwecken!*/
		
/* printf ("EVENT = T:%u C:%u V:%u\n", event.type, event.code, event.value); */
		
			if ((event.value) == 1)
	    
			switch (event.code)
			{
				case 113:
				/* Ton aus */
				system("113.sh");
				break;
			
				case 114:
				/* - */
				system("114.sh");
				break;
			
				case 115:
				/* + */
				system("115.sh");
				break;
			
				case 131:
				/* F2 Undo */
				system("131.sh");
				break;
			
				case 138:
				/* F1 Help */
				system("138.sh");
				break;

				case 140:
				/* Rechner */
				system("140.sh");
				break;

				case 142:
				/* Standby */
				system("142.sh");
				break;

				case 155:
				/* Mail */
				system("155.sh");
				break;

				case 163:
				/* Next Song */
				system("163.sh");
				break;

				case 164:
				/* >/|| Play,Pause*/
				system("164.sh");
				break;

				case 165:
				/* << Previous Song */
				system("165.sh");
				break;

				case 166:
				/* [] Stop */
				system("166.sh");
				break;

				case 171:
				/* Medien */
				system("171.sh");
				break;

				case 172:
				/* Startseite */
				system("172.sh");
				break;

				case 240:
				/* F3 Wiederherstell */
				system("240.sh");
				break;

				case 241:
				/* F10 Rechtschreib */
				system("241.sh");
				break;

				case 242:
				/* F12 Drucken */
				system("242.sh");
				break;

				case 243:
				/* F5 Öffnen */
				system("243.sh");
				break;

				case 244:
				/* F6 Schließ */
				system("244.sh");
				break;

				case 245:
				/* F11 Speichern */
				system("245.sh");
				break;

				case 246:
				/* F4 Neu */
				system("246.sh");
				break;

				case 247:
				/* Abmelden */
				system("247.sh");
				break;

				case 248:
				/* F7 Antwort */
				system("248.sh");
				break;

				case 249:
				/* F8 Weiterleiten */
				system("249.sh");
				break;

				case 250:
				/* F9 Senden */
				system("250.sh");
				break;

				case 251:
				/* Messenger */
				system("251.sh");
				break;

				case 252:
				/* Eigene Dateien */
				system("252.sh");
				break;
			
				case 253:
				/* Eigene Bilder */
				system("253.sh");
				break;
			
				case 254:
				/* Eigene Musik */
				system("254.sh");
				break;

				default:
				break;
			}

		evread = 0;
	}

	close (fd);
}

int main (int argc, char *argv[])
{
	if (argc == 0)
		usage_exit (EXIT_FAILURE, "What a call convention?");

	PROG = argv[0];

	if (argc != 2)
		usage_exit (EXIT_FAILURE, NULL);

	select_function (argv[1]);

	return 0;
}


Reply to: