/*
* sulky-modules - several general-purpose modules.
* Copyright (C) 2007-2014 Joern Huxhorn
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Copyright 2007-2014 Joern Huxhorn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.huxhorn.sulky.swing;
import java.awt.Event;
import java.awt.HeadlessException;
import java.awt.Toolkit;
import java.awt.event.InputEvent;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.KeyStroke;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class KeyStrokes
{
private static final Logger LOGGER = LoggerFactory.getLogger(KeyStrokes.class);
public static final String COMMAND_ALIAS = "command";
/**
* The string representation of the system-dependant command modifier.
*
* It is obtained by calling getModifiersString(Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()).
*/
public static final String COMMAND_MODIFIERS;
/**
* Contains Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()
*/
public static final int COMMAND_KEYMASK;
static
{
Toolkit toolkit = Toolkit.getDefaultToolkit();
int keyMask = Event.CTRL_MASK;
try
{
keyMask = toolkit.getMenuShortcutKeyMask();
}
catch(HeadlessException ignore)
{
if(LOGGER.isWarnEnabled()) LOGGER.warn("Failed to resolve MenuShortcutKeyMask. Falling back to 'control'.");
}
COMMAND_KEYMASK = keyMask;
COMMAND_MODIFIERS = getModifiersString(COMMAND_KEYMASK);
}
private KeyStrokes()
{}
/**
* Creates a string containing the text representation of the given modifiers.
* Calling this method with the value (InputEvent.SHIFT_MASK | InputEvent.CTRL_MASK)
* would return the string "shift control". Calling this method
* without any modifiers set in the modifiers will return an empty string.
* Calling it with all modifiers set will return "shift control meta alt altGraph".
*
* This method is only used to initialize the system-dependant COMMAND_MODIFIERS
* attribute but was left public because it can be quite handy for debugging.
*
* @param modifiers the modifiers that can be obtained by calling getModifiers() on any InputEvent.
* @return the string representation of the given modifiers.
* @see java.awt.event.InputEvent#getModifiers()
*/
public static String getModifiersString(int modifiers)
{
StringBuilder result = new StringBuilder();
if((modifiers & InputEvent.SHIFT_MASK) != 0)
{
result.append("shift");
}
if((modifiers & InputEvent.CTRL_MASK) != 0)
{
if(result.length() != 0)
{
result.append(" ");
}
result.append("control");
}
if((modifiers & InputEvent.META_MASK) != 0)
{
if(result.length() != 0)
{
result.append(" ");
}
result.append("meta");
}
if((modifiers & InputEvent.ALT_MASK) != 0)
{
if(result.length() != 0)
{
result.append(" ");
}
result.append("alt");
}
if((modifiers & InputEvent.ALT_GRAPH_MASK) != 0)
{
if(result.length() != 0)
{
result.append(" ");
}
result.append("altGraph");
}
return result.toString();
}
/**
* Shortcut for accel.replaceAll(COMMAND_ALIAS, COMMAND_MODIFIERS).
*
* @param accel the accelerator string to be processed.
* @return The accelerator with "command" replaced by the system command key, i.e. Ctrl on Windows, Cmd on Mac.
*/
public static String preprocessAccelerator(String accel)
{
return accel.replaceAll(COMMAND_ALIAS, COMMAND_MODIFIERS);
}
public static KeyStroke resolveAcceleratorKeyStroke(String keyStroke)
{
String preprocessedKeyStroke = preprocessAccelerator(keyStroke);
KeyStroke result = KeyStroke.getKeyStroke(preprocessedKeyStroke);
if(LOGGER.isDebugEnabled()) LOGGER.debug("keyStroke {} resolved to {} resulted in {}.", keyStroke, preprocessedKeyStroke, result);
return result;
}
public static void registerCommand(JComponent component, Action action, String commandName)
{
KeyStroke keyStroke = (KeyStroke) action.getValue(Action.ACCELERATOR_KEY);
if(keyStroke != null)
{
logInputMaps(component, "BEFORE");
InputMap inputMap = component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = component.getActionMap();
inputMap.put(keyStroke, commandName);
actionMap.put(commandName, action);
Object value;
inputMap = component.getInputMap(JComponent.WHEN_FOCUSED);
value = inputMap.get(keyStroke);
if(value != null)
{
inputMap.put(keyStroke, commandName);
}
inputMap = component.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
value = inputMap.get(keyStroke);
if(value != null)
{
inputMap.put(keyStroke, commandName);
}
logInputMaps(component, "AFTER");
}
}
private static void logInputMaps(JComponent component, String identifier)
{
if(LOGGER.isDebugEnabled())
{
StringBuilder buffer = new StringBuilder();
buffer.append("Component: ").append(component).append(":\n");
buffer.append("\t").append(identifier).append(":\n");
InputMap inputMap;
inputMap = component.getInputMap(JComponent.WHEN_FOCUSED);
appendInputMap(buffer, "WHEN_FOCUSED", inputMap);
inputMap = component.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
appendInputMap(buffer, "WHEN_ANCESTOR_OF_FOCUSED_COMPONENT", inputMap);
inputMap = component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
appendInputMap(buffer, "WHEN_IN_FOCUSED_WINDOW", inputMap);
LOGGER.debug(buffer.toString());
}
}
private static void appendInputMap(StringBuilder buffer, String mapName, InputMap inputMap)
{
buffer.append("\tmapName: ").append(mapName).append("\n");
KeyStroke[] keys = inputMap.allKeys();
if(keys != null)
{
for(KeyStroke ks : keys)
{
buffer.append("\t\tKey : ").append(ks).append("\n");
buffer.append("\t\tValue: ").append(inputMap.get(ks)).append("\n");
buffer.append("\t\t----------\n");
}
}
}
}