Històries amb la Wacom

De Wikijoan
Dreceres ràpides: navegació, cerca

Contingut

Introducció

Allò bàsic és utilitzar la Wacom com a controlador (per ex, com faig amb el Wacom Theremin), i poder generar sons sintètics amb la wacom: és a dir, quan guixo amb la wacom generar un so sintètic similar a un guixot. A partir d'aquí, utilitzar Gimp per a dibuixar i explicar una història, i que hi hagi efectes visuals. D'entrada se m'ocorren dues aplicacions divertides que es tradueixen a espectacles/performances per a escoles o grups:

Amb aquestes dues idees es poden desenvolupar espectacles atractius, sorprenents i originals, ben adreçat a escoles i instituts, escoles de música, i també a públic adult. També lliga amb fer monòlegs,...

Per produir el so he de mirar quina és la manera més fàcil i correcta de fer síntesi:

GIMP i 2 monitors

Programació Wacom + GIMP

En un altre lloc s'ha comentat sobre el codi xopen.c i com puc detectar de forma fàcil les comandes que provenen de la wacom. Això servei, entre d'altres coses, per fer la Wacom Theremin.

El problema que es planteja en aquest cas, treballar amb la wacom i GIMP, i programar al mateix temps, és que el codi que tinc de xopen.c no envia per pantalla flux de dades quan estic dibuixant amb el GIMP. Això és bàsic, doncs recordem el que es vol:

Ara bé, m'estic trobant que quan dibuixo amb el GIMP, xopen.c no vomita missatges per pantalla. Així doncs, aquí discutiré aquest fet.

prova_mouse.c

Primer de tot, prova_mouse.c funciona perfectament.

$gcc -o prova_mouse prova_mouse.c

prova_mouse.c

#include <stdio.h>
#include <stdlib.h>
main(){
        FILE *fmouse;
        char b[3];
        fmouse = fopen("/dev/input/mice","r");
        int xd=0,yd=0; //x/y movement delta
        int xo=0,yo=0; //x/y overflow (out of range -255 to +255)
        int lb=0,mb=0,rb=0,hs=0,vs=0; //left/middle/right mousebutton
        int run=0;
        while(!run){
                fread(b,sizeof(char),3,fmouse);
                lb=(b[0]&1)>0;
                rb=(b[0]&2)>0;
                mb=(b[0]&4)>0;
                hs=(b[0]&16)>0;
                vs=(b[0]&32)>0;
                xo=(b[0]&64)>0;
                yo=(b[0]&128)>0;
                xd=b[1];
                yd=b[2];
                printf("hs=%d,vs=%d,lb=%d rm=%d mb=%d xo=%d yo=%d xd=%d yd=%d\n",hs,vs,lb,rb,mb,xo,yo,xd,yd);
        }
        fclose(fmouse);
}

que funciona perfectament vol dir que mentre estic dibuixant amb el GIMP, per la consola on corre prova_mouse.c està vomitant els missatges.

xopen_mouse.c

Modifico xopen.c per tal de detectar els events del mouse (i no de la wacom). Tinc dues versions, xopen_mouse.c i xopen_mouse_v2.c. La primera només detecta el moviment del ratolí, i no els botons. I la segona versió, més general, detecta la pressió i el release dels botons.

$ xinput list
...
		Resolution is 1
	Axis 1 :
		Min_value is -1
		Max_value is -1
		Resolution is 1
"Logitech USB Optical Mouse"	id=4	[XExtensionPointer]
	Num_buttons is 32

El valor que s'ha de ficar en el programa serà:

#define MOUSENAME "Logitech USB Optical Mouse"

xopen_mouse.c:

$ gcc -o xopen_mouse xopen_mouse.c -lX11 -lXi -lXext
/* Trivial little XINPUT program written to test "raw" access to
 * XINPUT devices, without gtk wrappers or anything else.
 *  by Philip Brown
 * Written primarily to test my wacom tablet driver.
 *  http://www.bolthole.com/solaris/drivers/wacom.html
 *
 *
 * Note that it expects hardcoded special XINPUT dev names,
 * "wacomdev1" and "wacomdev2".
 *
 * It will then open those devices, and print out movement info when
 * you use those devices.
 *
 * compile with 
 *    cc -o xopen xopen.c -lX11 -lXi -lXext
 */

#define MOUSENAME "Logitech USB Optical Mouse"

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/extensions/XInput.h>
#include <stdio.h>

