blob: d9a6ecefcbe9b8b32a899a118f521faa0d770630 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2005 IBM Corporation 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.ui.tests.navigator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
/**
* @since 3.1
*/
public class KeyboardProbe {
private static final boolean TRACE= false;
private static final char FAKE_CHAR= '$';
public static void main(String[] args) {
new KeyboardProbe().getKeycodes();
}
private Display fDisplay;
private char[][] fCodes= null;
private int fKeyCode;
private static final int NONE= 0;
private static final int SHIFT= 1;
private boolean fKeyContinue;
private boolean fTextContinue;
private boolean fDisposeDisplay= false;
private Shell fShell;
/**
* Returns the characters being input into a text component by injecting key
* events into the system event queue. For each character, the array holds
* the resulting character when pressed alone and when pressed together with
* shift.
*
* @return the characters input by pressing the keys. The key code is the
* index into the array.
*/
public synchronized char[][] getKeycodes() {
initialize();
return fCodes;
}
/**
* Initializes this keyboard probe.
*/
public void initialize() {
if (fCodes == null) {
try {
probe();
} finally {
if (fDisposeDisplay && fDisplay != null) {
fDisplay.dispose();
}
fDisplay= null;
if (fShell != null && !fShell.isDisposed()) {
fShell.dispose();
}
fShell= null;
}
}
}
/**
* Returns the character resulting from pressing the character 'key' with
* or without shift being pressed.
*
* @param key the key to press
* @param pressShift whether pressed together with shift
* @return the char resulting from the given key combo, or 0 if there is no equivalent
*/
public char getCharForKeybinding(char key, boolean pressShift) {
char[][] keycodes= getKeycodes();
if (key < keycodes.length)
return keycodes[key][pressShift ? SHIFT : NONE];
return 0;
}
/**
* Returns a keybinding combo that will produce the wanted character. Note
* that there may be more than one combo that can produce the wanted
* binding, any one is returned. The last integer in the returned array is
* a character that must be set to the Event.character field, any integers
* before are SWT constants describing modifier keys that must be pressed
* to get the desired result.
*
* @param expected the char to be input
* @return the corresponding key combo, or an empty array if there is no combo
*/
public int[] getKeybindingForChar(char expected) {
char[][] keycodes= getKeycodes();
for (int i= 0; i < keycodes.length; i++) {
if (keycodes[i][NONE] == expected)
return new int[] {i};
else if (keycodes[i][SHIFT] == expected)
return new int[] { SWT.SHIFT, i };
}
return new int[0];
}
/**
* Presses a key combination such that the expected character is input by
* simulating key events on the given display. Returns <code>true</code>
* if a key combo could be found, <code>false</code> if not.
*
* @param expected the expected character
* @param display the display to simulate the events on
* @return <code>true</code> if there was a key combo to press,
* <code>false</code> if <code>expected</code> has no combo on
* the current keyboard layout.
*/
public boolean pressChar(char expected, Display display) {
return pressChar(expected, new int[0], display);
}
/**
* Presses a key combination such that the expected character is input by
* simulating key events on the given display. Returns <code>true</code>
* if a key combo could be found, <code>false</code> if not.
*
* @param expected the expected character
* @param modifiers additional modifiers to press
* @param display the display to simulate the events on
* @return <code>true</code> if there was a key combo to press,
* <code>false</code> if <code>expected</code> has no combo on
* the current keyboard layout.
*/
public boolean pressChar(char expected, int[] modifiers, Display display) {
int[] charkeys= getKeybindingForChar(expected);
int[] combo= new int[charkeys.length + modifiers.length];
System.arraycopy(modifiers, 0, combo, 0, modifiers.length);
System.arraycopy(charkeys, 0, combo, modifiers.length, charkeys.length);
for (int i= 0; i <= combo.length - 2; i++) {
Event event= new Event();
event.type= SWT.KeyDown;
event.keyCode= combo[i];
display.post(event);
}
if (combo.length > 0) {
Event event= new Event();
event.type= SWT.KeyDown;
event.character= (char) combo[combo.length - 1];
display.post(event);
event.type= SWT.KeyUp;
display.post(event);
}
for (int i= combo.length - 2; i >= 0; i--) {
Event event= new Event();
event.type= SWT.KeyUp;
event.keyCode= combo[i];
display.post(event);
}
return combo.length > 0;
}
void probe() {
fCodes= new char[128][];
fDisplay= createDisplay();
Text text= createControl(fDisplay);
for (fKeyCode= 0; fKeyCode < 128; fKeyCode++) {
fCodes[fKeyCode]= new char[2];
postNaturalKeyPress(fKeyCode);
char c= getContent(text);
if (TRACE) System.out.println("" + fKeyCode + "content[NONE]: " + c); //$NON-NLS-1$ //$NON-NLS-2$
fCodes[fKeyCode][NONE]= c;
clearText(text);
postShiftKeyPress(fKeyCode);
c= getContent(text);
if (TRACE) System.out.println("" + fKeyCode + "content[SHIFT]: " + c); //$NON-NLS-1$ //$NON-NLS-2$
fCodes[fKeyCode][SHIFT]= c;
clearText(text);
}
}
private char getContent(Text text) {
String content= text.getText();
char c;
if (content.length() == 2) {
c= content.charAt(0);
if (TRACE && content.charAt(1) != FAKE_CHAR)
System.out.println("second char was '" + content.charAt(1) + "'"); //$NON-NLS-1$ //$NON-NLS-2$
} else if (content.length() > 2) {
c= content.charAt(0);
if (TRACE) System.out.println("rest content was '" + content.substring(1) + "'"); //$NON-NLS-1$ //$NON-NLS-2$
} else if (content.length() == 1) {
c= '\0';
if (TRACE && content.charAt(0) != FAKE_CHAR)
System.out.println("second char was '" + content.charAt(0) + "'"); //$NON-NLS-1$ //$NON-NLS-2$
} else {
c= '\0';
if (TRACE) System.out.println("no content"); //$NON-NLS-1$
}
return c;
}
private void clearText(Text text) {
fTextContinue= false;
text.setText(""); //$NON-NLS-1$
do
driveEventQueue();
while (!fTextContinue && fDisplay.sleep());
}
private Display createDisplay() {
Display display= Display.getCurrent();
if (display == null) {
display= Display.getDefault();
fDisposeDisplay= true;
}
return display;
}
private void addListeners(Text control) {
control.addListener(SWT.KeyDown, new Listener() {
public void handleEvent(Event event) {
onKeyDown(event);
}
});
control.addListener(SWT.KeyUp, new Listener() {
public void handleEvent(Event event) {
onKeyUp(event);
}
});
control.addListener(SWT.Modify, new Listener() {
public void handleEvent(Event event) {
onModify(event);
}
});
}
private Text createControl(Display display) {
fShell= new Shell(display);
fShell.setSize(300, 200);
fShell.setText("Keyboard Probe"); //$NON-NLS-1$
fShell.setLayout(new FillLayout());
Text text= new Text(fShell, SWT.MULTI | SWT.LEFT | SWT.WRAP);
text.setSize(300, 200);
fShell.setVisible(true);
fShell.forceActive();
fShell.forceFocus();
addListeners(text);
text.setFocus();
return text;
}
private void postNaturalKeyPress(int i) {
fKeyContinue= false;
Event event= new Event();
event.type= SWT.KeyDown;
event.keyCode= i;
event.character= (char) i;
fDisplay.post(event);
event.type= SWT.KeyUp;
fDisplay.post(event);
Event event2= new Event();
event2.type= SWT.KeyDown;
// event2.keyCode= i;
event2.character= FAKE_CHAR;
fDisplay.post(event2);
event2.type= SWT.KeyUp;
fDisplay.post(event2);
do
driveEventQueue();
while (!fKeyContinue && fDisplay.sleep());
}
private void postShiftKeyPress(int i) {
fKeyContinue= false;
Event shift= new Event();
shift.type= SWT.KeyDown;
shift.keyCode= SWT.SHIFT;
fDisplay.post(shift);
Event event= new Event();
event.type= SWT.KeyDown;
event.character= (char) i;
fDisplay.post(event);
event.type= SWT.KeyUp;
fDisplay.post(event);
shift.type= SWT.KeyUp;
fDisplay.post(shift);
Event event2= new Event();
event2.type= SWT.KeyDown;
event2.character= FAKE_CHAR;
fDisplay.post(event2);
event2.type= SWT.KeyUp;
fDisplay.post(event2);
do
driveEventQueue();
while (!fKeyContinue && fDisplay.sleep());
}
private boolean fShiftPressed= false;
private void onKeyDown(Event event) {
if (event.keyCode == SWT.SHIFT)
fShiftPressed= true;
}
private void onKeyUp(Event event) {
if (!fShiftPressed || event.keyCode == SWT.SHIFT)
fKeyContinue= true;
fShiftPressed= false;
}
private void onModify(Event event) {
fTextContinue= true;
}
private void driveEventQueue() {
while (fDisplay.readAndDispatch()) {}
}
}