diff --git a/.gitignore b/.gitignore index ccb6180..46ba2ea 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ debian/files debian/kasmvncserver.substvars debian/kasmvncserver/ .pc +.vscode/ diff --git a/.gitmodules b/.gitmodules index e43a13a..3f757d8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "kasmweb"] path = kasmweb url = https://github.com/kasmtech/noVNC.git - branch = master + branch = feature/KASM-2335_IME_support_2 diff --git a/common/rfb/ServerCore.cxx b/common/rfb/ServerCore.cxx index 1d568c1..23832ec 100644 --- a/common/rfb/ServerCore.cxx +++ b/common/rfb/ServerCore.cxx @@ -226,4 +226,4 @@ static void bandwidthPreset() { rfb::PresetParameter rfb::Server::preferBandwidth ("PreferBandwidth", "Set various options for lower bandwidth use. The default is off, aka to prefer quality.", - false, bandwidthPreset); + false, bandwidthPreset); \ No newline at end of file diff --git a/common/rfb/ServerCore.h b/common/rfb/ServerCore.h index 70075bf..9717cc1 100644 --- a/common/rfb/ServerCore.h +++ b/common/rfb/ServerCore.h @@ -77,7 +77,6 @@ namespace rfb { static BoolParameter ignoreClientSettingsKasm; static BoolParameter selfBench; static PresetParameter preferBandwidth; - }; }; diff --git a/kasmweb b/kasmweb index df9c9d0..e2cc682 160000 --- a/kasmweb +++ b/kasmweb @@ -1 +1 @@ -Subproject commit df9c9d0d96acef17423c237fea9497850a6c1c17 +Subproject commit e2cc682243c55786e719436f214da0f0948f605a diff --git a/unix/xserver/hw/vnc/Input.c b/unix/xserver/hw/vnc/Input.c index e8f9170..d85f4dd 100644 --- a/unix/xserver/hw/vnc/Input.c +++ b/unix/xserver/hw/vnc/Input.c @@ -39,6 +39,7 @@ #include "xkbsrv.h" #include "xkbstr.h" #include "xserver-properties.h" +#include "stdbool.h" extern _X_EXPORT DevPrivateKey CoreDevicePrivateKey; #include #include @@ -66,6 +67,8 @@ static const unsigned short *codeMap; static unsigned int codeMapLen; static KeySym pressedKeys[256]; +static unsigned int needFree[256]; +static bool freeKeys; static int vncPointerProc(DeviceIntPtr pDevice, int onoff); static void vncKeyboardBell(int percent, DeviceIntPtr device, @@ -91,7 +94,7 @@ static void vncKeysymKeyboardEvent(KeySym keysym, int down); * Instead we call it from XserverDesktop at an appropriate * time. */ -void vncInitInputDevice(void) +void vncInitInputDevice(bool freeKeyMappings) { int i, ret; @@ -110,6 +113,8 @@ void vncInitInputDevice(void) codeMap = code_map_qnum_to_xorgkbd; codeMapLen = code_map_qnum_to_xorgkbd_len; #endif + freeKeys = freeKeyMappings; + memset(needFree, 0, sizeof(needFree)); for (i = 0;i < 256;i++) pressedKeys[i] = NoSymbol; @@ -500,6 +505,7 @@ static void vncKeysymKeyboardEvent(KeySym keysym, int down) pressedKeys[i] = NoSymbol; pressKey(vncKeyboardDev, i, FALSE, "keycode"); mieqProcessInputEvents(); + return; } } @@ -544,7 +550,7 @@ static void vncKeysymKeyboardEvent(KeySym keysym, int down) /* No matches. Will have to add a new entry... */ if (keycode == 0) { - keycode = vncAddKeysym(keysym, state); + keycode = vncAddKeysym(keysym, state, needFree, freeKeys); if (keycode == 0) { LOG_ERROR("Failure adding new keysym 0x%x", keysym); return; diff --git a/unix/xserver/hw/vnc/Input.h b/unix/xserver/hw/vnc/Input.h index ddc4e06..8041224 100644 --- a/unix/xserver/hw/vnc/Input.h +++ b/unix/xserver/hw/vnc/Input.h @@ -25,12 +25,13 @@ #include #include +#include "stdbool.h" #ifdef __cplusplus extern "C" { #endif -void vncInitInputDevice(void); +void vncInitInputDevice(bool freeKeyMappings); void vncPointerButtonAction(int buttonMask, const unsigned char skipclick, const unsigned char skiprelease); @@ -57,7 +58,8 @@ KeyCode vncKeysymToKeycode(KeySym keysym, unsigned state, unsigned *new_state); int vncIsAffectedByNumLock(KeyCode keycode); -KeyCode vncAddKeysym(KeySym keysym, unsigned state); +KeyCode vncAddKeysym(KeySym keysym, unsigned state, unsigned int *needfree, bool freeKeys); +void vncRemoveKeycode(unsigned keycode); #ifdef __cplusplus } diff --git a/unix/xserver/hw/vnc/InputXKB.c b/unix/xserver/hw/vnc/InputXKB.c index 50a2130..248bd10 100644 --- a/unix/xserver/hw/vnc/InputXKB.c +++ b/unix/xserver/hw/vnc/InputXKB.c @@ -25,16 +25,19 @@ #include "xorg-version.h" #include +#include #include #include #include +#include "RFBGlue.h" #include "xkbsrv.h" #include "xkbstr.h" #include "eventstr.h" #include "scrnintstr.h" #include "mi.h" +#include "stdbool.h" #include "Input.h" @@ -50,7 +53,15 @@ #endif #endif +#define LOG_NAME "Input" + +#define LOG_ERROR(...) vncLogError(LOG_NAME, __VA_ARGS__) +#define LOG_STATUS(...) vncLogStatus(LOG_NAME, __VA_ARGS__) +#define LOG_INFO(...) vncLogInfo(LOG_NAME, __VA_ARGS__) +#define LOG_DEBUG(...) vncLogDebug(LOG_NAME, __VA_ARGS__) + extern DeviceIntPtr vncKeyboardDev; +static unsigned int MAX_MAPPINGS = UINT_MAX - 1; static void vncXkbProcessDeviceEvent(int screenNum, InternalEvent *event, @@ -536,12 +547,16 @@ int vncIsAffectedByNumLock(KeyCode keycode) return 1; } -KeyCode vncAddKeysym(KeySym keysym, unsigned state) +KeyCode vncAddKeysym(KeySym keysym, unsigned state, unsigned int *needFree, bool freeKeys) { DeviceIntPtr master; XkbDescPtr xkb; - unsigned int key; - + unsigned int key = 0; + unsigned int i; + unsigned int newest_k = 0; + unsigned int oldest_k = 0; + unsigned int freeCnt = 0; + XkbEventCauseRec cause; XkbChangesRec changes; @@ -551,14 +566,45 @@ KeyCode vncAddKeysym(KeySym keysym, unsigned state) master = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT); xkb = master->key->xkbInfo->desc; - for (key = xkb->max_key_code; key >= xkb->min_key_code; key--) { - if (XkbKeyNumGroups(xkb, key) == 0) - break; + + //find the first free key to map + for (i = xkb->max_key_code; i >= xkb->min_key_code; i--) { + if (XkbKeyNumGroups(xkb, i) == 0 && *(needFree + i) != UINT_MAX) { + if (++freeCnt == 1) + key = i; + } } if (key < xkb->min_key_code) return 0; + //find the oldest and newest keys that have been remapped + for (i = 1;i < 256;i++) { + //protect from uint rollover + if (*(needFree + i) == MAX_MAPPINGS) + *(needFree + i) = 1; + if (*(needFree + i) > *(needFree + newest_k) && *(needFree + i) != UINT_MAX) + newest_k = i; + if (*(needFree + i) < *(needFree + oldest_k) && *(needFree +i) > 0) + oldest_k = i; + //mark as free to use + if (*(needFree + i) == UINT_MAX) + *(needFree + i) = 0; + } + *(needFree + key) = ++(*(needFree + newest_k)); + + //if running low on free keys, free the oldest key that was used + if (freeCnt < 3 && *(needFree + oldest_k) > 0 && freeKeys) { + vncRemoveKeycode(oldest_k); + LOG_DEBUG("Removed mapping for keycode %d", oldest_k); + //mark as free to use after one more cycle + *(needFree + oldest_k) = UINT_MAX; + } else if (freeCnt < 3 && freeKeys) { + //this should only happen if the system had fewer than 3 free keys to begin with + LOG_INFO("The system has fewer than 3 unmapped keys with no available keys to free."); + return 0; + } + memset(&changes, 0, sizeof(changes)); memset(&cause, 0, sizeof(cause)); @@ -612,6 +658,40 @@ KeyCode vncAddKeysym(KeySym keysym, unsigned state) return key; } +void vncRemoveKeycode(unsigned keycode) +{ + DeviceIntPtr master; + XkbDescPtr xkb; + + XkbEventCauseRec cause; + XkbChangesRec changes; + + master = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT); + xkb = master->key->xkbInfo->desc; + + memset(&changes, 0, sizeof(changes)); + memset(&cause, 0, sizeof(cause)); + + XkbSetCauseUnknown(&cause); + + KeySym ks = NoSymbol; + + KeySymsRec keysyms; + keysyms.minKeyCode = keycode; + keysyms.maxKeyCode = keycode; + keysyms.mapWidth = 1; + keysyms.map = &ks; + + unsigned check = 0; + XkbUpdateKeyTypesFromCore(master, &keysyms, keycode, 1, &changes); + XkbUpdateActions(master, keycode, 1, &changes, &check, &cause); + + if (check) + XkbCheckSecondaryEffects(master->key->xkbInfo, 1, &changes, &cause); + + XkbSendNotification(master, &changes, &cause); +} + static void vncXkbProcessDeviceEvent(int screenNum, InternalEvent *event, DeviceIntPtr dev) diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc index 26a9bfd..111cf26 100644 --- a/unix/xserver/hw/vnc/XserverDesktop.cc +++ b/unix/xserver/hw/vnc/XserverDesktop.cc @@ -60,6 +60,10 @@ BoolParameter rawKeyboard("RawKeyboard", "Send keyboard events straight through and " "avoid mapping them to the current keyboard " "layout", false); +BoolParameter freeKeyMappings("FreeKeyMappings", + "Automatically free added keyboard mappings " + "when there are not enough unused keys to " + "map symbols to.", false); IntParameter queryConnectTimeout("QueryConnectTimeout", "Number of seconds to show the " "Accept Connection dialog before " @@ -370,7 +374,7 @@ void XserverDesktop::blockHandler(int* timeout) // so we abuse the fact that this routine will be called first thing // once the dix is done initialising. // [1] Technically Xvnc has InitInput(), but libvnc.so has nothing. - vncInitInputDevice(); + vncInitInputDevice(freeKeyMappings); try { std::list sockets;