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