org.syntax.jedit.DefaultInputHandler Maven / Gradle / Ivy
The newest version!
/*
* soapUI, copyright (C) 2004-2011 smartbear.com
*
* soapUI is free software; you can redistribute it and/or modify it under the
* terms of version 2.1 of the GNU Lesser General Public License as published by
* the Free Software Foundation.
*
* soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details at gnu.org.
*/
package org.syntax.jedit;
import java.awt.Toolkit;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.Hashtable;
import java.util.StringTokenizer;
import javax.swing.KeyStroke;
/**
* The default input handler. It maps sequences of keystrokes into actions and
* inserts key typed events into the text area.
*
* @author Slava Pestov
* @version $Id$
*/
public class DefaultInputHandler extends InputHandler
{
/**
* Creates a new input handler with no key bindings defined.
*/
public DefaultInputHandler()
{
bindings = currentBindings = new Hashtable();
}
/**
* Sets up the default key bindings.
*/
public void addDefaultKeyBindings()
{
addKeyBinding( "BACK_SPACE", BACKSPACE );
addKeyBinding( "C+BACK_SPACE", BACKSPACE_WORD );
addKeyBinding( "DELETE", DELETE );
addKeyBinding( "C+DELETE", DELETE_WORD );
addKeyBinding( "ENTER", INSERT_BREAK );
addKeyBinding( "TAB", INSERT_TAB );
addKeyBinding( "INSERT", OVERWRITE );
addKeyBinding( "C+\\", TOGGLE_RECT );
addKeyBinding( "HOME", HOME );
addKeyBinding( "END", END );
addKeyBinding( "C+A", SELECT_ALL );
addKeyBinding( "S+HOME", SELECT_HOME );
addKeyBinding( "S+END", SELECT_END );
addKeyBinding( "C+HOME", DOCUMENT_HOME );
addKeyBinding( "C+END", DOCUMENT_END );
addKeyBinding( "CS+HOME", SELECT_DOC_HOME );
addKeyBinding( "CS+END", SELECT_DOC_END );
addKeyBinding( "PAGE_UP", PREV_PAGE );
addKeyBinding( "PAGE_DOWN", NEXT_PAGE );
addKeyBinding( "S+PAGE_UP", SELECT_PREV_PAGE );
addKeyBinding( "S+PAGE_DOWN", SELECT_NEXT_PAGE );
addKeyBinding( "LEFT", PREV_CHAR );
addKeyBinding( "S+LEFT", SELECT_PREV_CHAR );
addKeyBinding( "C+LEFT", PREV_WORD );
addKeyBinding( "CS+LEFT", SELECT_PREV_WORD );
addKeyBinding( "RIGHT", NEXT_CHAR );
addKeyBinding( "S+RIGHT", SELECT_NEXT_CHAR );
addKeyBinding( "C+RIGHT", NEXT_WORD );
addKeyBinding( "CS+RIGHT", SELECT_NEXT_WORD );
addKeyBinding( "UP", PREV_LINE );
addKeyBinding( "S+UP", SELECT_PREV_LINE );
addKeyBinding( "DOWN", NEXT_LINE );
addKeyBinding( "S+DOWN", SELECT_NEXT_LINE );
addKeyBinding( "C+ENTER", REPEAT );
// Clipboard
addKeyBinding( "C+C", CLIP_COPY );
addKeyBinding( "C+V", CLIP_PASTE );
addKeyBinding( "C+X", CLIP_CUT );
}
/**
* Adds a key binding to this input handler. The key binding is a list of
* white space separated key strokes of the form [modifiers+]key where
* modifier is C for Control, A for Alt, or S for Shift, and key is either a
* character (a-z) or a field name in the KeyEvent class prefixed with VK_
* (e.g., BACK_SPACE)
*
* @param keyBinding
* The key binding
* @param action
* The action
*/
public void addKeyBinding( String keyBinding, ActionListener action )
{
Hashtable current = bindings;
StringTokenizer st = new StringTokenizer( keyBinding );
while( st.hasMoreTokens() )
{
KeyStroke keyStroke = parseKeyStroke( st.nextToken() );
if( keyStroke == null )
return;
if( st.hasMoreTokens() )
{
Object o = current.get( keyStroke );
if( o instanceof Hashtable )
current = ( Hashtable )o;
else
{
o = new Hashtable();
current.put( keyStroke, o );
current = ( Hashtable )o;
}
}
else
current.put( keyStroke, action );
}
}
/**
* Removes a key binding from this input handler. This is not yet
* implemented.
*
* @param keyBinding
* The key binding
*/
public void removeKeyBinding( String keyBinding )
{
throw new InternalError( "Not yet implemented" );
}
/**
* Removes all key bindings from this input handler.
*/
public void removeAllKeyBindings()
{
bindings.clear();
}
/**
* Returns a copy of this input handler that shares the same key bindings.
* Setting key bindings in the copy will also set them in the original.
*/
public InputHandler copy()
{
return new DefaultInputHandler( this );
}
/**
* Handle a key pressed event. This will look up the binding for the key
* stroke and execute it.
*/
public void keyPressed( KeyEvent evt )
{
int keyCode = evt.getKeyCode();
int modifiers = evt.getModifiers();
if( keyCode == KeyEvent.VK_CONTROL || keyCode == KeyEvent.VK_SHIFT || keyCode == KeyEvent.VK_ALT
|| keyCode == KeyEvent.VK_META )
return;
if( ( modifiers & ~KeyEvent.SHIFT_MASK ) != 0 || evt.isActionKey() || keyCode == KeyEvent.VK_BACK_SPACE
|| keyCode == KeyEvent.VK_DELETE || keyCode == KeyEvent.VK_ENTER || keyCode == KeyEvent.VK_TAB
|| keyCode == KeyEvent.VK_ESCAPE )
{
if( grabAction != null )
{
handleGrabAction( evt );
return;
}
KeyStroke keyStroke = KeyStroke.getKeyStroke( keyCode, modifiers );
Object o = currentBindings.get( keyStroke );
if( o == null )
{
// Don't beep if the user presses some
// key we don't know about unless a
// prefix is active. Otherwise it will
// beep when caps lock is pressed, etc.
if( currentBindings != bindings )
{
Toolkit.getDefaultToolkit().beep();
// F10 should be passed on, but C+e F10
// shouldn't
repeatCount = 0;
repeat = false;
evt.consume();
}
currentBindings = bindings;
return;
}
else if( o instanceof ActionListener )
{
currentBindings = bindings;
executeAction( ( ( ActionListener )o ), evt.getSource(), null );
evt.consume();
return;
}
else if( o instanceof Hashtable )
{
currentBindings = ( Hashtable )o;
evt.consume();
return;
}
}
}
/**
* Handle a key typed event. This inserts the key into the text area.
*/
public void keyTyped( KeyEvent evt )
{
int modifiers = evt.getModifiers();
char c = evt.getKeyChar();
if( c != KeyEvent.CHAR_UNDEFINED && ( modifiers & KeyEvent.ALT_MASK ) == 0
&& ( modifiers & KeyEvent.CTRL_MASK ) == 0 && ( modifiers & KeyEvent.META_MASK ) == 0 )
{
if( c >= 0x20 && c != 0x7f )
{
KeyStroke keyStroke = KeyStroke.getKeyStroke( Character.toUpperCase( c ) );
Object o = currentBindings.get( keyStroke );
if( o instanceof Hashtable )
{
currentBindings = ( Hashtable )o;
return;
}
else if( o instanceof ActionListener )
{
currentBindings = bindings;
executeAction( ( ActionListener )o, evt.getSource(), String.valueOf( c ) );
return;
}
currentBindings = bindings;
if( grabAction != null )
{
handleGrabAction( evt );
return;
}
// 0-9 adds another 'digit' to the repeat number
if( repeat && Character.isDigit( c ) )
{
repeatCount *= 10;
repeatCount += ( c - '0' );
return;
}
executeAction( INSERT_CHAR, evt.getSource(), String.valueOf( evt.getKeyChar() ) );
repeatCount = 0;
repeat = false;
}
}
}
/**
* Converts a string to a keystroke. The string should be of the form
* modifiers+shortcut where modifiers is any combination
* of A for Alt, C for Control, S for Shift or M for Meta, and
* shortcut is either a single character, or a keycode name from the
* KeyEvent
class, without the VK_
prefix.
*
* @param keyStroke
* A string description of the key stroke
*/
public static KeyStroke parseKeyStroke( String keyStroke )
{
if( keyStroke == null )
return null;
int modifiers = 0;
int index = keyStroke.indexOf( '+' );
if( index != -1 )
{
for( int i = 0; i < index; i++ )
{
switch( Character.toUpperCase( keyStroke.charAt( i ) ) )
{
case 'A' :
modifiers |= InputEvent.ALT_MASK;
break;
case 'C' :
modifiers |= getMenuShortcutKeyMask();
break;
case 'M' :
modifiers |= InputEvent.META_MASK;
break;
case 'S' :
modifiers |= InputEvent.SHIFT_MASK;
break;
}
}
}
String key = keyStroke.substring( index + 1 );
if( key.length() == 1 )
{
char ch = Character.toUpperCase( key.charAt( 0 ) );
if( modifiers == 0 )
return KeyStroke.getKeyStroke( ch );
else
return KeyStroke.getKeyStroke( ch, modifiers );
}
else if( key.length() == 0 )
{
System.err.println( "Invalid key stroke: " + keyStroke );
return null;
}
else
{
int ch;
try
{
ch = KeyEvent.class.getField( "VK_".concat( key ) ).getInt( null );
}
catch( Exception e )
{
System.err.println( "Invalid key stroke: " + keyStroke );
return null;
}
return KeyStroke.getKeyStroke( ch, modifiers );
}
}
// private members
private Hashtable bindings;
private Hashtable currentBindings;
private DefaultInputHandler( DefaultInputHandler copy )
{
bindings = currentBindings = copy.bindings;
}
}