문제

Serial Port (/dev/ttys1)에서 외부 장치 (바코드 스캐너)의 문자를 읽는 간단한 프로그램을 작성하고 현재 활성 창 (Xsendevent를 사용하여)에 공급합니다.

프로그램은 더 빠른 컴퓨터에서 잘 작동하지만 느린 컴퓨터에서는 캐릭터가 보낸 것과 같은 순서로 캐릭터가받지 못하는 상황이 발생합니다. 예를 들어, 스캐너는 1234567을 직렬 포트로 보냅니다. 내 프로그램은 Char Events 1234567을 보내지 만 활성 프로그램 (예 : Xterm)은 3127456을받습니다. 다양한 장소에서 Xsync를 호출하고 추가했습니다. 잠 들어 전화이지만 도움이되지 않았습니다.

문자의 "질서"를 강요하는 방법이 있습니까?

아니면 활성 창으로 문자열을 보내는 다른 방법이 있습니까 (필요한 경우 외부 프로그램을 사용하는 것도 신경 쓰지 않습니까)?

코드는 다음과 같습니다. 아마도 내가 뭔가 잘못하고있을 것입니다.

#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;
}
//-----------------------------------------------------------------------------
도움이 되었습니까?

해결책

코드의 문제는 XopenDisplay (...)를 사용하여 매번 디스플레이를 열 수 있다는 것입니다. xopendisplay에 대한 모든 호출은 새로운 프로토콜 컨텍스트를 만듭니다. 디스플레이를 한 번만 열고 이벤트를 보낼 때 항상 동일한 디스플레이 핸들을 사용해야합니다. 단일 디스플레이 핸들의 맥락에서 이벤트는 주문 상태를 유지합니다.

sendchar (...)를 호출하기 전에 메인 (...)에서 디스플레이를 한 번 초기화하고 항상 동일한 디스플레이 포인터를 사용하십시오. COM 포트와 같이 완료 될 때만 디스플레이를 닫으십시오.

다른 팁

타임 스탬프가 각각 하나씩 증가하도록 강요 했습니까? 이는 X 서버에 이벤트가 시간이 지남에 따라 퍼져 있음을 알리지만 스캐너가 약 142 스캔/초로 병목 현상을 의미합니다. 그러나 인간이 그 사용에 관여한다고 가정하면 괜찮습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top