Resolve KASM-2335 "Feature/ ime support"

This commit is contained in:
Matthew McClaskey 2022-03-25 16:18:16 +00:00
parent 0c020f2e79
commit 3f89e5c117
9 changed files with 107 additions and 15 deletions

1
.gitignore vendored
View File

@ -21,3 +21,4 @@ debian/files
debian/kasmvncserver.substvars debian/kasmvncserver.substvars
debian/kasmvncserver/ debian/kasmvncserver/
.pc .pc
.vscode/

2
.gitmodules vendored
View File

@ -1,4 +1,4 @@
[submodule "kasmweb"] [submodule "kasmweb"]
path = kasmweb path = kasmweb
url = https://github.com/kasmtech/noVNC.git url = https://github.com/kasmtech/noVNC.git
branch = master branch = feature/KASM-2335_IME_support_2

View File

@ -77,7 +77,6 @@ namespace rfb {
static BoolParameter ignoreClientSettingsKasm; static BoolParameter ignoreClientSettingsKasm;
static BoolParameter selfBench; static BoolParameter selfBench;
static PresetParameter preferBandwidth; static PresetParameter preferBandwidth;
}; };
}; };

@ -1 +1 @@
Subproject commit df9c9d0d96acef17423c237fea9497850a6c1c17 Subproject commit e2cc682243c55786e719436f214da0f0948f605a

View File

