/* * #%L * SciJava Common shared library for SciJava software. * %% * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * #L% */ package org.scijava.input; import java.util.regex.Pattern; import org.scijava.util.PlatformUtils; /** * A keyboard shortcut, consisting of a {@link KeyCode} plus * {@link InputModifiers}. * * @author Curtis Rueden * @author Barry DeZonia */ public class Accelerator { /** Actual key pressed. */ private final KeyCode keyCode; /** Key modifiers used. */ private final InputModifiers modifiers; public Accelerator(final KeyCode keyCode, final InputModifiers modifiers) { this.keyCode = keyCode; this.modifiers = modifiers; } // -- Accelerator methods -- public KeyCode getKeyCode() { return keyCode; } public InputModifiers getModifiers() { return modifiers; } // -- Object methods -- @Override public boolean equals(final Object o) { if (!(o instanceof Accelerator)) return false; final Accelerator acc = (Accelerator) o; if (!getModifiers().equals(acc.getModifiers())) return false; if (!getKeyCode().equals(acc.getKeyCode())) return false; return true; } @Override public int hashCode() { return toString().hashCode(); } @Override public String toString() { final String modString = modifiers.toString(); final String keyString = keyCode.name(); if (modString.length() == 0) return keyString; return modString + " " + keyString; } // -- Utility methods -- /** * Creates an accelerator from the given string representation. The string * must have the following syntax: * *
	 * 	    <modifiers>* <keyCode>
	 * 
	 * 	    modifiers := alt | altGraph | control | meta | shift
	 * 	    keyCode := {@link KeyCode} field (e.g., COMMA or UP)
	 * 
* * For convenience: * * Here are some example strings: * * * @see javax.swing.KeyStroke#getKeyStroke(String) for the syntax from which * this one is derived. * @see KeyCode for the complete list of special character codes. */ public static Accelerator create(final String acc) { if (acc == null || acc.isEmpty()) return null; // allow use of caret for control/command // (e.g., "^X" to mean "control X" or "meta X") final String a = acc.replaceAll(Pattern.quote("^"), expandedCaret()); final String[] components = a.split(" "); // determine which modifiers are used boolean alt = false, altGr = false; boolean ctrl = false, meta = false, shift = false; for (int i = 0; i < components.length - 1; i++) { if (components[i].equalsIgnoreCase("alt")) alt = true; else if (components[i].equalsIgnoreCase("altGr") || components[i].equalsIgnoreCase("altGraph")) { altGr = true; } else if (components[i].equalsIgnoreCase("control") || components[i].equalsIgnoreCase("ctrl")) { ctrl = true; } else if (components[i].equalsIgnoreCase("meta")) meta = true; else if (components[i].equalsIgnoreCase("shift")) shift = true; } final InputModifiers modifiers = new InputModifiers(alt, altGr, ctrl, meta, shift, false, false, false); // upper case the key code final String code = components[components.length - 1].toUpperCase(); final KeyCode keyCode = KeyCode.get(code); return new Accelerator(keyCode, modifiers); } public static boolean isCtrlReplacedWithMeta() { // FIXME: Relocate this platform-specific logic. return PlatformUtils.isMac(); } // -- Helper methods -- private static String expandedCaret() { return isCtrlReplacedWithMeta() ? "meta " : "control "; } }