/******************************************************************************* * Copyright (c) 2012 Google, Inc. * 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: * Google, Inc. - initial API and implementation *******************************************************************************/ package com.windowtester.runtime.swt.internal.text; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.util.Locale; import javax.swing.KeyStroke; import org.eclipse.swt.SWT; import com.windowtester.internal.debug.Logger; import com.windowtester.runtime.IUIContext; import com.windowtester.runtime.swt.internal.selector.DisplayEventDispatcher; /** * Makes uses of the key maps for the various locales to support non US keyboard * text entry. * * KeyStrokeMap is used to get the mapping for the char according to locale */ public class KeyMapTextEntryStrategy implements ITextEntryStrategy { /** * Thrown when there is a key map file but there is no mapping for a * particular character. */ public static class UnMappedKeyException extends RuntimeException { private static final long serialVersionUID = 1L; public UnMappedKeyException(String msg) { super(msg); } } //TODO: this is used as a fallback ---> as soon as all of the methods use keymaps, remove private final ITextEntryStrategy defaultStrategy = new UIDriverTextEntryStrategy(); //a dispatcher for raw SWT events private final DisplayEventDispatcher dispatcher = new DisplayEventDispatcher(); /** * Enter text method that uses the key map * @param ui * @param txt */ public void enterText(IUIContext ui, String txt) { char[] ch = txt.toCharArray(); for (int i=0;i < ch.length;i++) { keyStroke(ch[i]); } } /** * using WT dispatcher to dispatch the key press and release events * @param ch */ public void keyStroke(char ch) { KeyStroke ks = KeyStrokeMap.getKeyStroke(ch); if (ks == null){ // use default mapping to get keystroke, for //a Japanese locale //System.out.println("Using default map for " + ch); ks = KeyStrokeMap.getDefaultKeyStroke(ch); } if (ks == null){ // still can't find a key stroke // throw UnMappedKeyException throw new UnMappedKeyException("Key map not found for " + ch + " for locale " + Locale.getDefault().toString()); } int keycode = ks.getKeyCode(); int mod = ks.getModifiers(); Logger.log("Char '" + ch + "' generated by keycode=" + keycode + " mod=" + mod); boolean isModifier = true; switch(keycode) { case KeyEvent.VK_ALT_GRAPH: mod |= InputEvent.ALT_GRAPH_MASK; break; case KeyEvent.VK_ALT: mod |= InputEvent.ALT_MASK; break; case KeyEvent.VK_SHIFT: mod |= InputEvent.SHIFT_MASK; break; case KeyEvent.VK_CONTROL: mod |= InputEvent.CTRL_MASK; break; case KeyEvent.VK_META: mod |= InputEvent.META_MASK;break; default: isModifier = false; break; } // check if accent key, if so press accent key int accentKeycode = KeyStrokeMap.getAccentKey(ch); if (accentKeycode != 0) accentCharKeyPress(mod,keycode,accentKeycode); else { setModifiers(mod, true); // press key if (!isModifier) { dispatcher.keyDown(ch); // for some reason $ becomes the +/- char on Mac, so see above dispatcher.keyUp(ch); } setModifiers(mod, false); } } /** Press or release the appropriate modifiers corresponding to the given mask. */ public void setModifiers(int modifiers, boolean press) { // boolean altGraph = (modifiers & InputEvent.ALT_GRAPH_MASK) != 0; boolean shift = (modifiers & InputEvent.SHIFT_MASK) != 0; boolean alt = (modifiers & InputEvent.ALT_MASK) != 0; boolean ctrl = (modifiers & InputEvent.CTRL_MASK) != 0; // boolean meta = (modifiers & InputEvent.META_MASK) != 0; if (press) { // if (altGraph) keyPress(KeyEvent.VK_ALT_GRAPH); if (alt) dispatcher.keyDown(SWT.ALT); if (shift) dispatcher.keyDown(SWT.SHIFT); if (ctrl) dispatcher.keyDown(SWT.CTRL); // if (meta) _dispatcher.keyDown(KeyEvent.VK_META); } else { // For consistency, release in the reverse order of press // if (meta) _dispatcher.keyUp(KeyEvent.VK_META); if (ctrl) dispatcher.keyUp(SWT.CTRL); if (shift) dispatcher.keyUp(SWT.SHIFT); if (alt) dispatcher.keyUp(SWT.ALT); //if (altGraph) _dispatcher.keyUp(KeyEvent.VK_ALT_GRAPH); } } /** * Enters the accent char - using 2 key presses, first the dead key and * then the vowel * @param keycode * @param accentCode */ private void accentCharKeyPress(int modifiers,int keycode, int accentCode){ char ch = 0; switch(keycode){ case 65: ch = 'a'; break; case 69: ch = 'e'; break; case 73: ch = 'i'; break; case 79: ch = 'o'; break; case 85: ch = 'u'; break; } // first press dead key pressDeadkey(accentCode); setModifiers(modifiers, true); dispatcher.keyDown(ch); dispatcher.keyUp(ch); setModifiers(modifiers, false); } /** * Press the appropriate accent key as specified in the code * @param code * 1 - circumflex ^ * 2 - umlaut * 3 - grave accent ` * 4 - acute accent * 5 - tilda ~ */ private void pressDeadkey(int code){ KeyStroke aks = null; char ch = 0; switch(code){ case 1: ch = '^'; aks = KeyStrokeMap.getKeyStroke(ch); break; case 2: ch = '�'; aks = KeyStrokeMap.getKeyStroke(ch); break; case 3: ch = '`'; aks = KeyStrokeMap.getKeyStroke(ch); break; case 4: ch = '�'; aks = KeyStrokeMap.getKeyStroke(ch); break; case 5: ch = '~'; aks = KeyStrokeMap.getKeyStroke(ch); break; } // if we have got the keystroke for the dead key, then press it if (aks != null){ //int keycode = aks.getKeyCode(); int mod = aks.getModifiers(); setModifiers(mod, true); dispatcher.keyDown(ch); dispatcher.keyUp(ch); setModifiers(mod, false); } } public void keyClick(IUIContext ui, int key) { // TODO implement this using the keymap defaultStrategy.keyClick(ui, key); } public void keyClick(IUIContext ui, char key) { // TODO implement this using the keymap defaultStrategy.keyClick(ui, key); } public void keyClick(IUIContext ui, int ctrl, char c) { // TODO implement this using the keymap defaultStrategy.keyClick(ui, ctrl, c); } public void keyDown(IUIContext ui, char key) { // TODO implement this using the keymap defaultStrategy.keyDown(ui, key); } public void keyDown(IUIContext ui, int key) { // TODO implement this using the keymap defaultStrategy.keyDown(ui, key); } public void keyUp(IUIContext ui, char key) { // TODO implement this using the keymap defaultStrategy.keyUp(ui, key); } public void keyUp(IUIContext ui, int key) { // TODO implement this using the keymap defaultStrategy.keyUp(ui, key); } }