Sections

 Home
 Dev Log
 Resume
 Free Media
 Riddles
 Bob's Gallery
 Links & Resources
 Contact


Projects

 Stem
 Nyx
 Kana Quizzer
 Keybinding Util
 Model Gallery
 Applets
 Nexus


Categories

 Dev Blog
 Keybindings
 Spell Checker
 History Search


Integrate Keybinding Chooser

Abstract

Keyboard shortcuts are vital to quick navigation of any sizable application. While The SIP Communicator has hard coded accelerators via an input/action map, having a chooser dialog would provide both customization and a centralized listing of those bindings. This touches on both the gui and back end, making it a good means of becoming acquainted with the current code.

Description

As mentioned in the abstract keyboard shortcuts are vital to quick navigation of any sizable application. A few months ago I wrote a package for handling key binding persistence and allowing customization via a chooser. The project can be found here.

This project consists of two tools for the use of customizable key bindings in Java applications. The first is an editor for creating or changing lists of bindings to be loaded by applications. The second is a chooser that can be used within applications to provide Swing dialogs for customizing the bindings. Both supported the following methods of persistence:

  • Serialized linked or normal hash maps
  • Serialized input maps
  • Properties mapping (java.util.Properties)- either as plain text or XML

The editor is used by developers, not end users, to create the default bindings. The chooser, however, is a UI utility that can be included in applications to provide to provide dialogs for changing the bindings (much as the JColorChooser allows the selection of colors). The dialog's appearance is fairly customizable, with screen shots on the project page and associated readme.

After a quick grep it looks like the current chat accelerators are mostly hard coded and handled by the SIPCommFrame class via an input/action map. The current keybinding-util package provides utilities for the KeyStroke -> String binding so I'll still need to figure out how to properly implement the ActionMap component, though this shouldn't be a terribly big whoop.

How To Add New Bindings

Adding configurable keybindings to new aspects of the SIP Communicator's UI isn't terribly difficult but can be tricky if you don't know where to look. The keybindings service is only intended for extensions of the SIPCommFrame class and this example will take you through the steps in defining the bindings for:
net.java.sip.communicator.impl.gui.main.MainFrame

All new binding sets need the following components:

  1. Unique string identifiers for internal use (by convention we use <component>-<action>, such as chat-nextTab). The MainFrame uses the following: main-rename, main-nextTab, and main-previousTab.
  2. i18n translations that are a reader friendly description of the action for the chooser. As of this writing we only have English and the MainFrame simply uses: "Rename", "Next Tab", and "Previous Tab".
  3. Default keybindings.
  4. A name for the resources (ie, the file name for the bindings). By convention this is keybindings-<component>, hence making it keybindings-main for the MainFrame.
  5. The actions to be fired when key's pressed.
  1. Create the mapping of default bindings to the internal identifiers. To do this run the KeybindingUtil.jar (java -jar lib/installer-exclude/KeybindingUtil.jar) to get the following window:

    Empty Editor

    Use the '+' button to add new entries and double click the actions to rename them to the internal identifiers. Clicking the shortcut field will make it prompt for the default shortcut. When you're done save the bindings as a "Serialized Hash Map" so they'll be internally represented as a LinkedHashMap (preserving the ordering). Add the new bindings to:
    resources/config/defaultKeybindings/<resource name> (in this case it was keybindings-main)

    Saving Editor
  2. Make your new bindings available for internal use. To do this you'll need to edit
    net.java.sip.communicator.service.keybindings.KeybindingSet
    adding the resource name and binding format to the Category enum. For instance the following was added for the MainFrame:
    MAIN("keybindings-main", Persistence.SERIAL_HASH)

  3. Add the mapping between the internal identifier and the i18n strings for the UI in:
    resources/languages/plugin/keybindingChooser/resources.properties

    For instance the following entries were added for the MainFrame:

    main-rename=Rename
    main-nextTab=Next Tab
    main-previousTab=Previous Tab
                    
  4. Use the setKeybindingInput(KeybindingSet.Category) and addKeybindingAction(String, Action) methods provided by the SIPCommFrame class to use the bindings in your frame. For instance the MainFrame does the following during its initialization:

      this.setKeybindingInput(KeybindingSet.Category.MAIN);
      this.addKeybindingAction("main-rename", new RenameAction());
      this.addKeybindingAction("main-nextTab", new ForwordTabAction());
      this.addKeybindingAction("main-previousTab", new BackwordTabAction());
                    

That's it. Your new bindings should now be included in a new tab under Settings > Keybindings. Changes applied here will be reflected in your frame and those changes will be preserved within the user's preferences.

Keybinding Settings Window

Hope this helps and happy hacking!


Back