예제 #1
0
TEST(Flags, remove) {
  {
    Flags flags = ModifierFlag::SHIFT_L | ModifierFlag::CONTROL_R | ModifierFlag::COMMAND_R;
    Flags removed = ModifierFlag::CONTROL_R | ModifierFlag::COMMAND_R;
    EXPECT_EQ(removed, flags.remove(ModifierFlag::SHIFT_L));
  }
  {
    Flags flags = ModifierFlag::SHIFT_L | ModifierFlag::SHIFT_R | ModifierFlag::CURSOR | ModifierFlag::EXTRA2 | ModifierFlag::NONE;
    Flags removed = ModifierFlag::SHIFT_R | ModifierFlag::CURSOR | ModifierFlag::EXTRA2 | ModifierFlag::NONE;
    EXPECT_EQ(removed, flags.remove(ModifierFlag::SHIFT_L));

    removed = ModifierFlag::SHIFT_R | ModifierFlag::NONE;
    EXPECT_EQ(removed, flags.remove(ModifierFlag::CURSOR | ModifierFlag::EXTRA2));

    removed = 0;
    EXPECT_EQ(removed, flags.remove(ModifierFlag::SHIFT_R | ModifierFlag::NONE));

    removed = 0;
    EXPECT_EQ(removed, flags.remove(ModifierFlag::OPTION_L | ModifierFlag::COMMAND_R));
  }
  {
    // chain
    Flags flags = ModifierFlag::SHIFT_L | ModifierFlag::SHIFT_R | ModifierFlag::CONTROL_R | ModifierFlag::COMMAND_R;
    Flags removed = ModifierFlag::CONTROL_R | ModifierFlag::COMMAND_R;
    EXPECT_EQ(removed, flags.remove(ModifierFlag::SHIFT_L).remove(ModifierFlag::SHIFT_R));
  }
}
예제 #2
0
    bool
    KeyToKey::remap(RemapParams& remapParams)
    {
      if (remapParams.isremapped) return false;
      if (! fromkeychecker_.isFromKey(remapParams.params.ex_iskeydown, remapParams.params.key, FlagStatus::makeFlags(), fromKey_.key, fromKey_.flags)) return false;
      remapParams.isremapped = true;

      // ------------------------------------------------------------
      // handle EventType & Modifiers

      // Let's consider the following setting.
      //   __KeyToKey__ KeyCode::SHIFT_R, ModifierFlag::SHIFT_R | ModifierFlag::NONE, KeyCode::A, ModifierFlag::SHIFT_R
      // In this setting, we need decrease SHIFT_R only once.
      // So, we transform values of fromKey_.
      //
      // [before]
      //   fromKey_.key   : KeyCode::SHIFT_R
      //   fromKey_.flags : ModifierFlag::SHIFT_R | ModifierFlag::NONE
      //
      // [after]
      //   fromKey_.key   : KeyCode::SHIFT_R
      //   fromKey_.flags : ModifierFlag::NONE
      //
      // Note: we need to apply this transformation after calling fromkeychecker_.isFromKey.

      Flags fromFlags = fromKey_.flags;
      fromFlags.remove(fromKey_.key.getModifierFlag());

      if (remapParams.params.ex_iskeydown) {
        retractInput();
      } else {
        restoreInput();
      }

      // ----------------------------------------
      // Handle beforeKeys_
      if (remapParams.params.ex_iskeydown) {
        FlagStatus::temporary_decrease(fromFlags);

        for (size_t i = 0; i < beforeKeys_.size(); ++i) {
          FlagStatus::temporary_increase(beforeKeys_[i].flags);

          Flags f = FlagStatus::makeFlags();
          KeyboardType keyboardType = remapParams.params.keyboardType;

          EventOutputQueue::FireKey::fire_downup(f, beforeKeys_[i].key, keyboardType);

          FlagStatus::temporary_decrease(beforeKeys_[i].flags);
        }

        FlagStatus::temporary_increase(fromFlags);
      }

      // ----------------------------------------
      // Handle toKeys_
      switch (toKeys_.size()) {
        case 0:
          break;

        case 1:
        {
          EventType newEventType = remapParams.params.ex_iskeydown ? EventType::DOWN : EventType::UP;
          KeyCode toKey = toKeys_[0].key;
          ModifierFlag toModifierFlag = toKey.getModifierFlag();

          if (toModifierFlag == ModifierFlag::NONE && ! VirtualKey::isKeyLikeModifier(toKey)) {
            // toKey
            FlagStatus::temporary_decrease(fromFlags);
            FlagStatus::temporary_increase(toKeys_[0].flags);

          } else {
            // toModifier or VirtualKey::isKeyLikeModifier
            if (toModifierFlag != ModifierFlag::NONE) {
              newEventType = EventType::MODIFY;
            }

            if (remapParams.params.ex_iskeydown) {
              FlagStatus::increase(toKeys_[0].flags | toModifierFlag);
              FlagStatus::decrease(fromFlags);
            } else {
              FlagStatus::decrease(toKeys_[0].flags | toModifierFlag);
              FlagStatus::increase(fromFlags);
            }
          }

          // ----------------------------------------
          Params_KeyboardEventCallBack::auto_ptr ptr(Params_KeyboardEventCallBack::alloc(newEventType,
                                                                                         FlagStatus::makeFlags(),
                                                                                         toKey,
                                                                                         remapParams.params.keyboardType,
                                                                                         remapParams.params.repeat));
          if (! ptr) return false;
          Params_KeyboardEventCallBack& params = *ptr;

          if (remapParams.params.ex_iskeydown && ! isRepeatEnabled_) {
            KeyboardRepeat::cancel();
          } else {
            KeyboardRepeat::set(params);
          }
          EventOutputQueue::FireKey::fire(params);

          break;
        }

        default:
          KeyCode lastKey                  = toKeys_[toKeys_.size() - 1].key;
          Flags lastKeyFlags               = toKeys_[toKeys_.size() - 1].flags;
          ModifierFlag lastKeyModifierFlag = lastKey.getModifierFlag();
          bool isLastKeyModifier           = (lastKeyModifierFlag != ModifierFlag::NONE);
          bool isLastKeyLikeModifier       = VirtualKey::isKeyLikeModifier(lastKey);

          if (remapParams.params.ex_iskeydown) {
            KeyboardRepeat::cancel();

            FlagStatus::temporary_decrease(fromFlags);

            size_t size = toKeys_.size();
            // If the last key is modifier, we give it special treatment.
            // - Don't fire key repeat.
            // - Synchronous the key press status and the last modifier status.
            if (isLastKeyModifier || isLastKeyLikeModifier) {
              --size;
            }

            for (size_t i = 0; i < size; ++i) {
              FlagStatus::temporary_increase(toKeys_[i].flags);

              Flags f = FlagStatus::makeFlags();
              KeyboardType keyboardType = remapParams.params.keyboardType;

              EventOutputQueue::FireKey::fire_downup(f, toKeys_[i].key, keyboardType);
              KeyboardRepeat::primitive_add_downup(f, toKeys_[i].key, keyboardType);

              FlagStatus::temporary_decrease(toKeys_[i].flags);
            }

            if (isLastKeyModifier || isLastKeyLikeModifier) {
              // restore temporary flag.
              FlagStatus::temporary_increase(fromFlags);

              FlagStatus::increase(lastKeyFlags | lastKeyModifierFlag);
              FlagStatus::decrease(fromFlags);

              if (isLastKeyLikeModifier) {
                // Don't call EventOutputQueue::FireModifiers::fire here.
                //
                // Intentionally VK_LAZY_* stop sending MODIFY events.
                // EventOutputQueue::FireModifiers::fire destroys this behavior.
                Params_KeyboardEventCallBack::auto_ptr ptr(Params_KeyboardEventCallBack::alloc(EventType::DOWN, FlagStatus::makeFlags(), lastKey, remapParams.params.keyboardType, false));
                if (ptr) {
                  EventOutputQueue::FireKey::fire(*ptr);
                }
              } else {
                EventOutputQueue::FireModifiers::fire();
              }
            }

            if (isLastKeyModifier || isLastKeyLikeModifier) {
              KeyboardRepeat::cancel();
            } else {
              if (isRepeatEnabled_) {
                keyboardRepeatID_ = KeyboardRepeat::primitive_start();
              } else {
                keyboardRepeatID_ = -1;
              }
            }

          } else {
            if (isLastKeyModifier || isLastKeyLikeModifier) {
              // For Lazy-Modifiers (KeyCode::VK_LAZY_*),
              // we need to handle these keys before restoring fromFlags, lastKeyFlags and lastKeyModifierFlag.
              // The unnecessary modifier events occur unless we do it.
              if (isLastKeyLikeModifier) {
                Params_KeyboardEventCallBack::auto_ptr ptr(Params_KeyboardEventCallBack::alloc(EventType::UP, FlagStatus::makeFlags(), lastKey, remapParams.params.keyboardType, false));
                if (ptr) {
                  EventOutputQueue::FireKey::fire(*ptr);
                }
              }

              FlagStatus::decrease(lastKeyFlags | lastKeyModifierFlag);
              FlagStatus::increase(fromFlags);
              EventOutputQueue::FireModifiers::fire();

            } else {
              if (KeyboardRepeat::getID() == keyboardRepeatID_) {
                KeyboardRepeat::cancel();
              }
            }
          }
          break;
      }

      // ----------------------------------------
      // Handle afterKeys_
      if (! remapParams.params.ex_iskeydown) {
        // We need to keep temporary flags for "general.lazy_modifiers_with_mouse_event" when afterKeys_ is empty.
        if (afterKeys_.size() > 0) {
          // clear temporary flags.
          FlagStatus::set();

          FlagStatus::temporary_decrease(fromFlags);

          for (size_t i = 0; i < afterKeys_.size(); ++i) {
            FlagStatus::temporary_increase(afterKeys_[i].flags);

            Flags f = FlagStatus::makeFlags();
            KeyboardType keyboardType = remapParams.params.keyboardType;

            EventOutputQueue::FireKey::fire_downup(f, afterKeys_[i].key, keyboardType);

            FlagStatus::temporary_decrease(afterKeys_[i].flags);
          }

          FlagStatus::temporary_increase(fromFlags);
        }
      }

      return true;
    }