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)); } }
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; }