int
main (int argc, char **argv)
{
	Display *display;
	int screen, ndev, i;
	XDeviceInfo *devinfo;
	XID mouseID = 0;
	XDevice *mousedev;
	XEventClass EClist[10];
	int meventtype, numtypes=0;
	XEventClass meventclass;
	XEvent event_return;

	if ((display = XOpenDisplay (NULL)) == NULL)
	{
		  fprintf (stderr, "failed to connect to X server (%s)\n",
			   XDisplayName (NULL));
		  return 1;
	}
	screen = DefaultScreen (display);

	if ((devinfo = XListInputDevices (display, &ndev)) == NULL)
	{
		  fprintf (stderr, "Failed to get list of devices\n");
		  return 1;
	}
	printf ("Number of devices is %d\n", ndev);
	for (i = 0; i < ndev; i++)
	{
		  printf ("%d. %s(%d)\n", i, devinfo[i].name, devinfo[i].id);

		  if (strcmp (devinfo[i].name, MOUSENAME) == 0)
		  {
			    mouseID = devinfo[i].id;
		  }
	}

	XFreeDeviceList (devinfo);

	if (mouseID == 0)
	{
		  puts ("no mouse dev");
		  exit (0);
	}

	printf ("mouseid = %d\n", mouseID);
	mousedev = XOpenDevice (display, mouseID);
	printf("mousedev=%x\n",mousedev);
	numtypes+=1;

	/* bizzaro macro, to SET arg 2 and 3. Grrr. */
	DeviceMotionNotify (mousedev, meventtype, EClist[0]);

	printf ("DEBUG: motioneventtype is supposedly %d\n", meventtype);

	XSelectExtensionEvent (display, RootWindow (display, screen), EClist, numtypes);

	puts ("starting loop");

	while (1)
	{
		  XDeviceMotionEvent *meventptr;
		  XNextEvent (display, &event_return);
		  printf ("Got XEvent of type %d (mevent=%d)\n",
			  event_return.type, meventtype);
		  if (event_return.type == meventtype)
		  {
			    meventptr = (XDeviceMotionEvent *) & event_return;
			    printf ("data is %d,%d,%d (devid %d)\n",
				    meventptr->axis_data[0],
				    meventptr->axis_data[1],
				    meventptr->axis_data[2],
				    meventptr->deviceid);
		  }
	}

	XCloseDevice (display, mousedev);

}

xopen_mouse_v2.c

$ gcc -o xopen_mouse xopen_mouse_v2.c -lX11 -lXi -lXext
/* Trivial little XINPUT program written to test "raw" access to
 * XINPUT devices, without gtk wrappers or anything else.
 *  by Philip Brown
 * Written primarily to test my wacom tablet driver.
 *  http://www.bolthole.com/solaris/drivers/wacom.html
 *
 *
 * Note that it expects hardcoded special XINPUT dev names,
 * "wacomdev1" and "wacomdev2".
 *
 * It will then open those devices, and print out movement info when
 * you use those devices.
 *
 * compile with 
 *    cc -o xopen xopen.c -lX11 -lXi -lXext
 */

//també (button press i button release): http://www-evasion.imag.fr/~Francois.Faure/doc/inventorToolmaker/sgi_html/ch11.html

#define MOUSENAME "Logitech USB Optical Mouse"

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/extensions/XInput.h>
#include <stdio.h>

