Ich habe ein einfaches Programm geschrieben, das die Zeichen vom externen Gerät (Barcode-Scanner) vom seriellen Port (/ dev/ttyS1) liest und es dem gerade aktiven Fenster zuführt (mit XSendEvent) .Zeichenfolge (Zeichen) an aktives Fenster senden
Programm funktioniert auf schnelleren Computern gut, aber auf langsamen passiert die Situation (sehr oft), dass Zeichen nicht in der gleichen Reihenfolge empfangen werden, in der sie gesendet wurden. Zum Beispiel sendet scanner 1234567 an die serielle Schnittstelle, mein Programm sendet Char-Ereignisse 1234567, aber das aktive Programm (xterm zum Beispiel) empfängt 3127456. Ich versuchte, XSync an verschiedenen Orten und Hinzufügen usleep Anrufe, aber es hat nicht geholfen.
Hat jemand eine Idee, wie man die "Reihenfolge" von Zeichen erzwingt?
Oder gibt es eine andere Möglichkeit, um eine Zeichenfolge an das aktive Fenster zu senden (ich habe nicht einmal etwas dagegen, ein externes Programm zu verwenden, wenn nötig)?
Hier ist der Code, vielleicht bin ich nur etwas falsch zu machen:
#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;
}
//-----------------------------------------------------------------------------
Ich kann das ursprüngliche Problem jetzt nicht reproduzieren (was seltsam ist), daher kann ich nicht sicher sein, dass diese Änderung es behebt. Aber, danke, ich werde es versuchen sobald das Problem wieder auftritt. –
Im Allgemeinen öffnet XOpenDisplay (...) einen neuen Socket. Es hängt vom Status Ihres X-Servers ab, wie er Anforderungen behandelt, die über verschiedene Sockets eingehen, so dass das Problem kommen und gehen kann. Aber definitiv ist es ein "Fehler" im Programm, dass Sie XOpenDisplay (...) viele Male aufrufen; normalerweise rufst du es nur einmal an. –