blob: 18afd41e26861fa18303e69b515f5cb08b8bb7b2 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009 Ketan Padegaonkar and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Ketan Padegaonkar - initial API and implementation
*******************************************************************************/
package org.eclipse.swtbot.swt.finder.keyboard;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.net.URL;
import org.eclipse.jface.bindings.keys.KeyStroke;
import org.eclipse.jface.bindings.keys.ParseException;
import org.eclipse.swt.SWT;
import org.eclipse.swtbot.swt.finder.utils.BidiMap;
import org.eclipse.swtbot.swt.finder.utils.FileUtils;
import org.eclipse.swtbot.swt.finder.utils.SWTBotPreferences;
/**
* Allows mapping of characters to {@link KeyStroke}s based on keyboard layouts.
*
* @author Ketan Padegaonkar <KetanPadegaonkar [at] gmail [dot] com>
* @version $Id$
*/
public class KeyboardLayout {
private final BidiMap<Character, KeyStroke> keyStrokes = new BidiMap<Character, KeyStroke>();
private final String layoutName;
private KeyboardLayout(String name, URL resource) throws IOException {
this.layoutName = name;
initialiseDefaults();
parseKeyStrokes(resource);
}
public String toString() {
return layoutName + " keyboard layout";
}
/**
* Returns the keystroke for typing the specified character.
* <p>
* E.g. 'T' will correspond to SHIFT+T. 't' will correspond to 'T'. '!' will correspond to SHIFT+1 on the US
* keyboard.
* </p>
*
* @param ch a character.
* @return the keystroke applicable corresponding to the character.
*/
public KeyStroke keyStrokeFor(char ch) {
KeyStroke keyStroke = keyStrokes.getValue(ch);
if (keyStroke != null) {
return keyStroke;
}
throw new IllegalArgumentException("no stroke available for character '" + ch + "'");
}
public char toCharacter(KeyStroke key) {
Character ch = keyStrokes.getKey(key);
if (ch == null)
ch = (char) key.getNaturalKey();
return ch;
}
/**
* @return the default keyboard layout.
* @see SWTBotPreferences#KEYBOARD_LAYOUT
*/
public static KeyboardLayout getDefaultKeyboardLayout() {
return getKeyboardLayout(SWTBotPreferences.KEYBOARD_LAYOUT);
}
/**
* @param layoutName the layout of the keyboard.
* @return the keyboard layout corresponding to the specified layout.
*/
public static KeyboardLayout getKeyboardLayout(String layoutName) {
ClassLoader classLoader = KeyboardLayout.class.getClassLoader();
URL configURL = classLoader.getResource(toFolder(myPackage() + "." + layoutName) + ".keyboard");
if (configURL == null)
configURL = classLoader.getResource(toFolder(layoutName) + ".keyboard");
if (configURL == null)
throw new IllegalArgumentException(layoutName + ".keyboard not found, see http://wiki.eclipse.org/SWTBot/Keyboard_Layouts for more information.");
try {
return new KeyboardLayout(layoutName, configURL);
} catch (IOException e) {
throw new IllegalStateException("could not parse " + layoutName + " keyboard layout properties");
}
}
private static String myPackage() {
return KeyboardLayout.class.getPackage().getName();
}
private static String toFolder(String layoutName) {
return layoutName.replaceAll("\\.", "/");
}
private void initialiseDefaults() {
for (char ch = '0'; ch <= '9'; ch++) {
keyStrokes.put(ch, KeyStroke.getInstance(0, ch));
}
for (char ch = 'A'; ch <= 'Z'; ch++) {
keyStrokes.put(Character.toLowerCase(ch), KeyStroke.getInstance(0, ch));
keyStrokes.put(ch, KeyStroke.getInstance(SWT.SHIFT, ch));
}
keyStrokes.put('\n', KeyStroke.getInstance(0, '\n'));
keyStrokes.put('\r', KeyStroke.getInstance(0, '\n'));
keyStrokes.put('\t', KeyStroke.getInstance(0, '\t'));
keyStrokes.put('\b', KeyStroke.getInstance(0, '\b'));
keyStrokes.put(' ', KeyStroke.getInstance(0, ' '));
}
private void parseKeyStrokes(URL resource) throws IOException {
String contents = FileUtils.read(resource);
BufferedReader in = new BufferedReader(new StringReader(contents));
parseKeyStrokes(in);
}
private void parseKeyStrokes(BufferedReader in) throws IOException {
String line;
while ((line = in.readLine()) != null) {
char ch = line.charAt(0);
String keyStrokeSpec = line.substring(2).replaceAll(" \\+ ", "+");
try {
keyStrokes.put(ch, KeyStroke.getInstance(keyStrokeSpec));
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
}
}