/******************************************************************************* * Copyright (c) 2011, 2015 EclipseSource 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: * EclipseSource - initial API and implementation ******************************************************************************/ package org.eclipse.rap.rwt.internal.util; import static org.eclipse.rap.rwt.internal.protocol.RemoteObjectFactory.getRemoteObject; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import org.eclipse.rap.json.JsonArray; import org.eclipse.rap.rwt.RWT; import org.eclipse.rap.rwt.internal.lifecycle.DisplayUtil; import org.eclipse.rap.rwt.internal.lifecycle.RemoteAdapter; import org.eclipse.rap.rwt.internal.lifecycle.WidgetUtil; import org.eclipse.swt.internal.widgets.ControlRemoteAdapter; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; public final class ActiveKeysUtil { private static final Map<String,Integer> KEY_MAP = new HashMap<>(); static { KEY_MAP.put( "BACKSPACE", Integer.valueOf( 8 ) ); KEY_MAP.put( "BS", Integer.valueOf( 8 ) ); KEY_MAP.put( "TAB", Integer.valueOf( 9 ) ); KEY_MAP.put( "RETURN", Integer.valueOf( 13 ) ); KEY_MAP.put( "ENTER", Integer.valueOf( 13 ) ); KEY_MAP.put( "CR", Integer.valueOf( 13 ) ); KEY_MAP.put( "PAUSE", Integer.valueOf( 19 ) ); KEY_MAP.put( "BREAK", Integer.valueOf( 19 ) ); KEY_MAP.put( "CAPS_LOCK", Integer.valueOf( 20 ) ); KEY_MAP.put( "ESCAPE", Integer.valueOf( 27 ) ); KEY_MAP.put( "ESC", Integer.valueOf( 27 ) ); KEY_MAP.put( "SPACE", Integer.valueOf( 32 ) ); KEY_MAP.put( "PAGE_UP", Integer.valueOf( 33 ) ); KEY_MAP.put( "PAGE_DOWN", Integer.valueOf( 34 ) ); KEY_MAP.put( "END", Integer.valueOf( 35 ) ); KEY_MAP.put( "HOME", Integer.valueOf( 36 ) ); KEY_MAP.put( "ARROW_LEFT", Integer.valueOf( 37 ) ); KEY_MAP.put( "ARROW_UP", Integer.valueOf( 38 ) ); KEY_MAP.put( "ARROW_RIGHT", Integer.valueOf( 39 ) ); KEY_MAP.put( "ARROW_DOWN", Integer.valueOf( 40 ) ); KEY_MAP.put( "PRINT_SCREEN", Integer.valueOf( 44 ) ); KEY_MAP.put( "INSERT", Integer.valueOf( 45 ) ); KEY_MAP.put( "DEL", Integer.valueOf( 46 ) ); KEY_MAP.put( "DELETE", Integer.valueOf( 46 ) ); KEY_MAP.put( "F1", Integer.valueOf( 112 ) ); KEY_MAP.put( "F2", Integer.valueOf( 113 ) ); KEY_MAP.put( "F3", Integer.valueOf( 114 ) ); KEY_MAP.put( "F4", Integer.valueOf( 115 ) ); KEY_MAP.put( "F5", Integer.valueOf( 116 ) ); KEY_MAP.put( "F6", Integer.valueOf( 117 ) ); KEY_MAP.put( "F7", Integer.valueOf( 118 ) ); KEY_MAP.put( "F8", Integer.valueOf( 119 ) ); KEY_MAP.put( "F9", Integer.valueOf( 120 ) ); KEY_MAP.put( "F10", Integer.valueOf( 121 ) ); KEY_MAP.put( "F11", Integer.valueOf( 122 ) ); KEY_MAP.put( "F12", Integer.valueOf( 123 ) ); KEY_MAP.put( "NUMPAD_0", Integer.valueOf( 96 ) ); KEY_MAP.put( "NUMPAD_1", Integer.valueOf( 97 ) ); KEY_MAP.put( "NUMPAD_2", Integer.valueOf( 98 ) ); KEY_MAP.put( "NUMPAD_3", Integer.valueOf( 99 ) ); KEY_MAP.put( "NUMPAD_4", Integer.valueOf( 100 ) ); KEY_MAP.put( "NUMPAD_5", Integer.valueOf( 101 ) ); KEY_MAP.put( "NUMPAD_6", Integer.valueOf( 102 ) ); KEY_MAP.put( "NUMPAD_7", Integer.valueOf( 103 ) ); KEY_MAP.put( "NUMPAD_8", Integer.valueOf( 104 ) ); KEY_MAP.put( "NUMPAD_9", Integer.valueOf( 105 ) ); KEY_MAP.put( "NUMPAD_MULTIPLY", Integer.valueOf( 106 ) ); KEY_MAP.put( "NUMPAD_ADD", Integer.valueOf( 107 ) ); KEY_MAP.put( "NUMPAD_SUBTRACT", Integer.valueOf( 109 ) ); KEY_MAP.put( "NUMPAD_DECIMAL", Integer.valueOf( 110 ) ); KEY_MAP.put( "NUMPAD_DIVIDE", Integer.valueOf( 111 ) ); KEY_MAP.put( "NUM_LOCK", Integer.valueOf( 144 ) ); KEY_MAP.put( "SCROLL_LOCK", Integer.valueOf( 145 ) ); } private final static String ALT = "ALT+"; private final static String CTRL = "CTRL+"; private final static String SHIFT = "SHIFT+"; final static String PROP_ACTIVE_KEYS = "activeKeys"; final static String PROP_CANCEL_KEYS = "cancelKeys"; final static String PROP_MNEMONIC_ACTIVATOR = "mnemonicActivator"; private ActiveKeysUtil() { // prevent instantiation } public static void preserveActiveKeys( Display display ) { RemoteAdapter adapter = DisplayUtil.getAdapter( display ); adapter.preserve( PROP_ACTIVE_KEYS, getActiveKeys( display ) ); } public static void preserveActiveKeys( Control control ) { ControlRemoteAdapter adapter = ( ControlRemoteAdapter )WidgetUtil.getAdapter( control ); if( !adapter.hasPreservedActiveKeys() ) { adapter.preserveActiveKeys( getActiveKeys( control ) ); } } public static void preserveCancelKeys( Display display ) { RemoteAdapter adapter = DisplayUtil.getAdapter( display ); adapter.preserve( PROP_CANCEL_KEYS, getCancelKeys( display ) ); } public static void preserveCancelKeys( Control control ) { ControlRemoteAdapter adapter = ( ControlRemoteAdapter )WidgetUtil.getAdapter( control ); if( !adapter.hasPreservedCancelKeys() ) { adapter.preserveCancelKeys( getCancelKeys( control ) ); } } public static void renderActiveKeys( Display display ) { if( !display.isDisposed() ) { RemoteAdapter adapter = DisplayUtil.getAdapter( display ); String[] actual = getActiveKeys( display ); String[] preserved = ( String[] )adapter.getPreserved( PROP_ACTIVE_KEYS ); if( !Arrays.equals( actual, preserved ) ) { getRemoteObject( display ).set( PROP_ACTIVE_KEYS, translateKeySequences( actual ) ); } } } public static void renderActiveKeys( Control control ) { if( !control.isDisposed() ) { ControlRemoteAdapter adapter = ( ControlRemoteAdapter )WidgetUtil.getAdapter( control ); if( adapter.hasPreservedActiveKeys() ) { String[] actual = getActiveKeys( control ); String[] preserved = adapter.getPreservedActiveKeys(); if( !Arrays.equals( actual, preserved ) ) { getRemoteObject( control ).set( PROP_ACTIVE_KEYS, translateKeySequences( actual ) ); } } } } public static void renderCancelKeys( Display display ) { if( !display.isDisposed() ) { RemoteAdapter adapter = DisplayUtil.getAdapter( display ); String[] actual = getCancelKeys( display ); String[] preserved = ( String[] )adapter.getPreserved( PROP_CANCEL_KEYS ); if( !Arrays.equals( actual, preserved ) ) { getRemoteObject( display ).set( PROP_CANCEL_KEYS, translateKeySequences( actual ) ); } } } public static void renderCancelKeys( Control control ) { if( !control.isDisposed() ) { ControlRemoteAdapter adapter = ( ControlRemoteAdapter )WidgetUtil.getAdapter( control ); if( adapter.hasPreservedCancelKeys() ) { String[] actual = getCancelKeys( control ); String[] preserved = adapter.getPreservedCancelKeys(); if( !Arrays.equals( actual, preserved ) ) { getRemoteObject( control ).set( PROP_CANCEL_KEYS, translateKeySequences( actual ) ); } } } } public static void preserveMnemonicActivator( Display display ) { RemoteAdapter adapter = DisplayUtil.getAdapter( display ); adapter.preserve( PROP_MNEMONIC_ACTIVATOR, getMnemonicActivator( display ) ); } public static void renderMnemonicActivator( Display display ) { if( !display.isDisposed() ) { RemoteAdapter adapter = DisplayUtil.getAdapter( display ); String actual = getMnemonicActivator( display ); String preserved = ( String )adapter.getPreserved( PROP_MNEMONIC_ACTIVATOR ); if( !equals( actual, preserved ) ) { getRemoteObject( display ).set( PROP_MNEMONIC_ACTIVATOR, getModifierKeys( actual ) ); } } } private static String[] getActiveKeys( Display display ) { Object data = display.getData( RWT.ACTIVE_KEYS ); String[] result = null; if( data != null ) { if( data instanceof String[] ) { result = getArrayCopy( ( String[] )data ); } else { String mesg = "Illegal value for RWT.ACTIVE_KEYS in display data, must be a string array"; throw new IllegalArgumentException( mesg ); } } return result; } private static String[] getActiveKeys( Control control ) { Object data = control.getData( RWT.ACTIVE_KEYS ); return data != null ? getArrayCopy( ( String[] )data ) : null; } private static String[] getCancelKeys( Display display ) { String[] result = null; Object data = display.getData( RWT.CANCEL_KEYS ); if( data != null ) { if( data instanceof String[] ) { result = getArrayCopy( ( String[] )data ); } else { String mesg = "Illegal value for RWT.CANCEL_KEYS in display data, must be a string array"; throw new IllegalArgumentException( mesg ); } } return result; } private static String[] getCancelKeys( Control control ) { Object data = control.getData( RWT.CANCEL_KEYS ); return data != null ? getArrayCopy( ( String[] )data ) : null; } private static String getMnemonicActivator( Display display ) { String result = null; Object data = display.getData( RWT.MNEMONIC_ACTIVATOR ); if( data != null ) { if( data instanceof String ) { result = ( String )data; if( !result.endsWith( "+" ) ) { result += "+"; } } else { String mesg = "Illegal value for RWT.MNEMONIC_ACTIVATOR in display data, must be a string"; throw new IllegalArgumentException( mesg ); } } return result; } private static JsonArray translateKeySequences( String[] activeKeys ) { JsonArray result = new JsonArray(); if( activeKeys != null ) { for( int i = 0; i < activeKeys.length; i++ ) { result.add( translateKeySequence( activeKeys[ i ] ) ); } } return result; } private static String translateKeySequence( String keySequence ) { if( keySequence == null ) { throw new NullPointerException( "Null argument" ); } if( keySequence.trim().length() == 0 ) { throw new IllegalArgumentException( "Empty key sequence definition found" ); } String modifierPart = ""; String keyPart = ""; int lastPlusIndex = keySequence.lastIndexOf( "+", keySequence.length() - 2 ); if( lastPlusIndex != -1 ) { modifierPart = keySequence.substring( 0, lastPlusIndex + 1 ); keyPart = keySequence.substring( lastPlusIndex + 1 ); } else { keyPart = keySequence; } return getModifierKeys( modifierPart ) + formatKey( keyPart ); } private static String formatKey( String key ) { int keyCode = getKeyCode( key ); // TODO [tb] : use identifier instead of keycode return keyCode == -1 ? key : "#" + keyCode; } private static String getModifierKeys( String modifier ) { StringBuilder result = new StringBuilder(); // order modifiers if( modifier.indexOf( ALT ) != -1 ) { result.append( ALT ); } if( modifier.indexOf( CTRL ) != -1 ) { result.append( CTRL ); } if( modifier.indexOf( SHIFT ) != -1 ) { result.append( SHIFT ); } if( modifier.length() != result.length() ) { throw new IllegalArgumentException( "Unrecognized modifier found in key sequence: " + modifier ); } return result.toString(); } private static int getKeyCode( String key ) { int result = -1; Object value = KEY_MAP.get( key ); if( value instanceof Integer ) { result = ( ( Integer )value ).intValue(); } else if( key.length() == 1 ) { if( Character.isLetterOrDigit( key.charAt( 0 ) ) ) { // NOTE: This works only for A-Z and 0-9 where keycode matches charcode result = key.toUpperCase().charAt( 0 ); } } else { throw new IllegalArgumentException( "Unrecognized key: " + key ); } return result; } private static String[] getArrayCopy( String[] data ) { return Arrays.copyOf( data, data.length ); } private static boolean equals( Object object1, Object object2 ) { boolean result; if( object1 == object2 ) { result = true; } else if( object1 == null ) { result = false; } else { result = object1.equals( object2 ); } return result; } }