📄 vnckeymap.cpp
字号:
for (int i = 0; i < sizeof(keymap) / sizeof(keymap_t); i++)
{
vkMap[keymap[i].keysym] = keymap[i].vk;
extendedMap[keymap[i].keysym] = keymap[i].extended;
}
// Find dead characters for the current keyboard layout
// XXX how could we handle the keyboard layout changing?
BYTE keystate[256];
memset(keystate, 0, 256);
for (int j = 0; j < sizeof(latin1DeadChars); j++)
{
SHORT s = VkKeyScan(latin1DeadChars[j]);
if (s != -1)
{
//rdr::U8 chars[2]; // a 2 Byte buffer seems to be to small, so I changed it to 2 WORD
WORD chars[2];
UINT vkCode = LOBYTE(s);
BYTE modifierState = HIBYTE(s);
keystate[VK_SHIFT] = (modifierState & 1) ? 0x80 : 0;
keystate[VK_CONTROL] = (modifierState & 2) ? 0x80 : 0;
keystate[VK_MENU] = (modifierState & 4) ? 0x80 : 0;
int nchars = ToAscii(vkCode, 0, keystate, (LPWORD)chars, 0);
if (nchars < 0)
{
deadChars.push_back(latin1DeadChars[j]);
// warning!: though the spacing version is returned, the non-spacing
// version is still in the keyboard buffer, therefore it's recommended
// to call ToAscii again with a non-dead key to form a combined character.
// (as this will remove the deadkey from the keyb buffer)
ToAscii(vkCode, 0, keystate, (LPWORD)chars, 0); //
}
}
}
}
void keyEvent(rdr::U32 keysym, bool down)
{
vnclog.Print(LL_INTWARN, VNCLOG("keysym 0x%x down=%d"), keysym, down);
if (keysym>=XK_dead_grave && keysym<=XK_dead_doublequote)
{
if(!down)
return;
if(keysymDead==0)
{
keysymDead=keysym;
return;
}
}
if ((keysym >= 32 && keysym <= 126) ||
(keysym >= 160 && keysym <= 255) ||
(keysym>=XK_dead_grave && keysym<=XK_dead_doublequote))
{
if (keysymDead!=0 && down)
{
rdr::U32 keysymold = keysym;
//vnclog.Print(LL_INTWARN, VNCLOG(" Compose dead 0x%x 0x%x"),keysymDead,keysym);
switch (keysymDead)
{
case XK_dead_grave:
switch(keysym)
{
case XK_A: keysym=XK_Agrave;break;
case XK_E: keysym=XK_Egrave;break;
case XK_I: keysym=XK_Igrave;break;
case XK_O: keysym=XK_Ograve;break;
case XK_U: keysym=XK_Ugrave;break;
case XK_a: keysym=XK_agrave;break;
case XK_e: keysym=XK_egrave;break;
case XK_i: keysym=XK_igrave;break;
case XK_o: keysym=XK_ograve;break;
case XK_u: keysym=XK_ugrave;break;
}
break;
case XK_dead_acute:
case XK_dead_quote:
switch(keysym)
{
case XK_A: keysym=XK_Aacute;break;
case XK_E: keysym=XK_Eacute;break;
case XK_I: keysym=XK_Iacute;break;
case XK_O: keysym=XK_Oacute;break;
case XK_U: keysym=XK_Uacute;break;
case XK_a: keysym=XK_aacute;break;
case XK_e: keysym=XK_eacute;break;
case XK_i: keysym=XK_iacute;break;
case XK_o: keysym=XK_oacute;break;
case XK_u: keysym=XK_uacute;break;
case XK_y: keysym=XK_yacute;break;
case XK_Y: keysym=XK_Yacute;break;
}
break;
case XK_dead_circumflex:
switch(keysym)
{
case XK_A: keysym=XK_Acircumflex;break;
case XK_E: keysym=XK_Ecircumflex;break;
case XK_I: keysym=XK_Icircumflex;break;
case XK_O: keysym=XK_Ocircumflex;break;
case XK_U: keysym=XK_Ucircumflex;break;
case XK_a: keysym=XK_acircumflex;break;
case XK_e: keysym=XK_ecircumflex;break;
case XK_i: keysym=XK_icircumflex;break;
case XK_o: keysym=XK_ocircumflex;break;
case XK_u: keysym=XK_ucircumflex;break;
}
break;
case XK_dead_tilde:
switch(keysym)
{
case XK_A : keysym=XK_Atilde;break;
case XK_N : keysym=XK_Ntilde;break;
case XK_O : keysym=XK_Otilde;break;
case XK_a : keysym=XK_atilde;break;
case XK_n : keysym=XK_ntilde;break;
case XK_o : keysym=XK_otilde;break;
}
break;
case XK_dead_diaeresis:
case XK_dead_doublequote:
switch(keysym)
{
case XK_A: keysym=XK_Adiaeresis;break;
case XK_E: keysym=XK_Ediaeresis;break;
case XK_I: keysym=XK_Idiaeresis;break;
case XK_O: keysym=XK_Odiaeresis;break;
case XK_U: keysym=XK_Udiaeresis;break;
case XK_a: keysym=XK_adiaeresis;break;
case XK_e: keysym=XK_ediaeresis;break;
case XK_i: keysym=XK_idiaeresis;break;
case XK_o: keysym=XK_odiaeresis;break;
case XK_u: keysym=XK_udiaeresis;break;
case XK_y: keysym=XK_ydiaeresis;break;
}
break;
case XK_dead_cedilla:
switch(keysym)
{
case XK_C: keysym=XK_Ccedilla;break;
case XK_c: keysym=XK_ccedilla;break;
}
break;
}
if(keysym == keysymold) // not a composed key
{
doKeyPress(makeUndead(keysymDead), true);
if(keysym == XK_space) // do not print space after not composed dead char
keysym = 0;
else
keysym = makeUndead(keysym);
}
keysymDead=0;
}
doKeyPress(keysym, down);
}
else
{
// see if it's a recognised keyboard key, otherwise ignore it
if (vkMap.find(keysym) == vkMap.end())
{
vnclog.Print(LL_INTWARN, VNCLOG("ignoring unknown keysym %d"),keysym);
return;
}
BYTE vkCode = vkMap[keysym];
DWORD flags = 0;
if (extendedMap[keysym]) flags |= KEYEVENTF_EXTENDEDKEY;
if (!down) flags |= KEYEVENTF_KEYUP;
// vnclog.Print(LL_INTINFO,
// "keyboard key: keysym %d(0x%x) vkCode 0x%x ext %d down %d\n",
// keysym, keysym, vkCode, extendedMap[keysym], down);
if (down && (vkCode == VK_DELETE) &&
((GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0) &&
((GetAsyncKeyState(VK_MENU) & 0x8000) != 0) &&
vncService::IsWinNT())
{
vncService::SimulateCtrlAltDel();
return;
}
if (vncService::IsWin95())
{
switch (vkCode)
{
case VK_RSHIFT: vkCode = VK_SHIFT; break;
case VK_RCONTROL: vkCode = VK_CONTROL; break;
case VK_RMENU: vkCode = VK_MENU; break;
}
}
doKeyboardEvent(vkCode, flags);
}
}
private:
void doKeyPress(rdr::U32 keysym, bool down);
rdr::U32 makeUndead(rdr::U32 key)
{
switch(key) // so simulate the dead key as a normal keypress
{
case XK_dead_grave:
return XK_grave;
case XK_dead_acute:
return XK_acute;
case XK_dead_circumflex:
return XK_asciicircum;
case XK_dead_tilde:
return XK_asciitilde;
case XK_dead_diaeresis:
return XK_diaeresis;
case XK_dead_cedilla:
return XK_cedilla;
case XK_dead_quote:
return XK_apostrophe;
case XK_dead_doublequote:
return XK_quotedbl;
default:
return key;
}
}
std::map<rdr::U32,rdr::U8> vkMap;
std::map<rdr::U32,bool> extendedMap;
} key_mapper;
void Keymapper::doKeyPress(rdr::U32 keysym, bool down)
{
if(keysym == 0)
return;
vnclog.Print(LL_INTINFO, VNCLOG("doKeyPress %x, %d"), keysym, down);
SHORT s = VkKeyScan(keysym);
vnclog.Print(LL_INTWARN, VNCLOG(" SHORT s %i"),s);
bool undead = false;
for (int j = 0; j < deadChars.size(); j++)
if(keysym == deadChars[j]) undead = true;
if (s == -1 || undead)
{
if (down)
{
//vnclog.Print(LL_INTWARN, VNCLOG("down"));
// not a single keypress - try synthesizing dead chars.
{
bool initialzero = false;
int ascii=0;
if(keysym >= 0xa0 && keysym <= 0xff)
{
// map to latin1
initialzero = true;
ascii = keysym;
}
else
{
for (ascii=0;ascii<256;ascii++) //Lookup ascii representation
{
if (keysym==ascii_to_x[ascii]) break;
}
}
//vnclog.Print(LL_INTINFO, VNCLOG("simulating %s%d"), initialzero ? "0":"", ascii);
rdr::U8 a0=ascii/100;
ascii=ascii%100;
rdr::U8 a1=ascii/10;
ascii=ascii%10;
rdr::U8 a2=ascii;
if (ascii!=256)
{
KeyStateModifier shift(VK_SHIFT);
shift.release();
KeyStateModifier lshift(VK_LSHIFT);
lshift.release();
KeyStateModifier rshift(VK_RSHIFT);
rshift.release();
keybd_event(VK_MENU,MapVirtualKey( VK_MENU, 0 ), 0 ,0);
if(initialzero) // enter 0xxx on the numpad -> use latin1
{ // instead of 850
keybd_event(VK_NUMPAD0+a0, MapVirtualKey(VK_NUMPAD0, 0), 0, 0);
keybd_event(VK_NUMPAD0+a0, MapVirtualKey(VK_NUMPAD0, 0),KEYEVENTF_KEYUP,0);
}
keybd_event(VK_NUMPAD0+a0, MapVirtualKey(VK_NUMPAD0+a0, 0), 0, 0);
keybd_event(VK_NUMPAD0+a0, MapVirtualKey(VK_NUMPAD0+a0, 0),KEYEVENTF_KEYUP,0);
keybd_event(VK_NUMPAD0+a1, MapVirtualKey(VK_NUMPAD0+a1, 0),0,0);
keybd_event(VK_NUMPAD0+a1, MapVirtualKey(VK_NUMPAD0+a1, 0),KEYEVENTF_KEYUP, 0);
keybd_event(VK_NUMPAD0+a2, MapVirtualKey(VK_NUMPAD0+a2, 0) ,0, 0);
keybd_event(VK_NUMPAD0+a2, MapVirtualKey(VK_NUMPAD0+a2, 0),KEYEVENTF_KEYUP, 0);
keybd_event(VK_MENU, MapVirtualKey( VK_MENU, 0 ),KEYEVENTF_KEYUP, 0);
return;
}
else
vnclog.Print(LL_INTWARN, VNCLOG("ignoring unrecognised Latin-1 keysym 0x%x"),keysym);
}
}
return;
}
BYTE vkCode = LOBYTE(s);
KeyStateModifier ctrl(VK_CONTROL);
KeyStateModifier alt(VK_MENU);
KeyStateModifier shift(VK_SHIFT);
KeyStateModifier lshift(VK_LSHIFT);
KeyStateModifier rshift(VK_RSHIFT);
if (down)
{
BYTE modifierState = HIBYTE(s);
if (modifierState & 2) ctrl.press();
if (modifierState & 4) alt.press();
if (modifierState & 1)
{
shift.press();
}
else
{
if (vncService::IsWin95())
{
shift.release();
}
else
{
lshift.release();
rshift.release();
}
}
}
//vnclog.Print(LL_INTINFO,
// "latin-1 key: keysym %d(0x%x) vkCode 0x%x down %d\n",
// keysym, keysym, vkCode, down);
doKeyboardEvent(vkCode, down ? 0 : KEYEVENTF_KEYUP);
}
void vncKeymap::keyEvent(CARD32 keysym, bool down)
{
key_mapper.keyEvent(keysym, down);
}
void
SetShiftState(BYTE key, BOOL down)
{
BOOL keystate = (GetAsyncKeyState(key) & 0x8000) != 0;
// This routine sets the specified key to the desired value (up or down)
if ((keystate && down) || ((!keystate) && (!down)))
return;
vnclog.Print(LL_INTINFO,
VNCLOG("setshiftstate %d - (%s->%s)"),
key, keystate ? "down" : "up",
down ? "down" : "up");
// Now send a key event to set the key to the new value
doKeyboardEvent(key, down ? 0 : KEYEVENTF_KEYUP);
keystate = (GetAsyncKeyState(key) & 0x8000) != 0;
vnclog.Print(LL_INTINFO,
VNCLOG("new state %d (%s)"),
key, keystate ? "down" : "up");
}
void
vncKeymap::ClearShiftKeys()
{
if (vncService::IsWinNT())
{
// On NT, clear both sets of keys
// LEFT
SetShiftState(VK_LSHIFT, FALSE);
SetShiftState(VK_LCONTROL, FALSE);
SetShiftState(VK_LMENU, FALSE);
// RIGHT
SetShiftState(VK_RSHIFT, FALSE);
SetShiftState(VK_RCONTROL, FALSE);
SetShiftState(VK_RMENU, FALSE);
}
else
{
// Otherwise, we can't distinguish the keys anyway...
// Clear the shift key states
SetShiftState(VK_SHIFT, FALSE);
SetShiftState(VK_CONTROL, FALSE);
SetShiftState(VK_MENU, FALSE);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -