Pierre Ossman 6 лет назад
Родитель
Сommit
7cc9f6ad07
5 измененных файлов: 131 добавлений и 41 удалений
  1. 4
    7
      doc/keyboard-test.txt
  2. 58
    34
      vncviewer/Viewport.cxx
  3. 9
    0
      vncviewer/Viewport.h
  4. 58
    0
      vncviewer/win32.c
  5. 2
    0
      vncviewer/win32.h

+ 4
- 7
doc/keyboard-test.txt Просмотреть файл

@@ -66,17 +66,16 @@ Client (classic, non-raw, mode)

- CapsLock, NumLock
- Shift, Ctrl
- Alt, AltGr, Super [Win, X11] (FIXME: AltGr broken on Win)
- Alt, AltGr, Super [Win, X11]
- Ctrl+AltGr [Win]
- Meta [X11]
- Left/right identification (FIXME: broken for Shift on Win)
- Left/right identification (FIXME: broken release for Shift on Win)
- CmdL => AltL, CmdR => SuperL, AltL => ModeSwitch, AltR => Level3Shift [OS X]
- Hyper sends Super [X11]

- CapsLock, Shift and AltGr affect symbol lookup
- Ctrl does not affect symbol lookup
- CtrlL+AltR is fake released to compensate for Windows' AltGr magic [Win]
- Ctrl+Alt+<ANY> sends the same symbol as <ANY> (note behaviour above though)
- Ctrl+AltGr+<ANY> sends the same symbol as AltGr+<ANY> (FIXME: broken on Win)
- Ctrl+Alt+<ANY> sends the same symbol as <ANY>
- "Shift press, A press, Shift release, A release" should not send "a release"

- Numpad:
@@ -128,8 +127,6 @@ Client (raw mode)
- Multimedia keys
- Non-character keys

- CtrlL+AltR is fake released to compensate for Windows' AltGr magic [Win]

Client (both modes)
-------------------


+ 58
- 34
vncviewer/Viewport.cxx Просмотреть файл

@@ -115,6 +115,9 @@ static const WORD SCAN_FAKE = 0xaa;
Viewport::Viewport(int w, int h, const rfb::PixelFormat& serverPF, CConn* cc_)
: Fl_Widget(0, 0, w, h), cc(cc_), frameBuffer(NULL),
lastPointerPos(0, 0), lastButtonMask(0),
#ifdef WIN32
altGrArmed(false),
#endif
menuCtrlKey(false), menuAltKey(false), cursor(NULL)
{
#if !defined(WIN32) && !defined(__APPLE__)
@@ -187,6 +190,9 @@ Viewport::~Viewport()
// Unregister all timeouts in case they get a change tro trigger
// again later when this object is already gone.
Fl::remove_timeout(handlePointerTimeout, this);
#ifdef WIN32
Fl::remove_timeout(handleAltGrTimeout, this);
#endif

Fl::remove_system_handler(handleSystemEvent);

@@ -734,26 +740,6 @@ void Viewport::handleKeyPress(int keyCode, rdr::U32 keySym)
}
#endif

#ifdef WIN32
// Ugly hack alert!
//
// Windows doesn't have a proper AltGr, but handles it using fake
// Ctrl+Alt. Unfortunately X11 doesn't generally like the combination
// Ctrl+Alt+AltGr, which we usually end up with when Xvnc tries to
// get everything in the correct state. Cheat and temporarily release
// Ctrl and Alt when we send some other symbol.
if (downKeySym.count(0x1d) && downKeySym.count(0xb8)) {
vlog.debug("Faking release of AltGr (Ctrl_L+Alt_R)");
try {
cc->writer()->keyEvent(downKeySym[0x1d], 0x1d, false);
cc->writer()->keyEvent(downKeySym[0xb8], 0xb8, false);
} catch (rdr::Exception& e) {
vlog.error("%s", e.str());
exit_vncviewer(e.str());
}
}
#endif

// Because of the way keyboards work, we cannot expect to have the same
// symbol on release as when pressed. This breaks the VNC protocol however,
// so we need to keep track of what keysym a key _code_ generated on press
@@ -777,20 +763,6 @@ void Viewport::handleKeyPress(int keyCode, rdr::U32 keySym)
vlog.error("%s", e.str());
exit_vncviewer(e.str());
}

#ifdef WIN32
// Ugly hack continued...
if (downKeySym.count(0x1d) && downKeySym.count(0xb8)) {
vlog.debug("Restoring AltGr state");
try {
cc->writer()->keyEvent(downKeySym[0x1d], 0x1d, true);
cc->writer()->keyEvent(downKeySym[0xb8], 0xb8, true);
} catch (rdr::Exception& e) {
vlog.error("%s", e.str());
exit_vncviewer(e.str());
}
}
#endif
}


@@ -862,6 +834,24 @@ int Viewport::handleSystemEvent(void *event, void *data)

keyCode = ((msg->lParam >> 16) & 0xff);

