| /******************************************************************************* |
| * Copyright (c) 2009 SWTBot Committers 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.FileWriter; |
| import java.io.IOException; |
| import java.math.BigInteger; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import org.eclipse.jface.bindings.keys.KeyStroke; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.layout.GridLayout; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.swt.widgets.Text; |
| import org.eclipse.swtbot.swt.finder.utils.SWTBotPreferenceConstants; |
| import org.eclipse.swtbot.swt.finder.utils.SWTUtils; |
| import org.eclipse.swtbot.swt.finder.widgets.SWTBotText; |
| |
| /** |
| * @author Ketan Padegaonkar <KetanPadegaonkar [at] gmail [dot] com> |
| * @version $Id$ |
| */ |
| public class KeyboardLayoutGenerator { |
| |
| private static Keyboard keyboard; |
| private static SWTBotText text; |
| private static FileWriter fileWriter; |
| private static CombinationGenerator<Integer> generator; |
| |
| public static void main(String[] args) { |
| System.setProperty(SWTBotPreferenceConstants.KEY_KEYBOARD_LAYOUT, "org.eclipse.swtbot.swt.finder.keyboard.empty"); |
| |
| Display display = new Display(); |
| keyboard = KeyboardFactory.getSWTKeyboard(); |
| Shell shell = new Shell(display); |
| shell.setLayout(new GridLayout(1, false)); |
| |
| final Text text = new Text(shell, SWT.MULTI | SWT.LEAD | SWT.BORDER); |
| text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); |
| |
| createGenerator(); |
| new Thread() { |
| @Override |
| public void run() { |
| SWTUtils.sleep(1000); |
| try { |
| typeKeystrokes(text); |
| } catch (IOException e) { |
| e.printStackTrace(); |
| throw new RuntimeException(e); |
| } finally { |
| System.exit(0); |
| } |
| }; |
| }.start(); |
| |
| shell.open(); |
| while (!shell.isDisposed()) { |
| if (!display.readAndDispatch()) |
| display.sleep(); |
| } |
| display.dispose(); |
| |
| } |
| |
| private static void typeKeystrokes(final Text text) throws IOException { |
| fileWriter = new FileWriter("keyboard.layout"); |
| KeyboardLayoutGenerator.text = new SWTBotText(text); |
| for (char c : Keys.getInputs()) { |
| combination(c); |
| } |
| |
| fileWriter.close(); |
| } |
| |
| private static void createGenerator() { |
| if (isMac()) { |
| generator = new CombinationGenerator<Integer>(4, SWT.ALT, SWT.SHIFT, SWT.CTRL, SWT.COMMAND); |
| } else { |
| generator = new CombinationGenerator<Integer>(3, SWT.ALT, SWT.SHIFT, SWT.CTRL); |
| } |
| } |
| |
| private static void combination(char ch) { |
| Iterator<List<Integer>> iterator = generator.iterator(); |
| while (iterator.hasNext()) { |
| List<Integer> combinationList = iterator.next(); |
| Integer[] combination = combinationList.toArray(new Integer[combinationList.size()]); |
| int modificationKeys = or(combination); |
| |
| KeyStroke[] keys; |
| try { |
| keys = Keystrokes.toKeys(modificationKeys, ch); |
| } catch (Exception e) { |
| // could not parse ch to a keystroke. |
| keys = new KeyStroke[] { KeyStroke.getInstance(0, ch) }; |
| } |
| if (filter(keys)) |
| continue; |
| text.setText("\n"); |
| text.setFocus(); |
| keyboard.pressShortcut(keys); |
| text.setFocus(); |
| text.setText(text.getText().trim() + " " + KeyStroke.getInstance(modificationKeys, ch)); |
| try { |
| fileWriter.write(text.getText()); |
| fileWriter.write('\n'); |
| } catch (IOException e) { |
| e.printStackTrace(); |
| throw new RuntimeException(e); |
| } |
| } |
| } |
| |
| private static boolean filter(KeyStroke[] keys) { |
| List<KeyStroke> list = Arrays.asList(keys); |
| |
| return // quit |
| list.equals(Arrays.asList(Keystrokes.toKeys(SWT.COMMAND, 'Q'))) |
| || list.equals(Arrays.asList(Keystrokes.toKeys(SWT.COMMAND, 'q'))) |
| // logout |
| || list.equals(Arrays.asList(Keystrokes.toKeys(SWT.COMMAND | SWT.ALT, 'Q'))) |
| || list.equals(Arrays.asList(Keystrokes.toKeys(SWT.COMMAND | SWT.ALT, 'q'))) |
| // minimize |
| || list.equals(Arrays.asList(Keystrokes.toKeys(SWT.COMMAND, 'm'))) |
| || list.equals(Arrays.asList(Keystrokes.toKeys(SWT.COMMAND, 'M'))) |
| // screenshot |
| || list.equals(Arrays.asList(Keystrokes.toKeys(SWT.COMMAND | SWT.SHIFT, '4'))) |
| || list.equals(Arrays.asList(Keystrokes.toKeys(SWT.COMMAND | SWT.CTRL | SWT.SHIFT, '4'))) |
| || list.equals(Arrays.asList(Keystrokes.toKeys(SWT.COMMAND | SWT.SHIFT, '3'))) |
| || list.equals(Arrays.asList(Keystrokes.toKeys(SWT.COMMAND | SWT.CTRL | SWT.SHIFT, '3'))) |
| // hide |
| || list.equals(Arrays.asList(Keystrokes.toKeys(SWT.COMMAND, 'h'))) |
| || list.equals(Arrays.asList(Keystrokes.toKeys(SWT.COMMAND, 'H'))) |
| // paste |
| || list.equals(Arrays.asList(Keystrokes.toKeys(SWT.COMMAND, 'v'))) |
| || list.equals(Arrays.asList(Keystrokes.toKeys(SWT.COMMAND, 'V'))) |
| || list.equals(Arrays.asList(Keystrokes.toKeys(SWT.CTRL, 'v'))) |
| || list.equals(Arrays.asList(Keystrokes.toKeys(SWT.CTRL, 'V'))) |
| // cut |
| || list.equals(Arrays.asList(Keystrokes.toKeys(SWT.COMMAND, 'x'))) |
| || list.equals(Arrays.asList(Keystrokes.toKeys(SWT.COMMAND, 'X'))) |
| || list.equals(Arrays.asList(Keystrokes.toKeys(SWT.CTRL, 'x'))) |
| || list.equals(Arrays.asList(Keystrokes.toKeys(SWT.CTRL, 'X'))) |
| // |
| ; |
| } |
| |
| private static boolean isMac() { |
| String swtPlatform = SWT.getPlatform(); |
| return ("carbon".equals(swtPlatform) || "cocoa".equals(swtPlatform)); |
| } |
| |
| private static int or(Integer[] combination) { |
| int or = 0; |
| for (Integer integer : combination) { |
| or |= integer; |
| } |
| return or; |
| } |
| |
| private static class CombinationGenerator<T> implements Iterable<List<T>> { |
| |
| private final int r; |
| private final T[] values; |
| private ArrayList<List<T>> result; |
| |
| /** |
| * @param r the number of elements in the combination |
| * @param values the values that should be combined. |
| */ |
| CombinationGenerator(int r, T... values) { |
| this.r = r; |
| this.values = values; |
| initialize(); |
| } |
| |
| private void initialize() { |
| result = new ArrayList<List<T>>(); |
| for (int i = 1; i <= r; i++) { |
| FixedSizeCombinationGenerator<T> combinationGenerator = new FixedSizeCombinationGenerator<T>(i, values); |
| for (List<T> list : combinationGenerator) { |
| result.add(list); |
| } |
| } |
| } |
| |
| public Iterator<List<T>> iterator() { |
| return result.iterator(); |
| } |
| |
| class FixedSizeCombinationGenerator<E> implements Iterator<List<E>>, Iterable<List<E>> { |
| private int[] a; |
| private int n; |
| private int r; |
| private BigInteger numLeft; |
| private BigInteger total; |
| private final E[] elements; |
| |
| FixedSizeCombinationGenerator(int r, E... elements) { |
| this.elements = elements; |
| int n = elements.length; |
| if (r > n) { |
| throw new IllegalArgumentException(); |
| } |
| if (n < 1) { |
| throw new IllegalArgumentException(); |
| } |
| this.n = n; |
| this.r = r; |
| a = new int[r]; |
| BigInteger nFact = getFactorial(n); |
| BigInteger rFact = getFactorial(r); |
| BigInteger nminusrFact = getFactorial(n - r); |
| total = nFact.divide(rFact.multiply(nminusrFact)); |
| reset(); |
| } |
| |
| public void reset() { |
| for (int i = 0; i < a.length; i++) { |
| a[i] = i; |
| } |
| numLeft = new BigInteger(total.toString()); |
| } |
| |
| private BigInteger getFactorial(int n) { |
| BigInteger fact = BigInteger.ONE; |
| for (int i = n; i > 1; i--) { |
| fact = fact.multiply(new BigInteger(Integer.toString(i))); |
| } |
| return fact; |
| } |
| |
| private int[] getIndices() { |
| if (numLeft.equals(total)) { |
| numLeft = numLeft.subtract(BigInteger.ONE); |
| return a; |
| } |
| |
| int i = r - 1; |
| while (a[i] == n - r + i) { |
| i--; |
| } |
| a[i] = a[i] + 1; |
| for (int j = i + 1; j < r; j++) { |
| a[j] = a[i] + j - i; |
| } |
| numLeft = numLeft.subtract(BigInteger.ONE); |
| return a; |
| } |
| |
| public boolean hasNext() { |
| return numLeft.compareTo(BigInteger.ZERO) == 1; |
| } |
| |
| public List<E> next() { |
| ArrayList<E> arrayList = new ArrayList<E>(); |
| int[] indices = getIndices(); |
| for (int i = 0; i < indices.length; i++) { |
| arrayList.add(elements[indices[i]]); |
| } |
| return arrayList; |
| } |
| |
| public void remove() { |
| throw new UnsupportedOperationException(); |
| } |
| |
| public Iterator<List<E>> iterator() { |
| return this; |
| } |
| } |
| |
| } |
| |
| } |