key_translation xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state) { key_translation tr = { 0, 0 }; tr = keymap[keysym & KEYMAP_MASK]; if (tr.modifiers & MapInhibitMask) { DEBUG_KBD(("Inhibiting key\n")); tr.scancode = 0; return tr; } if (tr.modifiers & MapLocalStateMask) { /* The modifiers to send for this key should be obtained from the local state. Currently, only shift is implemented. */ if (state & ShiftMask) { tr.modifiers = MapLeftShiftMask; } } if (tr.scancode != 0) { DEBUG_KBD(("Found key translation, scancode=0x%x, modifiers=0x%x\n", tr.scancode, tr.modifiers)); return tr; } if (keymap_loaded) warning("No translation for (keysym 0x%lx, %s)\n", keysym, get_ksname(keysym)); /* not in keymap, try to interpret the raw scancode */ if ((keycode >= min_keycode) && (keycode <= 0x60)) { tr.scancode = keycode - min_keycode; /* The modifiers to send for this key should be obtained from the local state. Currently, only shift is implemented. */ if (state & ShiftMask) { tr.modifiers = MapLeftShiftMask; } DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode)); } else { DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode)); } return tr; }
key_translation xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state) { key_translation tr = { 0, 0, 0, 0 }; key_translation *ptr; ptr = keymap[keysym & KEYMAP_MASK]; if (ptr) { tr = *ptr; if (tr.seq_keysym == 0) /* Normal scancode translation */ { if (MASK_HAS_BITS(tr.modifiers, MapInhibitMask)) { DEBUG_KBD(("Inhibiting key\n")); tr.scancode = 0; return tr; } if (MASK_HAS_BITS(tr.modifiers, MapLocalStateMask)) { /* The modifiers to send for this key should be obtained from the local state. Currently, only shift is implemented. */ if (MASK_HAS_BITS(state, ShiftMask)) { tr.modifiers = MapLeftShiftMask; } } /* Windows interprets CapsLock+Ctrl+key differently from Shift+Ctrl+key. Since we are simulating CapsLock with Shifts, things like Ctrl+f with CapsLock on breaks. To solve this, we are releasing Shift if Ctrl is on, but only if Shift isn't physically pressed. */ if (MASK_HAS_BITS(tr.modifiers, MapShiftMask) && MASK_HAS_BITS(remote_modifier_state, MapCtrlMask) && !MASK_HAS_BITS(state, ShiftMask)) { DEBUG_KBD(("Non-physical Shift + Ctrl pressed, releasing Shift\n")); MASK_REMOVE_BITS(tr.modifiers, MapShiftMask); } DEBUG_KBD(("Found scancode translation, scancode=0x%x, modifiers=0x%x\n", tr.scancode, tr.modifiers)); } } else { if (keymap_loaded) warning("No translation for (keysym 0x%lx, %s)\n", keysym, get_ksname(keysym)); /* not in keymap, try to interpret the raw scancode */ if (((int) keycode >= min_keycode) && (keycode <= 0x60)) { tr.scancode = keycode - min_keycode; /* The modifiers to send for this key should be obtained from the local state. Currently, only shift is implemented. */ if (MASK_HAS_BITS(state, ShiftMask)) { tr.modifiers = MapLeftShiftMask; } DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode)); } else { DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode)); } } return tr; }
/* Handle special key combinations */ RD_BOOL handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, RD_BOOL pressed) { DEBUG_KBD(("handle_special_keys (keysym 0x%x, %s state 0x%x, pressed %d)\n", keysym, get_ksname(keysym), state, pressed)); DEBUG_KBD(("Control_L %d, Control_R %d, Alt_L %d, Alt_R %d\n", get_key_state(state, XK_Control_L), get_key_state(state, XK_Control_R), get_key_state(state, XK_Alt_L), get_key_state(state, XK_Alt_R))); if (keysym == XK_Alt_L || keysym == XK_Alt_R || keysym == XK_Control_L || keysym == XK_Control_R) { int new_state = state; if (pressed) new_state |= get_keysym_mask(keysym); else new_state &= ~get_keysym_mask(keysym); new_state &= ~get_keysym_mask(XK_Num_Lock); if (pressed) { if ((new_state & (get_keysym_mask(XK_Alt_L) | get_keysym_mask(XK_Alt_R))) && (new_state & (get_keysym_mask(XK_Control_L) | get_keysym_mask(XK_Control_R)))) { ctrl_alt_pressed = True; DEBUG_KBD(("Ctrl-Alt Pressed\n")); } } else { if (ctrl_alt_pressed && !new_state) { DEBUG_KBD(("Ctrl-Alt Released\n")); if (g_ungrab_on_ctrlalt) xwin_ungrab_keyboard(); } } } else if (pressed) { ctrl_alt_pressed = False; if (!get_keysym_mask(keysym)) xwin_grab_keyboard(); } switch (keysym) { case XK_Return: if ((get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R)) && (get_key_state(state, XK_Control_L) || get_key_state(state, XK_Control_R))) { /* Ctrl-Alt-Enter: toggle full screen */ if (pressed) xwin_toggle_fullscreen(); return True; } break; case XK_Break: /* Send Break sequence E0 46 E0 C6 */ if (pressed) { rdp_send_scancode(ev_time, RDP_KEYPRESS, (SCANCODE_EXTENDED | 0x46)); rdp_send_scancode(ev_time, RDP_KEYPRESS, (SCANCODE_EXTENDED | 0xc6)); } /* No release sequence */ return True; break; case XK_Pause: /* According to MS Keyboard Scan Code Specification, pressing Pause should result in E1 1D 45 E1 9D C5. I'm not exactly sure of how this is supposed to be sent via RDP. The code below seems to work, but with the side effect that Left Ctrl stays down. Therefore, we release it when Pause is released. */ if (pressed) { rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0); rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x1d, 0); rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x45, 0); rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0); rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x9d, 0); rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xc5, 0); } else { /* Release Left Ctrl */ rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYRELEASE, 0x1d, 0); } return True; break; case XK_Meta_L: /* Windows keys */ case XK_Super_L: case XK_Hyper_L: send_winkey(ev_time, pressed, True); return True; break; case XK_Meta_R: case XK_Super_R: case XK_Hyper_R: send_winkey(ev_time, pressed, False); return True; break; case XK_space: /* Prevent access to the Windows system menu in single app mode */ if (g_win_button_size && (get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R))) return True; break; case XK_Num_Lock: /* Synchronize on key release */ if (g_numlock_sync && !pressed) rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, ui_get_numlock_state(read_keyboard_state()), 0); /* Inhibit */ return True; break; case XK_Overlay1_Enable: /* Toggle SeamlessRDP */ if (pressed) ui_seamless_toggle(); break; } return False; }