J'ai écrit un programme simple qui lit les caractères d'un périphérique externe (scanner de code à barres) depuis le port série (/ dev/ttyS1) et l'alimente dans la fenêtre active (avec XSendEvent) . Le programme fonctionne correctement sur les ordinateurs plus rapides, mais sur les ordinateurs lents, il arrive (très souvent) que les caractères ne soient pas reçus dans le même ordre que celui où ils ont été envoyés. Par exemple, scanner envoie 1234567 au port série, mon programme envoie des événements char 1234567, mais le programme actif (xterm par exemple) reçoit 3127456. J'ai essayé d'appeler XSync à divers endroits et en ajoutant usleep appels, mais cela n'a pas aidé.Envoi d'une chaîne (de caractères) à la fenêtre active
Est-ce que quelqu'un a une idée sur la façon de forcer l'ordre des caractères?
Ou existe-t-il un autre moyen d'envoyer une chaîne à la fenêtre active (cela ne me dérange même pas d'utiliser un programme externe si nécessaire)?
est ici le code, peut-être que je vais juste faire quelque chose de mal:
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h> // serial port stuff
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#include <X11/Xlib.h>
/*
BarCode KeyboardFeeder: BCKF
Copyright (c) Milan Babuskov
Licence: GNU General Public Licence
Compile with: g++ bckf.cpp -lX11 -L /usr/X11R6/lib/ -o bckf
Keycodes: /usr/X11R6/include/X11/keysymdef.h
*/
//-----------------------------------------------------------------------------
void SendEvent(XKeyEvent *event, bool press)
{
if (press)
XSendEvent(event->display, event->window, True, KeyPressMask, (XEvent *)event);
else
XSendEvent(event->display, event->window, True, KeyReleaseMask, (XEvent *)event);
XSync(event->display, False);
}
//-----------------------------------------------------------------------------
bool sendChar(int c)
{
if (c >= 0x08 && c <= 0x1b) // send CR twice
{
sendChar(0xff0d);
c = 0xff0d;
}
printf("Sending char : 0x%02x\n", c);
char disp[] = ":0";
char *dp = getenv("DISPLAY");
if (!dp)
dp = disp;
else
printf("Using env.variable $DISPLAY = %s.\n", dp);
Display *dpy = XOpenDisplay(dp);
if (dpy == NULL)
{
printf("ERROR! Couldn't connect to display %s.\n", dp);
return false;
}
else
{
Window cur_focus; // focused window
int revert_to; // focus state
XGetInputFocus(dpy, &cur_focus, &revert_to); // get window with focus
if (cur_focus == None)
{
printf("WARNING! No window is focused\n");
return true;
}
else
{
XKeyEvent event;
event.display = dpy;
event.window = cur_focus;
event.root = RootWindow(event.display, DefaultScreen(event.display));
event.subwindow = None;
event.time = CurrentTime;
event.x = 1;
event.y = 1;
event.x_root = 1;
event.y_root = 1;
event.same_screen = True;
event.type = KeyPress;
event.state = 0;
event.keycode = XKeysymToKeycode(dpy, c);
SendEvent(&event, true);
event.type = KeyRelease;
SendEvent(&event, false);
}
XCloseDisplay(dpy);
}
usleep(20);
return true;
}
//-----------------------------------------------------------------------------
// Forward declaration
int InitComPort(const char *port);
//-----------------------------------------------------------------------------
int main(int argc, char **argv)
{
if (argc != 2)
{
printf("Usage: bckf serial_port\n");
return 1;
}
int port = InitComPort(argv[1]);
if (port == -1)
return 1;
while (true)
{
char buf[30];
ssize_t res = read(port, buf, 30);
if (res > 0)
{
for (ssize_t i=0; i<res; ++i)
{
int c = buf[i];
printf("Received char: 0x%02x\n", c);
if (c >= '0' && c <= '9' || c >= 0x08 && c <= 0x1b)
if (!sendChar(c)) // called from console?
break;
}
}
}
return 0;
}
//-----------------------------------------------------------------------------
int InitComPort(const char *port)
{
int c, res;
struct termios newtio;
struct termios oldtio;
// Open modem device for reading and writing and not as controlling tty
// because we don't want to get killed if linenoise sends CTRL-C.
int fdSerial = open(port, O_RDWR | O_NOCTTY);
if (fdSerial < 0)
{
printf(0, "Error opening port: %s\n%s", port, strerror(errno));
return -1;
}
tcgetattr(fdSerial,&oldtio); // save current port settings
memset(&newtio, 0, sizeof(newtio));
newtio.c_cflag = B9600 | CS8 | CLOCAL | CREAD; // CREAD : enable receiving characters
// CS8 : character size 8
// CLOCAL : Ignore modem control lines
newtio.c_iflag = IGNPAR; // IGNPAR : ignore bytes with parity errors
newtio.c_oflag = 0; // 0 : raw output (no echo, non-canonical)
//newtio.c_cc[VTIME] = timeout; // 10=1sec : inter-character timer (deciseconds)
newtio.c_cc[VMIN] = 1; // 50 : blocking read until 50 chars received
tcflush(fdSerial, TCIOFLUSH); // clear the line and...
tcsetattr(fdSerial,TCSANOW,&newtio); // ...activate new settings for the port
return fdSerial;
}
//-----------------------------------------------------------------------------
Je suis incapable de reproduire le problème d'origine maintenant (ce qui est étrange), donc je ne peux pas être sûr que ce changement le corrige. Mais, merci, je vais essayer dès que le problème se pose à nouveau. –
En général, XOpenDisplay (...) ouvre une nouvelle socket. Cela dépend de l'état de votre serveur X, de la façon dont il traite les demandes provenant de différentes sockets, de sorte que le problème peut aller et venir. Mais c'est définitivement une "erreur" dans le programme que vous appelez XOpenDisplay (...) plusieurs fois; Habituellement, vous l'appelez une seule fois. –