alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 * DefaultInputHandler.java - Default implementation of an input handler
 * Copyright (C) 1999 Slava Pestov
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

package org.gjt.sp.jedit.textarea;

import javax.swing.KeyStroke;
import java.awt.event.*;
import java.awt.Toolkit;
import java.util.Hashtable;
import java.util.StringTokenizer;

import org.jext.*;

/**
 * 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: DefaultInputHandler.java,v 1.6 2002/08/09 14:16:38 orangeherbert Exp $
 */
public class DefaultInputHandler extends InputHandler
{

  /**
   * Creates a new input handler with no key bindings defined.
   */
  public DefaultInputHandler()
  {
    bindings = currentBindings = new Hashtable();
  }

  /**
   * Creates a new input handler with the same set of key bindings
   * as the one specified. Note that both input handlers share
   * a pointer to exactly the same key binding table; so adding
   * a key binding in one will also add it to the other.
   * @param copy The input handler to copy key bindings from
   */
  public DefaultInputHandler(DefaultInputHandler copy)
  {
    bindings = currentBindings = copy.bindings;
  }

  /**
   * 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("HOME",HOME);
    addKeyBinding("END",END);
    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);
  }

  /**
   * 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();
  }

  /**
   * 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 (evt.isShiftDown())
    {
      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;

        ((JextTextArea) getTextArea(evt)).endCurrentEdit();
        executeAction(((ActionListener)o), evt.getSource(), null);

        evt.consume();
        return;
      } else if(o instanceof Hashtable) {
        currentBindings = (Hashtable)o;
        evt.consume();
        return;
      }
    } 
    else if (!evt.isShiftDown()
        || 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;

        ((JextTextArea) getTextArea(evt)).endCurrentEdit();
        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)
  {
    char c = evt.getKeyChar();

    if (c != KeyEvent.CHAR_UNDEFINED && !evt.isAltDown())
    {
      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 org.jext.OneClickAction) {
          currentBindings = bindings;
          ((JextTextArea) getTextArea(evt)).endCurrentEdit();
          executeOneClickAction((org.jext.OneClickAction) o, evt.getSource(), String.valueOf(c));
          return;
        } else if (o instanceof ActionListener) {
          currentBindings = bindings;
          ((JextTextArea) getTextArea(evt)).endCurrentEdit();
          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))
        {
          setRepeatCount(repeatCount * 10 + (c - '0'));
          evt.consume();
          return;
        } 

        executeAction(inputAction, evt.getSource(), String.valueOf(evt.getKeyChar()));

        //if (!evt.isControlDown())
        //System.out.println(evt.isControlDown());
        ((JextTextArea) getTextArea(evt)).userInput(c);

        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 |= Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); //InputEvent.CTRL_MASK;
            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;
}
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.