diff --git a/meshcore/KVM/Linux/linux_events.c b/meshcore/KVM/Linux/linux_events.c index c3992c3..1d77b05 100644 --- a/meshcore/KVM/Linux/linux_events.c +++ b/meshcore/KVM/Linux/linux_events.c @@ -23,6 +23,11 @@ extern int change_display; x11tst_struct *x11tst_exports = NULL; extern void kvm_keyboard_unmap_unicode_key(Display *display, int keycode); extern int kvm_keyboard_map_unicode_key(Display *display, uint16_t unicode); +extern int kvm_keyboard_update_map_unicode_key(Display *display, uint16_t unicode, int keycode); + +#define g_keyboardMapCount 8 +int g_keyboardMap[g_keyboardMapCount] = { 0 }; +int g_keyboardMapIndex = 0; static struct keymap_t g_keymap[] = { { XK_BackSpace, VK_BACK }, @@ -216,10 +221,25 @@ void KeyAction(unsigned char vk, int up, Display *display) //printf("%x %x %d %d\n", keysym, vk, keycode, up); if (keycode != 0) { + //ILIBLOGMESSAGEX("VK: %u [%d]", vk, up); + if (!x11tst_exports->XTestFakeKeyEvent(display, keycode, !up, 0)) { return; } x11tst_exports->XFlush(display); } } +void KeyActionUnicode_UNMAP_ALL(Display *display) +{ + int i; + for (i = 0; i < g_keyboardMapCount; ++i) + { + if (g_keyboardMap[i] != 0) + { + kvm_keyboard_unmap_unicode_key(display, g_keyboardMap[i]); + g_keyboardMap[i] = 0; + } + } + g_keyboardMapIndex = 0; +} void KeyActionUnicode(uint16_t unicode, int up, Display *display) { if (change_display) { return; } @@ -227,16 +247,64 @@ void KeyActionUnicode(uint16_t unicode, int up, Display *display) if (up == 0) { - int keycode = kvm_keyboard_map_unicode_key(display, unicode); // Create a key mapping on an unmapped key - if (keycode > 0) - { - x11tst_exports->XTestFakeKeyEvent(display, keycode, 1, 0); - x11tst_exports->XFlush(display); + //ILIBLOGMESSAGEX("UNICODE: %u [%d] <<%ull>>", unicode, up, CurrentTime); + //if (g_keyboardMap[g_keyboardMapIndex] != 0) { kvm_keyboard_unmap_unicode_key(display, g_keyboardMap[g_keyboardMapIndex]); g_keyboardMap[g_keyboardMapIndex] = 0; } + //g_keyboardMap[g_keyboardMapIndex] = kvm_keyboard_map_unicode_key(display, unicode); // Create a key mapping on an unmapped key + //if (g_keyboardMap[g_keyboardMapIndex] > 0) + //{ + // //ILIBLOGMESSAGEX("<<%d>>", g_keyboardMap[g_keyboardMapIndex]); + // x11tst_exports->XTestFakeKeyEvent(display, g_keyboardMap[g_keyboardMapIndex], 1, 0); + // x11tst_exports->XFlush(display); - usleep(10000); // We need a short sleep between KeyDown and KeyUp, to register correctly. - x11tst_exports->XTestFakeKeyEvent(display, keycode, 0, 0); - x11tst_exports->XFlush(display); - kvm_keyboard_unmap_unicode_key(display, keycode); // Delete the key mapping we created above + // x11tst_exports->XTestFakeKeyEvent(display, g_keyboardMap[g_keyboardMapIndex], 0, 0); + // x11tst_exports->XFlush(display); + // + // if (++g_keyboardMapIndex >= g_keyboardMapCount) + // { + // g_keyboardMapIndex = 0; + // } + //} + + if (g_keyboardMap[g_keyboardMapIndex] != 0) + { + g_keyboardMap[g_keyboardMapIndex] = kvm_keyboard_update_map_unicode_key(display, unicode, g_keyboardMap[g_keyboardMapIndex]); // Create a key mapping on an unmapped key } + else + { + g_keyboardMap[g_keyboardMapIndex] = kvm_keyboard_map_unicode_key(display, unicode); // Create a key mapping on an unmapped key + } + if (g_keyboardMap[g_keyboardMapIndex] > 0) + { + //ILIBLOGMESSAGEX("<<%d>>", g_keyboardMap[g_keyboardMapIndex]); + x11tst_exports->XTestFakeKeyEvent(display, g_keyboardMap[g_keyboardMapIndex], 1, 0); + x11tst_exports->XTestFakeKeyEvent(display, g_keyboardMap[g_keyboardMapIndex], 0, 15); + x11tst_exports->XFlush(display); + + if (++g_keyboardMapIndex >= g_keyboardMapCount) + { + g_keyboardMapIndex = 0; + } + } + + + //x11tst_exports->XTestFakeKeyEvent(display, x11tst_exports->XKeysymToKeycode(display, 65), 1, 0); + //x11tst_exports->XFlush(display); + //x11tst_exports->XTestFakeKeyEvent(display, x11tst_exports->XKeysymToKeycode(display, 65), 0, 0); + //x11tst_exports->XFlush(display); + + + + //int keycode = kvm_keyboard_map_unicode_key(display, unicode); // Create a key mapping on an unmapped key + //if (keycode > 0) + //{ + + // x11tst_exports->XTestFakeKeyEvent(display, keycode, 1, 0); + // x11tst_exports->XFlush(display); + + // //usleep(1000 * 15); // We need a short sleep between KeyDown and KeyUp, to register correctly. + // x11tst_exports->XTestFakeKeyEvent(display, keycode, 0, 0); + // x11tst_exports->XFlush(display); + // kvm_keyboard_unmap_unicode_key(display, keycode); // Delete the key mapping we created above + //} } } \ No newline at end of file diff --git a/meshcore/KVM/Linux/linux_events.h b/meshcore/KVM/Linux/linux_events.h index e3b0459..bc1aac3 100644 --- a/meshcore/KVM/Linux/linux_events.h +++ b/meshcore/KVM/Linux/linux_events.h @@ -402,5 +402,7 @@ struct keymap_t { extern void MouseAction(double absX, double absY, int button, short wheel, Display *display); extern void KeyAction(unsigned char vk, int up, Display *display); extern void KeyActionUnicode(uint16_t unicode, int up, Display *display); +extern void KeyActionUnicode_UNMAP_ALL(Display *display); + #endif /* LINUX_EVENTS_H_ */ diff --git a/meshcore/KVM/Linux/linux_kvm.c b/meshcore/KVM/Linux/linux_kvm.c index b71eee6..0d4a6b4 100644 --- a/meshcore/KVM/Linux/linux_kvm.c +++ b/meshcore/KVM/Linux/linux_kvm.c @@ -22,6 +22,7 @@ limitations under the License. #include "microstack/ILibProcessPipe.h" #include #include +#include #include #include @@ -42,6 +43,15 @@ limitations under the License. extern uint32_t crc32c(uint32_t crc, const unsigned char* buf, uint32_t len); extern char* g_ILibCrashDump_path; +ILibQueue keyqueue = NULL; + +typedef struct kvm_keydata +{ + int delay; + uint8_t up; + uint16_t data; +}kvm_keydata; + typedef enum KVM_MouseCursors { KVM_MouseCursor_NOCHANGE = -1, @@ -91,6 +101,7 @@ unsigned short current_display = 0; pid_t g_slavekvm = 0; int master2slave[2]; int slave2master[2]; + FILE *logFile = NULL; int g_enableEvents = 0; extern int gRemoteMouseRenderDefault; @@ -101,6 +112,8 @@ ILibQueue g_messageQ; extern void* tilebuffer; extern char **environ; +struct timespec inputtime; +uint32_t inputcounter = 0; typedef struct x11ext_struct { @@ -155,7 +168,21 @@ void kvm_keyboard_unmap_unicode_key(Display *display, int keycode) // Delete a keymapping that we created previously KeySym keysym_list[] = { 0 }; x11_exports->XChangeKeyboardMapping(display, keycode, 1, keysym_list, 1); - x11_exports->XFlush(display); + x11_exports->XSync(display, 0); +} +int kvm_keyboard_update_map_unicode_key(Display *display, uint16_t unicode, int keycode) +{ + char unicodestring[6]; + + // Convert the unicode character to something xorg will understand + if (sprintf_s(unicodestring, sizeof(unicodestring), "U%04X", unicode) < 0) { return(keycode); } + + // Map the unicode character to one of the unused keys above + KeySym sym = x11_exports->XStringToKeysym(unicodestring); + KeySym keysym_list[] = { sym, sym }; + x11_exports->XChangeKeyboardMapping(display, keycode, 2, keysym_list, 1); + x11_exports->XSync(display, 0); + return(keycode); } int kvm_keyboard_map_unicode_key(Display *display, uint16_t unicode) { @@ -185,13 +212,12 @@ int kvm_keyboard_map_unicode_key(Display *display, uint16_t unicode) if (empty) { empty_keycode = i; break; } // Found it! } x11_exports->XFree(keysyms); - x11_exports->XFlush(display); // Map the unicode character to one of the unused keys above KeySym sym = x11_exports->XStringToKeysym(unicodestring); - KeySym keysym_list[] = { sym }; - x11_exports->XChangeKeyboardMapping(display, empty_keycode, 1, keysym_list, 1); - x11_exports->XFlush(display); + KeySym keysym_list[] = { sym, sym }; + x11_exports->XChangeKeyboardMapping(display, empty_keycode, 2, keysym_list, 1); + x11_exports->XSync(display, 0); return(empty_keycode); } @@ -367,30 +393,6 @@ void kvm_send_display() #define BUFSIZE 65535 int kvm_server_inputdata(char* block, int blocklen); -void* kvm_mainloopinput(void* parm) -{ - int ptr = 0; - int ptr2 = 0; - int len = 0; - char pchRequest2[30000]; - ssize_t cbBytesRead = 0; - - while (!g_shutdown) - { - //fprintf(logFile, "Reading from master in kvm_mainloopinput\n"); - cbBytesRead = read(master2slave[0], pchRequest2 + len, 30000 - len); - //fprintf(logFile, "Read %d bytes from master in kvm_mainloopinput\n", cbBytesRead); - if (cbBytesRead == -1 || cbBytesRead == 0 || g_shutdown) { /*ILIBMESSAGE("KVMBREAK-K1\r\n");*/ g_shutdown = 1; break; } - len += cbBytesRead; - ptr2 = 0; - while ((ptr2 = kvm_server_inputdata((char*)pchRequest2 + ptr, cbBytesRead - ptr)) != 0) { ptr += ptr2; } - if (ptr == len) { len = 0; ptr = 0; } - // TODO: else move the reminder. - } - - return 0; -} - int lockfileCheckFn(const struct dirent *ent) { if (ent == NULL) { @@ -509,6 +511,8 @@ int kvm_init(int displayNo) int dummy1, dummy2, dummy3; char displayString[256] = ""; + if (clock_gettime(CLOCK_MONOTONIC, &inputtime) != 0) { memset(&inputtime, 0, sizeof(inputtime)); } + if (x11ext_exports == NULL) { x11ext_exports = ILibMemory_SmartAllocate(sizeof(x11ext_struct)); @@ -559,8 +563,7 @@ int kvm_init(int displayNo) ((void**)x11_exports)[18] = (void*)dlsym(x11_exports->x11_lib, "XGetKeyboardMapping"); ((void**)x11_exports)[19] = (void*)dlsym(x11_exports->x11_lib, "XStringToKeysym"); ((void**)x11_exports)[20] = (void*)dlsym(x11_exports->x11_lib, "XChangeKeyboardMapping"); - - + ((void**)x11tst_exports)[4] = (void*)x11_exports->XFlush; ((void**)x11tst_exports)[5] = (void*)x11_exports->XKeysymToKeycode; } @@ -664,12 +667,68 @@ int kvm_server_inputdata(char* block, int blocklen) { case MNG_KVM_KEY_UNICODE: // Unicode Key if (size != 7) break; - if (g_enableEvents) KeyActionUnicode(((((unsigned char)block[5]) << 8) + ((unsigned char)block[6])), block[4], eventdisplay); + if (g_enableEvents && block[4] == 0) + { + kvm_keydata *data; + struct timespec curtime; memset(&curtime, 0, sizeof(curtime)); + + while ((data = (kvm_keydata*)ILibCircularQueue_EnQueue(keyqueue)) == NULL) + { + data = (kvm_keydata*)ILibCircularQueue_DeQueue(keyqueue); + if (data->delay < 0) + { + KeyAction((unsigned char)data->data, data->up, eventdisplay); + } + else + { + KeyActionUnicode(data->data, data->up, eventdisplay); + } + } + data->data = ((((unsigned char)block[5]) << 8) + ((unsigned char)block[6])); // Unicode + data->up = block[4]; + if (clock_gettime(CLOCK_MONOTONIC, &curtime) != 0 || ILibTime_timespec_subtract(&curtime, &inputtime) < 1000000000) + { + ++inputcounter; + } + else + { + inputcounter = 0; + } + memcpy_s(&inputtime, sizeof(inputtime), &curtime, sizeof(curtime)); + + if (inputcounter > 8) + { + data->delay = (1000 * 1000); + inputcounter = 0; + } + else + { + data->delay = 0; + } + } break; case MNG_KVM_KEY: // Key { if (size != 6) break; - if (g_enableEvents) KeyAction(block[5], block[4], eventdisplay); + if (g_enableEvents) + { + kvm_keydata *data; + while ((data = (kvm_keydata*)ILibCircularQueue_EnQueue(keyqueue)) == NULL) + { + data = (kvm_keydata*)ILibCircularQueue_DeQueue(keyqueue); + if (data->delay == 0) + { + KeyAction((unsigned char)data->data, data->up, eventdisplay); + } + else + { + KeyActionUnicode(data->data, data->up, eventdisplay); + } + } + data->data = block[5]; // Unicode + data->up = block[4]; + data->delay = -1; + } break; } case MNG_KVM_MOUSE: // Mouse @@ -916,8 +975,13 @@ void bitblt(char *sourcebitmap, int source_width, int source_height, int sx, int ILibMemory_Free(drect); } +void kvm_server_sighandler(int signum, siginfo_t *info, void *context) +{ + g_shutdown = 1; +} void* kvm_server_mainloop(void* parm) { + int maxsleep; Window rr, cr; int rx, ry, wx, wy, rs; unsigned int mr; @@ -970,9 +1034,25 @@ void* kvm_server_mainloop(void* parm) //fprintf(logFile, "After kvm_init.\n"); fflush(logFile); g_shutdown = 0; - pthread_create(&kvmthread, NULL, kvm_mainloopinput, parm); + + struct sigaction action; + memset(&action, 0, sizeof(action)); + action.sa_sigaction = kvm_server_sighandler; + sigemptyset(&action.sa_mask); + action.sa_flags = SA_SIGINFO; + ignore_result(sigaction(SIGTERM, &action, NULL)); + + //pthread_create(&kvmthread, NULL, kvm_mainloopinput, parm); //fprintf(logFile, "Created the kvmthread.\n"); fflush(logFile); + int ptr = 0; + int ptr2 = 0; + int len = 0; + char pchRequest2[30000]; + ssize_t cbBytesRead = 0; + keyqueue = ILibCircularQueue_Create(sizeof(kvm_keydata), 1024); + kvm_keydata *keydata; + while (!g_shutdown) { // Check if there are pending messages to be sent @@ -1020,6 +1100,29 @@ void* kvm_server_mainloop(void* parm) } if (count == 100 && imagedisplay == NULL) { g_shutdown = 1; break; } + FD_ZERO(&readset); + FD_ZERO(&errorset); + FD_ZERO(&writeset); + tv.tv_sec = 0; + tv.tv_usec = 0; + FD_SET(master2slave[0], &readset); + if (select(FD_SETSIZE, &readset, &writeset, &errorset, &tv) > 0 && FD_ISSET(master2slave[0], &readset)) + { + + //fprintf(logFile, "Reading from master in kvm_mainloopinput\n"); + cbBytesRead = read(master2slave[0], pchRequest2 + len, 30000 - len); + //fprintf(logFile, "Read %d bytes from master in kvm_mainloopinput\n", cbBytesRead); + if (cbBytesRead == -1 || cbBytesRead == 0 || g_shutdown) + { + g_shutdown = 1; + break; + } + len += cbBytesRead; + ptr2 = 0; + while ((ptr2 = kvm_server_inputdata((char*)pchRequest2 + ptr, cbBytesRead - ptr)) != 0) { ptr += ptr2; } + if (ptr == len) { len = 0; ptr = 0; } + } + if (cursordisplay == NULL) { if ((cursordisplay = x11_exports->XOpenDisplay(displayString))) @@ -1246,14 +1349,62 @@ void* kvm_server_mainloop(void* parm) // We can't go full speed here, we need to slow this down. height = FRAME_RATE_TIMER; - while (!g_shutdown && height > 0) { if (height > 50) { height -= 50; usleep(50000); } else { usleep(height * 1000); height = 0; } } + while (!g_shutdown && height > 0) + { + if (height > 50) + { + height -= 50; + maxsleep = 50000; + } + else + { + maxsleep = height * 1000; + height = 0; + } + + while ((keydata = (kvm_keydata*)ILibCircularQueue_Peek(keyqueue)) != NULL) + { + if (keydata->delay > 0) + { + // Need to sleep, calculate how much + if (keydata->delay > maxsleep) + { + // Frame Rate Timer is smaller + keydata->delay -= maxsleep; + break; + } + else + { + // Frame Rate timer is larger + maxsleep -= keydata->delay; + usleep(keydata->delay); + keydata->delay = 0; + continue; + } + } + keydata = (kvm_keydata*)ILibCircularQueue_DeQueue(keyqueue); + if (keydata->delay == 0) + { + KeyActionUnicode(keydata->data, keydata->up, eventdisplay); + } + else + { + KeyAction((unsigned char)keydata->data, keydata->up, eventdisplay); + } + } + + usleep(maxsleep); + } } + ILibCircularQueue_Destroy(keyqueue); + close(slave2master[1]); close(master2slave[0]); slave2master[1] = 0; master2slave[0] = 0; + KeyActionUnicode_UNMAP_ALL(eventdisplay); x11_exports->XCloseDisplay(eventdisplay); eventdisplay = NULL; @@ -1263,8 +1414,6 @@ void* kvm_server_mainloop(void* parm) cursordisplay = NULL; } - pthread_join(kvmthread, NULL); - kvmthread = (pthread_t)NULL; if (g_tileInfo != NULL) { for (r = 0; r < TILE_HEIGHT_COUNT; r++) { free(g_tileInfo[r]); } @@ -1433,7 +1582,7 @@ void kvm_cleanup() if (master2slave[1] != 0 && g_slavekvm != 0) { - kill(g_slavekvm, SIGKILL); + kill(g_slavekvm, SIGTERM); waitpid(g_slavekvm, &code, 0); g_slavekvm = 0; } diff --git a/microstack/ILibParsers.c b/microstack/ILibParsers.c index d8d8441..6182d6c 100644 --- a/microstack/ILibParsers.c +++ b/microstack/ILibParsers.c @@ -4703,6 +4703,57 @@ struct ILibXMLNode *ILibParseXML(char *buffer, size_t offset, size_t length) return RetVal; } +typedef struct ILibCircularQueue_Record +{ + void *next; + char data[]; +}ILibCircularQueue_Record; +ILibQueue ILibCircularQueue_Create(size_t entrySize, size_t totalEntries) +{ + totalEntries++; + size_t index; + void *ret = ILibMemory_SmartAllocateEx(2 * sizeof(void*), (sizeof(ILibCircularQueue_Record) + entrySize)*totalEntries); + ((void**)ret)[0] = ((void**)ret)[1] = ILibMemory_Extra(ret); + + char *data = (char*)ILibMemory_Extra(ret); + for (index = 0; index < totalEntries; ++index) + { + ((ILibCircularQueue_Record*)data)->next = (index == totalEntries - 1) ? ILibMemory_Extra(ret) : (data + sizeof(ILibCircularQueue_Record) + entrySize); + data = ((ILibCircularQueue_Record*)data)->next; + } + return(ret); +} +void* ILibCircularQueue_EnQueue(ILibQueue circularQueue) +{ + ILibCircularQueue_Record *head = (ILibCircularQueue_Record*)((void**)circularQueue)[0]; + ILibCircularQueue_Record *tail = (ILibCircularQueue_Record*)((void**)circularQueue)[1]; + ILibCircularQueue_Record *next = (ILibCircularQueue_Record*)tail->next; + + if (next == head) { return(NULL); } // No Space + ((void**)circularQueue)[1] = next; + return(tail->data); +} +void* ILibCircularQueue_DeQueue(ILibQueue circularQueue) +{ + ILibCircularQueue_Record *head = (ILibCircularQueue_Record*)((void**)circularQueue)[0]; + ILibCircularQueue_Record *tail = (ILibCircularQueue_Record*)((void**)circularQueue)[1]; + if (head == tail) { return(NULL); } // Empty + + ((void**)circularQueue)[0] = head->next; + return(head->data); +} +void* ILibCircularQueue_Peek(ILibQueue circularQueue) +{ + ILibCircularQueue_Record *head = (ILibCircularQueue_Record*)((void**)circularQueue)[0]; + ILibCircularQueue_Record *tail = (ILibCircularQueue_Record*)((void**)circularQueue)[1]; + if (head == tail) { return(NULL); } // Empty + return(head->data); +} +int ILibCircularQueue_IsEmpty(ILibQueue circularQueue) +{ + return(((void**)circularQueue)[0] == ((void**)circularQueue)[1]); +} + /*! \fn ILibQueue_Create() \brief Create an empty Queue \return An empty queue diff --git a/microstack/ILibParsers.h b/microstack/ILibParsers.h index e3e187c..c67b754 100644 --- a/microstack/ILibParsers.h +++ b/microstack/ILibParsers.h @@ -515,6 +515,7 @@ int ILibIsRunningOnChainThread(void* chain); time_t ILibTime_Parse(char *timeString); char* ILibTime_Serialize(time_t timeVal); long long ILibGetUptime(); + #define ILibTime_timespec_subtract(bigger, smaller) ((uint64_t)(((bigger)->tv_sec - (smaller)->tv_sec) * 1000000000) + (uint64_t)((bigger)->tv_nsec - (smaller)->tv_nsec)) uint64_t ILibHTONLL(uint64_t v); uint64_t ILibNTOHLL(uint64_t v); @@ -904,6 +905,13 @@ int ILibIsRunningOnChainThread(void* chain); \{ */ typedef void* ILibQueue; + ILibQueue ILibCircularQueue_Create(size_t entrySize, size_t totalEntries); + void* ILibCircularQueue_EnQueue(ILibQueue circularQueue); + void* ILibCircularQueue_DeQueue(ILibQueue circularQueue); + void* ILibCircularQueue_Peek(ILibQueue circularQueue); + int ILibCircularQueue_IsEmpty(ILibQueue circularQueue); + #define ILibCircularQueue_Destroy(circularQueue) ILibMemory_Free(circularQueue) + ILibQueue ILibQueue_Create(); void ILibQueue_Destroy(ILibQueue q); int ILibQueue_IsEmpty(ILibQueue q);