@ -39,6 +39,7 @@
#include "xkbsrv.h" #include "xkbsrv.h"
#include "xkbstr.h" #include "xkbstr.h"
#include "xserver-properties.h" #include "xserver-properties.h"
#include "stdbool.h"
extern _X_EXPORT DevPrivateKey CoreDevicePrivateKey; extern _X_EXPORT DevPrivateKey CoreDevicePrivateKey;
#include <X11/keysym.h> #include <X11/keysym.h>
#include <X11/Xlib.h> #include <X11/Xlib.h>
@ -66,6 +67,8 @@ static const unsigned short *codeMap;
static unsigned int codeMapLen; static unsigned int codeMapLen;
static KeySym pressedKeys[256]; static KeySym pressedKeys[256];
static unsigned int needFree[256];
static bool freeKeys;
static int vncPointerProc(DeviceIntPtr pDevice, int onoff); static int vncPointerProc(DeviceIntPtr pDevice, int onoff);
static void vncKeyboardBell(int percent, DeviceIntPtr device, 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 * Instead we call it from XserverDesktop at an appropriate
* time. * time.
*/ */
void vncInitInputDevice(void) void vncInitInputDevice(bool freeKeyMappings)
{ {
int i, ret; int i, ret;
@ -110,6 +113,8 @@ void vncInitInputDevice(void)
codeMap = code_map_qnum_to_xorgkbd; codeMap = code_map_qnum_to_xorgkbd;
codeMapLen = code_map_qnum_to_xorgkbd_len; codeMapLen = code_map_qnum_to_xorgkbd_len;
#endif #endif
freeKeys = freeKeyMappings;
memset(needFree, 0, sizeof(needFree));
for (i = 0;i < 256;i++) for (i = 0;i < 256;i++)
pressedKeys[i] = NoSymbol; pressedKeys[i] = NoSymbol;
@ -500,6 +505,7 @@ static void vncKeysymKeyboardEvent(KeySym keysym, int down)
pressedKeys[i] = NoSymbol; pressedKeys[i] = NoSymbol;
pressKey(vncKeyboardDev, i, FALSE, "keycode"); pressKey(vncKeyboardDev, i, FALSE, "keycode");
mieqProcessInputEvents(); mieqProcessInputEvents();
return; return;
} }
} }
@ -544,7 +550,7 @@ static void vncKeysymKeyboardEvent(KeySym keysym, int down)
/* No matches. Will have to add a new entry... */ /* No matches. Will have to add a new entry... */
if (keycode == 0) { if (keycode == 0) {
keycode = vncAddKeysym(keysym, state); keycode = vncAddKeysym(keysym, state, needFree, freeKeys);
if (keycode == 0) { if (keycode == 0) {
LOG_ERROR("Failure adding new keysym 0x%x", keysym); LOG_ERROR("Failure adding new keysym 0x%x", keysym);
return; return;

View File

@ -25,12 +25,13 @@
#include <stdlib.h> #include <stdlib.h>
#include <X11/X.h> #include <X11/X.h>
#include "stdbool.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
void vncInitInputDevice(void); void vncInitInputDevice(bool freeKeyMappings);
void vncPointerButtonAction(int buttonMask, const unsigned char skipclick, void vncPointerButtonAction(int buttonMask, const unsigned char skipclick,
const unsigned char skiprelease); const unsigned char skiprelease);
@ -57,7 +58,8 @@ KeyCode vncKeysymToKeycode(KeySym keysym, unsigned state, unsigned *new_state);
int vncIsAffectedByNumLock(KeyCode keycode); 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 #ifdef __cplusplus
} }

View File

@ -25,16 +25,19 @@
#include "xorg-version.h" #include "xorg-version.h"
#include <stdio.h> #include <stdio.h>
#include <limits.h>
#include <X11/keysym.h> #include <X11/keysym.h>
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/Xutil.h> #include <X11/Xutil.h>
#include "RFBGlue.h"
#include "xkbsrv.h" #include "xkbsrv.h"
#include "xkbstr.h" #include "xkbstr.h"
#include "eventstr.h" #include "eventstr.h"
#include "scrnintstr.h" #include "scrnintstr.h"
#include "mi.h" #include "mi.h"
#include "stdbool.h"
#include "Input.h" #include "Input.h"
@ -50,7 +53,15 @@
#endif #endif
#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; extern DeviceIntPtr vncKeyboardDev;
static unsigned int MAX_MAPPINGS = UINT_MAX - 1;
static void vncXkbProcessDeviceEvent(int screenNum, static void vncXkbProcessDeviceEvent(int screenNum,
InternalEvent *event, InternalEvent *event,
@ -536,11 +547,15 @@ int vncIsAffectedByNumLock(KeyCode keycode)
return 1; return 1;
} }
KeyCode vncAddKeysym(KeySym keysym, unsigned state) KeyCode vncAddKeysym(KeySym keysym, unsigned state, unsigned int *needFree, bool freeKeys)
{ {
DeviceIntPtr master; DeviceIntPtr master;
XkbDescPtr xkb; 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; XkbEventCauseRec cause;
XkbChangesRec changes; XkbChangesRec changes;
@ -551,14 +566,45 @@ KeyCode vncAddKeysym(KeySym keysym, unsigned state)
master = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT); master = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT);
xkb = master->key->xkbInfo->desc; xkb = master->key->xkbInfo->desc;
for (key = xkb->max_key_code; key >= xkb->min_key_code; key--) {
if (XkbKeyNumGroups(xkb, key) == 0) //find the first free key to map
break; 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) if (key < xkb->min_key_code)
return 0; 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(&changes, 0, sizeof(changes));
memset(&cause, 0, sizeof(cause)); memset(&cause, 0, sizeof(cause));
@ -612,6 +658,40 @@ KeyCode vncAddKeysym(KeySym keysym, unsigned state)
return key; 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, static void vncXkbProcessDeviceEvent(int screenNum,
InternalEvent *event, InternalEvent *event,
DeviceIntPtr dev) DeviceIntPtr dev)

View File

@ -60,6 +60,10 @@ BoolParameter rawKeyboard("RawKeyboard",
"Send keyboard events straight through and " "Send keyboard events straight through and "
"avoid mapping them to the current keyboard " "avoid mapping them to the current keyboard "
"layout", false); "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", IntParameter queryConnectTimeout("QueryConnectTimeout",
"Number of seconds to show the " "Number of seconds to show the "
"Accept Connection dialog before " "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 // so we abuse the fact that this routine will be called first thing
// once the dix is done initialising. // once the dix is done initialising.
// [1] Technically Xvnc has InitInput(), but libvnc.so has nothing. // [1] Technically Xvnc has InitInput(), but libvnc.so has nothing.
vncInitInputDevice(); vncInitInputDevice(freeKeyMappings);
try { try {
std::list<Socket*> sockets; std::list<Socket*> sockets;