/** * MIT License * * Copyright (c) 2017 zgqq * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package mah.keybind; import com.tulskiy.keymaster.common.HotKeyListener; import com.tulskiy.keymaster.common.Provider; import mah.action.Action; import mah.action.ActionException; import mah.action.ActionManager; import mah.action.GlobalAction; import mah.app.ApplicationEvent; import mah.app.ApplicationListener; import mah.app.config.Config; import mah.app.config.XmlConfig; import mah.keybind.config.GlobalKeybindConfig; import mah.keybind.config.ModifierConfig; import mah.keybind.config.XmlGlobalKeybindParser; import mah.keybind.config.XmlModifierParser; import mah.keybind.listener.GlobalKeyEvent; import mah.keybind.listener.GlobalKeyListener; import mah.keybind.listener.GlobalKeybindListener; import mah.keybind.listener.KeyPressedHandler; import mah.keybind.util.SimpleParser; import mah.mode.Mode; import mah.mode.ModeManager; import mah.ui.layout.LayoutFactoryBean; import mah.ui.window.Window; import mah.ui.window.WindowManager; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import javax.swing.*; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingDeque; import java.util.concurrent.BlockingQueue; /** * Created by zgq on 2017-01-09 09:21 */ public class KeybindManager implements ApplicationListener, GlobalKeyListener { private final Map<String, List<Keybind>> keybinds = new HashMap<>(); private static final Logger LOGGER = LoggerFactory.getLogger(KeybindManager.class); private final List<Keybind> globalKeybinds = new ArrayList<>(); private Mode currentMode; private static final KeybindManager INSTANCE = new KeybindManager(); private final KeybindMatcher keybindMatcher = new KeybindMatcher(); private final GlobalKeybindListener globalListener = new GlobalKeybindListener(); public void addKeybind(String mod, Keybind keybind) { List<Keybind> keybindings = keybinds.get(mod); if (keybindings == null) { keybindings = new ArrayList<>(); keybinds.put(mod, keybindings); } keybindings.add(keybind); } public static KeybindManager getInstance() { return INSTANCE; } public void addGlobalKeybind(Keybind keybind) { globalKeybinds.add(keybind); } private void consumeKeystroke(KeyStroke keyStroke) { final Provider provider = Provider.getCurrentProvider(false); final HotKeyListener listener = hotKey -> { //do nothing }; provider.register(keyStroke, listener); } private void registerGlobalKeybinds(Document document) { XmlGlobalKeybindParser globalKeybindParser = new XmlGlobalKeybindParser(document); List<GlobalKeybindConfig> globalKeybindConfigs = globalKeybindParser.parseGlobalKeybinds(); globalKeybindConfigs.forEach(keybind -> { Keybind keybinding = new Keybind(); Action action = ModeManager.getInstance().findGlobalAction(keybind.getAction()); if (!(action instanceof GlobalAction)) { throw new ActionException("The action is not global mode " + keybind.getAction()); } keybinding.setAction(action); List<KeyStroke> keyStrokes = SimpleParser.parse(keybind.getListen()); List<KeyStroke> consumeKeyStrokes = SimpleParser.parse(keybind.getListen()); keybinding.setKeyStrokes(keyStrokes); KeybindManager.getInstance().addGlobalKeybind(keybinding); consumeKeystroke(consumeKeyStrokes.get(0)); }); } @Override public void start(ApplicationEvent event) { LayoutFactoryBean.getInstance().setOnKeyPressed(new KeyPressedHandler()); globalListener.addListener(this); final XmlModifierParser parser = new XmlModifierParser(((XmlConfig) event.getConfig()).getDocument()); globalListener.start(parser.parseModifiers()); } @Override public void afterStart(ApplicationEvent event) { Config config = event.getConfig(); if (config instanceof XmlConfig) { XmlConfig xmlConfig = (XmlConfig) config; registerGlobalKeybinds(xmlConfig.getDocument()); } } @Nullable private Action findAction(Mode mode, KeyStroke pressedKeyStroke) { List<Keybind> keybinds = this.keybinds.get(mode.getName()); if (keybinds != null) { Action action = keybindMatcher.addPendingKeybindIfNotFoundAction(keybinds, pressedKeyStroke); if (action != null) { return action; } } final List<Mode> children = mode.getChildren(); for (final Mode child : children) { Action action = findAction(child, pressedKeyStroke); if (action != null) { return action; } } return null; } @Nullable private Action findAction(KeyStroke pressedKeyStroke) { Action action; keybindMatcher.start(); if (keybindMatcher.isEmpty()) { action = findAction(currentMode, pressedKeyStroke); } else { action = keybindMatcher.continueMatch(pressedKeyStroke); } keybindMatcher.end(); return action; } @Nullable private Action findAction(List<Keybind> keybinds, KeyStroke pressedKeyStroke) { return keybindMatcher.addPendingKeybindIfNotFoundAction(keybinds, pressedKeyStroke); } public void setCurrentMode(Mode currentMode) { this.currentMode = currentMode; } public void tryExecuteAction(KeyStroke keyStroke) { Action action = findAction(keyStroke); if (action != null) { ActionManager.getInstance().handleAction(action); } } private Action findGlobalAction(KeyStroke pressedKeyStroke) { return findAction(globalKeybinds, pressedKeyStroke); } public void tryExecuteGlobalAction(KeyStroke keyStroke) { Action action = findGlobalAction(keyStroke); if (action != null) { ActionManager.getInstance().handleAction(action); } } public void addGlobalKeyListener(GlobalKeyListener globalKeyListener) { globalListener.addListener(globalKeyListener); } @Override public void keyPressed(GlobalKeyEvent keyEvent) { Window window = WindowManager.getInstance().getCurrentWindow(); if (window != null && window.isShowing() && window.isFocused()) { return; } KeybindManager.getInstance().tryExecuteGlobalAction(keyEvent.getKeyStroke()); } }