إرسال سلسلة (الحروف) إلى الإطار النشط
-
22-07-2019 - |
سؤال
وكتبت برنامج بسيط هو أن يقرأ حرفا من جهاز خارجي (شريط رمز الماسح الضوئي) من المنفذ التسلسلي (/ ديف / ttyS1) ويتغذى عليه إلى الإطار النشط حاليا (باستخدام XSendEvent).
والبرنامج يعمل بشكل جيد على أجهزة الكمبيوتر بشكل أسرع، ولكن على بطء منها يحدث الوضع (في كثير من الأحيان) أن الأحرف لا تحصل تلقى في نفس الترتيب الذي تم إرسالها. على سبيل المثال، الماسح الضوئي يرسل 1234567 إلى المنفذ التسلسلي، يرسل برنامجي أحداث شار 1234567، ولكن البرنامج النشط (إكس تيرم على سبيل المثال) يتلقى 3127456. حاولت يدعو XSync في أماكن مختلفة وإضافة <م> usleep م> المكالمات، ولكنها لم يساعد.
هل لديها فكرة عن كيفية إجبار "النظام" من الأحرف؟
وأم أن هناك طريقة أخرى لإرسال السلسلة إلى الإطار النشط (أنا لا أمانع حتى باستخدام برنامج خارجي إذا لزم الأمر)؟
وهنا هو رمز، ربما أنا فقط تفعل شيئا خطأ:
#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 يخلق سياق بروتوكول جديد. يجب أن افتح الشاشة مرة واحدة فقط، ودائما استخدام نفس مقبض العرض عند إرسال هذه الأحداث. في سياق مقبض عرض واحد، ويضمن الأحداث أن يبقي أمر.
وتهيئة الشاشة مرة واحدة، على سبيل المثال، في main (...)، قبل البدء في استدعاء sendChar (...)، ودائما استخدام نفس مؤشر العرض. إغلاق العرض فقط عند الانتهاء منها، كما تفعل مع ميناء كوم.
نصائح أخرى
هل محاولة فرض الطابع الزمني إلى زيادة واحد لكل؟ يجب أن أقول خادم X التي تنتشر الأحداث عبر الزمن، ولكنه يعني أيضا أنه اختناقات الماسح الضوئي إلى حوالي 142 بالاشعة / ثانية. هذا يبدو بخير على الرغم من افتراض البشر يشاركون في استخدامه.