// Windows doesn't have a proper AltGr, but handles it using fake
// Ctrl+Alt. However the remote end might not be Windows, so we need
// to merge those in to a single AltGr event. We detect this case
// by seeing the two key events directly after each other with a very
// short time between them (<50ms) and supress the Ctrl event.
if (self->altGrArmed) {
self->altGrArmed = false;
Fl::remove_timeout(handleAltGrTimeout);

if (isExtended && (keyCode == 0x38) && (vKey == VK_MENU) &&
((msg->time - self->altGrCtrlTime) < 50)) {
// Alt seen, so this is an AltGr sequence
} else {
// Not Alt, so fire the queued up Ctrl event
self->handleKeyPress(0x1d, XK_Control_L);
}
}

if (keyCode == SCAN_FAKE) {
vlog.debug("Ignoring fake key press (virtual key 0x%02x)", vKey);
return 1;
@@ -921,6 +911,20 @@ int Viewport::handleSystemEvent(void *event, void *data)
if ((keySym == XK_Shift_L) && (keyCode == 0x36))
keySym = XK_Shift_R;

// AltGr handling (see above)
if (win32_has_altgr()) {
if ((keyCode == 0xb8) && (keySym == XK_Alt_R))
keySym = XK_ISO_Level3_Shift;

// Possible start of AltGr sequence?
if ((keyCode == 0x1d) && (keySym == XK_Control_L)) {
self->altGrArmed = true;
self->altGrCtrlTime = msg->time;
Fl::add_timeout(0.1, handleAltGrTimeout, self);
return 1;
}
}

self->handleKeyPress(keyCode, keySym);

return 1;
@@ -934,6 +938,14 @@ int Viewport::handleSystemEvent(void *event, void *data)

keyCode = ((msg->lParam >> 16) & 0xff);

// We can't get a release in the middle of an AltGr sequence, so
// abort that detection
if (self->altGrArmed) {
self->altGrArmed = false;
Fl::remove_timeout(handleAltGrTimeout);
self->handleKeyPress(0x1d, XK_Control_L);
}

if (keyCode == SCAN_FAKE) {
vlog.debug("Ignoring fake key release (virtual key 0x%02x)", vKey);
return 1;
@@ -1046,6 +1058,18 @@ int Viewport::handleSystemEvent(void *event, void *data)
return 0;
}

#ifdef WIN32
void Viewport::handleAltGrTimeout(void *data)
{
Viewport *self = (Viewport *)data;

assert(self);

self->altGrArmed = false;
self->handleKeyPress(0x1d, XK_Control_L);
}
#endif

void Viewport::initContextMenu()
{
contextMenu->clear();

+ 9
- 0
vncviewer/Viewport.h Просмотреть файл

@@ -76,6 +76,10 @@ private:

static int handleSystemEvent(void *event, void *data);

#ifdef WIN32
static void handleAltGrTimeout(void *data);
#endif

void initContextMenu();
void popupContextMenu();

@@ -94,6 +98,11 @@ private:
typedef std::map<int, rdr::U32> DownMap;
DownMap downKeySym;

#ifdef WIN32
bool altGrArmed;
unsigned int altGrCtrlTime;
#endif

rdr::U32 menuKeySym;
int menuKeyCode, menuKeyFLTK;
Fl_Menu_Button *contextMenu;

+ 58
- 0
vncviewer/win32.c Просмотреть файл

@@ -33,6 +33,9 @@
#define MAPVK_VK_TO_CHAR 2
#endif

int has_altgr;
HKL current_layout = 0;

static HANDLE thread;
static DWORD thread_id;

@@ -300,3 +303,58 @@ int win32_vkey_to_keysym(UINT vkey, int extended)

return NoSymbol;
}

int win32_has_altgr(void)
{
BYTE orig_state[256];
BYTE altgr_state[256];

if (current_layout == GetKeyboardLayout(0))
return has_altgr;

// Save current keyboard state so we can get things sane again after
// we're done
if (!GetKeyboardState(orig_state))
return 0;

// We press Ctrl+Alt (Windows fake AltGr) and then test every key
// to see if it produces a printable character. If so then we assume
// AltGr is used in the current layout.

has_altgr = 0;

memset(altgr_state, 0, sizeof(altgr_state));
altgr_state[VK_CONTROL] = 0x80;
altgr_state[VK_MENU] = 0x80;

for (UINT vkey = 0;vkey <= 0xff;vkey++) {
int ret;
WCHAR wstr[10];

// Need to skip this one as it is a bit magical and will trigger
// a false positive
if (vkey == VK_PACKET)
continue;

ret = ToUnicode(vkey, 0, altgr_state, wstr,
sizeof(wstr)/sizeof(wstr[0]), 0);
if (ret == 1) {
has_altgr = 1;
break;
}

if (ret == -1) {
// Dead key, need to clear out state before we proceed
do {
ret = ToUnicode(vkey, 0, altgr_state, wstr,
sizeof(wstr)/sizeof(wstr[0]), 0);
} while (ret < 0);
}
}

SetKeyboardState(orig_state);

current_layout = GetKeyboardLayout(0);

return has_altgr;
}

+ 2
- 0
vncviewer/win32.h Просмотреть файл

@@ -32,6 +32,8 @@ void win32_disable_lowlevel_keyboard(HWND hwnd);

int win32_vkey_to_keysym(UINT vkey, int extended);

int win32_has_altgr(void);

};

#endif

Загрузка…
Отмена
Сохранить