示例#1
0
void AutoTypePlatformX11::unload()
{
    // Restore the KeyboardMapping to its original state.
    AddKeysym(NoSymbol);

    if (m_keysymTable) {
        XFree(m_keysymTable);
    }

    if (m_xkb) {
        XkbFreeKeyboard(m_xkb, XkbAllComponentsMask, True);
    }

    m_loaded = false;
}
示例#2
0
void KeyEvent(CARD32 keysym, Bool down)
{
  int i;
  unsigned state, new_state;
  KeyCode keycode;

  unsigned level_three_mask;
  KeyCode shift_press = 0, level_three_press = 0;
  KeyCode *shift_release = NULL, *level_three_release = NULL;

  /*
   * Release events must match the press event, so look up what
   * keycode we sent for the press.
   */
  if (!down) {
    for (i = 0; i < 256; i++) {
      if (pressedKeys[i] == keysym) {
        pressedKeys[i] = NoSymbol;
        PressKey(kbdDevice, i, FALSE, "keycode");
        mieqProcessInputEvents();
        return;
      }
    }

    /*
     * This can happen quite often as we ignore some
     * key presses.
     */
    if (xkbDebug)
      rfbLog("Unexpected release of keysym 0x%x\n", keysym);

    return;
  }

  /*
   * Since we are checking the current state to determine if we need
   * to fake modifiers, we must make sure that everything put on the
   * input queue is processed before we start. Otherwise, shift may be
   * stuck down.
   */
  mieqProcessInputEvents();

  state = GetKeyboardState();

  keycode = KeysymToKeycode(keysym, state, &new_state);

  /* Try some equivalent keysyms if we couldn't find a perfect match */
  if (keycode == 0) {
    for (i = 0; i < sizeof(altKeysym) / sizeof(altKeysym[0]); i++) {
      KeySym altsym;

      if (altKeysym[i].a == keysym)
        altsym = altKeysym[i].b;
      else if (altKeysym[i].b == keysym)
        altsym = altKeysym[i].a;
      else
        continue;

      keycode = KeysymToKeycode(altsym, state, &new_state);
      if (keycode != 0)
        break;
    }
  }

  /* We don't have lock synchronisation... */
  if (IsLockModifier(keycode, new_state) && ignoreLockModifiers) {
    if (xkbDebug)
      rfbLog("Ignoring lock key (e.g. caps lock)\n");
    return;
  }

  /* No matches. Will have to add a new entry... */
  if (keycode == 0) {
    keycode = AddKeysym(keysym, state);
    if (keycode == 0) {
      rfbLog("ERROR: Could not add new keysym 0x%x\n", keysym);
      return;
    }

    rfbLog("Mapped unknown keysym 0x%x to keycode %d\n", keysym, keycode);

    /*
     * The state given to addKeysym() is just a hint and
     * the actual result might still require some state
     * changes.
     */
    keycode = KeysymToKeycode(keysym, state, &new_state);
    if (keycode == 0) {
      rfbLog("ERROR: Cannot generate keycode for newly-added keysym 0x%x\n",
             keysym);
      return;
    }
  }

  /*
   * X11 generally lets shift toggle the keys on the numeric pad
   * the same way NumLock does. This is however not the case on
   * other systems like Windows. As a result, some applications
   * get confused when we do a fake shift to get the same effect
   * that having NumLock active would produce.
   *
   * Until we have proper NumLock synchronisation (so we can
   * avoid faking shift), we try to avoid the fake shifts if we
   * can use an alternative keysym.
   */
  if (((state & ShiftMask) != (new_state & ShiftMask)) &&
      avoidShiftNumLock && IsAffectedByNumLock(keycode)) {
    KeyCode keycode2 = 0;
    unsigned new_state2;

    if (xkbDebug)
      rfbLog("Finding alternative to keysym 0x%x to avoid fake shift for numpad\n",
             keysym);

    for (i = 0; i < sizeof(altKeysym) / sizeof(altKeysym[0]); i++) {
      KeySym altsym;

      if (altKeysym[i].a == keysym)
        altsym = altKeysym[i].b;
      else if (altKeysym[i].b == keysym)
        altsym = altKeysym[i].a;
      else
        continue;

      keycode2 = KeysymToKeycode(altsym, state, &new_state2);
      if (keycode2 == 0)
        continue;

      if (((state & ShiftMask) != (new_state2 & ShiftMask)) &&
          IsAffectedByNumLock(keycode2))
        continue;

      break;
    }

    if (i == sizeof(altKeysym) / sizeof(altKeysym[0])) {
      if (xkbDebug)
        rfbLog("No alternative keysym found\n");
    } else {
      keycode = keycode2;
      new_state = new_state2;
    }
  }

  /*
   * "Shifted Tab" is a bit of a mess. Some systems have varying,
   * special keysyms for this symbol. VNC mandates that clients
   * should always send the plain XK_Tab keysym and the server
   * should deduce the meaning based on current Shift state.
   * To comply with this, we will find the keycode that sends
   * XK_Tab, and make sure that Shift isn't cleared. This can
   * possibly result in a different keysym than XK_Tab, but that
   * is the desired behaviour.
   *
   * Note: We never get ISO_Left_Tab here because it's already
   *       been translated in VNCSConnectionST.
   */
  if (keysym == XK_Tab && (state & ShiftMask))
    new_state |= ShiftMask;

  /*
   * We need a bigger state change than just shift,
   * so we need to know what the mask is for level 3 shifts.
   */
  if ((new_state & ~ShiftMask) != (state & ~ShiftMask))
    level_three_mask = GetLevelThreeMask();
  else
    level_three_mask = 0;

  shift_press = level_three_press = 0;

  /* Need a fake press or release of shift? */
  if (!(state & ShiftMask) && (new_state & ShiftMask) && fakeShift) {
    shift_press = PressShift();
    if (shift_press == 0) {
      rfbLog("ERROR: Unable to find modifier key for Shift key press\n");
      return;
    }
    PressKey(kbdDevice, shift_press, TRUE, "temp shift");
  } else if ((state & ShiftMask) && !(new_state & ShiftMask) && fakeShift) {
    int index = 0;
    KeyCode *shift_release = ReleaseShift();
    if (!shift_release) {
      rfbLog("ERROR: Unable to find modifier key(s) for Shift key release\n");
      return;
    }
    while (shift_release[index])
      PressKey(kbdDevice, shift_release[index++], FALSE, "temp shift");
  }

  /* Need a fake press or release of level three shift? */
  if (!(state & level_three_mask) && (new_state & level_three_mask) &&
      fakeShift) {
    level_three_press = PressLevelThree();
    if (level_three_press == 0) {
      rfbLog("ERROR: Unable to find modifier key for ISO_Level3_Shift/Mode_Switch key press\n");
      return;
    }
    PressKey(kbdDevice, level_three_press, TRUE, "temp level 3 shift");
  } else if ((state & level_three_mask) && !(new_state & level_three_mask) &&
             fakeShift) {
    int index = 0;
    level_three_release = ReleaseLevelThree();
    if (!level_three_release) {
      rfbLog("ERROR: Unable to find modifier key(s) for ISO_Level3_Shift/Mode_Switch key release\n");
      return;
    }
    while (level_three_release[index])
      PressKey(kbdDevice, level_three_release[index++], FALSE,
               "temp level 3 shift");
  }

  /* Now press the actual key */
  PressKey(kbdDevice, keycode, TRUE, "keycode");

  /* And store the mapping so that we can do a proper release later */
  for (i = 0; i < 256; i++) {
    if (i == keycode)
      continue;
    if (pressedKeys[i] == keysym) {
      rfbLog("ERROR: Keysym 0x%x generated by both keys %d and %d\n", keysym,
             i, keycode);
      pressedKeys[i] = NoSymbol;
    }
  }

  pressedKeys[keycode] = keysym;

  /* Undo any fake level three shift */
  if (level_three_press != 0)
    PressKey(kbdDevice, level_three_press, FALSE, "temp level 3 shift");
  else if (level_three_release) {
    int index = 0;
    while (level_three_release[index])
      PressKey(kbdDevice, level_three_release[index++], TRUE,
               "temp level 3 shift");
    free(level_three_release);
  }

  /* Undo any fake shift */
  if (shift_press != 0)
    PressKey(kbdDevice, shift_press, FALSE, "temp shift");
  else if (shift_release) {
    int index = 0;
    while (shift_release[index])
      PressKey(kbdDevice, shift_release[index++], TRUE, "temp shift");
    free(shift_release);
  }

  /*
   * When faking a modifier we are putting a keycode (which can
   * currently activate the desired modifier) on the input
   * queue. A future modmap change can change the mapping so
   * that this keycode means something else entirely. Guard
   * against this by processing the queue now.
   */
  mieqProcessInputEvents();
}