int
main (int argc, char **argv)
{
	Display *display;
	int screen, ndev, i;
	XDeviceInfo *devinfo;
	XID mouseID = 0;
	XDevice *mousedev;
	XEventClass EClist[10];
	int motionEventType, buttonPressEventType, buttonReleaseEventType, numtypes=0;
	XEventClass meventclass;
	XEvent event_return;

	if ((display = XOpenDisplay (NULL)) == NULL)
	{
		  fprintf (stderr, "failed to connect to X server (%s)\n",
			   XDisplayName (NULL));
		  return 1;
	}
	screen = DefaultScreen (display);

	if ((devinfo = XListInputDevices (display, &ndev)) == NULL)
	{
		  fprintf (stderr, "Failed to get list of devices\n");
		  return 1;
	}
	printf ("Number of devices is %d\n", ndev);
	for (i = 0; i < ndev; i++)
	{
		  printf ("%d. %s(%d)\n", i, devinfo[i].name, devinfo[i].id);

		  if (strcmp (devinfo[i].name, MOUSENAME) == 0)
		  {
			    mouseID = devinfo[i].id;
		  }
	}

	XFreeDeviceList (devinfo);

	if (mouseID == 0)
	{
		  puts ("no mouse dev");
		  exit (0);
	}

	printf ("mouseid = %d\n", mouseID);
	mousedev = XOpenDevice (display, mouseID);
	printf("mousedev=%x\n",mousedev);
	
	/* bizzaro macro, to SET arg 2 and 3. Grrr. */
	DeviceMotionNotify (mousedev, motionEventType, EClist[numtypes]);
	numtypes+=1;

	DeviceButtonPress(mousedev, buttonPressEventType, EClist[numtypes]);
	numtypes+=1;

	DeviceButtonRelease(mousedev, buttonReleaseEventType, EClist[numtypes]);
	numtypes+=1;

	printf ("DEBUG: motioneventtype is supposedly %d\n", motionEventType);
	printf ("DEBUG: buttonPressEventType is supposedly %d\n", buttonPressEventType);
	printf ("DEBUG: buttonReleaseEventType is supposedly %d\n", buttonReleaseEventType);

	XSelectExtensionEvent (display, RootWindow (display, screen), EClist, numtypes);

	puts ("starting loop");

	while (1)
	{
		  XDeviceMotionEvent *meventptr;
		  XNextEvent (display, &event_return);

		  if (event_return.type == motionEventType)
		  {
			  printf ("Got XEvent of type %d (motionevent=%d)\n", event_return.type, motionEventType);
			    meventptr = (XDeviceMotionEvent *) & event_return;
			    printf ("data is %d,%d,%d (devid %d)\n",
				    meventptr->axis_data[0],
				    meventptr->axis_data[1],
				    meventptr->axis_data[2],
				    meventptr->deviceid);
		  }

		  if (event_return.type == buttonPressEventType)
		  {
			  printf ("Got XEvent of type %d (buttonpressevent=%d)\n", event_return.type, buttonPressEventType);
			    meventptr = (XDeviceButtonEvent *) & event_return;
			    printf ("data is %d,%d,%d (devid %d)\n",
				    meventptr->axis_data[0],
				    meventptr->axis_data[1],
				    meventptr->axis_data[2],
				    meventptr->deviceid);
		  }

		  if (event_return.type == buttonReleaseEventType)
		  {
			  printf ("Got XEvent of type %d (buttonpressevent=%d)\n", event_return.type, buttonReleaseEventType);
			    meventptr = (XDeviceButtonEvent *) & event_return;
			    printf ("data is %d,%d,%d (devid %d)\n",
				    meventptr->axis_data[0],
				    meventptr->axis_data[1],
				    meventptr->axis_data[2],
				    meventptr->deviceid);
		  }
	}

	XCloseDevice (display, mousedev);

}

Hi ha una diferència important entre les dues versions: la primera no treballa bé amb GIMP (quan dibuixo en el GIMP no vomita res, tot i que quan em moc sobre la finestra principal del GIMP sí que vomita); i en canvi la versió _v2 té el comportament esperat (cal arrencar GIMP com a sudo?). És a dir, he de detectar els events buttonPressEventType i buttonReleaseEventType. I això és precisament el que també he de fer amb la wacom per tal de què treballi bé amb GIMP, detectar aquests dos events: buttonPressEventType i buttonReleaseEventType-

xopen_wacom.c (solució)

Només em centro en el llapis principal, no amb el Erase. Són molts pocs canvis respecte l'anterior. La clau està en què per treballar bé amb el GIMP he de notificar el pressbuton i el releasebutton (no sé per què).

$ gcc -o xopen_wacom xopen_wacom.c -lX11 -lXi -lXext
/* Trivial little XINPUT program written to test "raw" access to
 * XINPUT devices, without gtk wrappers or anything else.
 *  by Philip Brown
 * Written primarily to test my wacom tablet driver.
 *  http://www.bolthole.com/solaris/drivers/wacom.html
 *
 *
 * Note that it expects hardcoded special XINPUT dev names,
 * "wacomdev1" and "wacomdev2".
 *
 * It will then open those devices, and print out movement info when
 * you use those devices.
 *
 * compile with 
 *    cc -o xopen xopen.c -lX11 -lXi -lXext
 */

//també (button press i button release): http://www-evasion.imag.fr/~Francois.Faure/doc/inventorToolmaker/sgi_html/ch11.html

#define PENNAME "Wacom Intuos2 12x12"

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/extensions/XInput.h>
#include <stdio.h>

int
main (int argc, char **argv)
{
	Display *display;
	int screen, ndev, i;
	XDeviceInfo *devinfo;
	XID tabletID = 0;
	XDevice *tabletdev;
	XEventClass EClist[10];
	int motionEventType, buttonPressEventType, buttonReleaseEventType, numtypes=0;
	XEventClass meventclass;
	XEvent event_return;

	if ((display = XOpenDisplay (NULL)) == NULL)
	{
		  fprintf (stderr, "failed to connect to X server (%s)\n",
			   XDisplayName (NULL));
		  return 1;
	}
	screen = DefaultScreen (display);

	if ((devinfo = XListInputDevices (display, &ndev)) == NULL)
	{
		  fprintf (stderr, "Failed to get list of devices\n");
		  return 1;
	}
	printf ("Number of devices is %d\n", ndev);
	for (i = 0; i < ndev; i++)
	{
		  printf ("%d. %s(%d)\n", i, devinfo[i].name, devinfo[i].id);

		  if (strcmp (devinfo[i].name, PENNAME) == 0)
		  {
			    tabletID = devinfo[i].id;
		  }
	}

	XFreeDeviceList (devinfo);

	if (tabletID == 0)
	{
		  puts ("no tablet dev");
		  exit (0);
	}

	printf ("tabletid = %d\n", tabletID);
	tabletdev = XOpenDevice (display, tabletID);
	printf("tabletdev=%x\n",tabletdev);
	
	/* bizzaro macro, to SET arg 2 and 3. Grrr. */
	DeviceMotionNotify (tabletdev, motionEventType, EClist[numtypes]);
	numtypes+=1;

	DeviceButtonPress(tabletdev, buttonPressEventType, EClist[numtypes]);
	numtypes+=1;

	DeviceButtonRelease(tabletdev, buttonReleaseEventType, EClist[numtypes]);
	numtypes+=1;

	printf ("DEBUG: motioneventtype is supposedly %d\n", motionEventType);
	printf ("DEBUG: buttonPressEventType is supposedly %d\n", buttonPressEventType);
	printf ("DEBUG: buttonReleaseEventType is supposedly %d\n", buttonReleaseEventType);

	XSelectExtensionEvent (display, RootWindow (display, screen), EClist, numtypes);

	puts ("starting loop");

	while (1)
	{
		  XDeviceMotionEvent *meventptr;
		  XNextEvent (display, &event_return);

		  if (event_return.type == motionEventType)
		  {
			  printf ("Got XEvent of type %d (motionevent=%d)\n", event_return.type, motionEventType);
			    meventptr = (XDeviceMotionEvent *) & event_return;
			    printf ("data is %d,%d,%d (devid %d)\n",
				    meventptr->axis_data[0],
				    meventptr->axis_data[1],
				    meventptr->axis_data[2],
				    meventptr->deviceid);
		  }

		  if (event_return.type == buttonPressEventType)
		  {
			  printf ("Got XEvent of type %d (buttonpressevent=%d)\n", event_return.type, buttonPressEventType);
			    meventptr = (XDeviceButtonEvent *) & event_return;
			    printf ("data is %d,%d,%d (devid %d)\n",
				    meventptr->axis_data[0],
				    meventptr->axis_data[1],
				    meventptr->axis_data[2],
				    meventptr->deviceid);
		  }

		  if (event_return.type == buttonReleaseEventType)
		  {
			  printf ("Got XEvent of type %d (buttonpressevent=%d)\n", event_return.type, buttonReleaseEventType);
			    meventptr = (XDeviceButtonEvent *) & event_return;
			    printf ("data is %d,%d,%d (devid %d)\n",
				    meventptr->axis_data[0],
				    meventptr->axis_data[1],
				    meventptr->axis_data[2],
				    meventptr->deviceid);
		  }
	}

	XCloseDevice (display, tabletdev);

}

nota important: arrencar GIMP com a sudo. xopen_wacom no cal. De fet no és tan estrany que funcioni amb buttonpress i buttonrelease, doncs aquests events són importants per a notificar al GIMP que es comenci a dibuixar.

Fer moure el ratolí tot sol

Programàticament podem fer moure el ratolí, disparar tecles del teclat,...

$ sudo apt-get install xautomation
$ xte 'mousermove 1 1'

A linux també hi ha xsendkeys (sudo apt-get install lineakd), però no cal si ja tenim xte.

Projectes


creat per Joan Quintana Compte, gener 2012

Eines de l'usuari
Espais de noms
Variants
Accions
Navegació
Institut Jaume Balmes
Màquines recreatives
CNC
Informàtica musical
joanillo.org Planet
Eines