Using Key Events effectively in RAP
March 8, 2012 | 6 min ReadGood keyboard controls have become a staple of modern web applications, such as Google Mail, Github (press “?”) and Flickr. However, almost every browser implements key events slightly differently, all with some quirks, and none of them like in SWT. For this reason, key events in RAP had, until recently, several issues and limitations. That is a thing of the past now, as the key events implementation has been largely rewritten in RAP 1.5M5, and now finally works reliably. This also brings some general changes to RAP key event handling.
Some keys that didn’t work at all (like arrow-keys in Firefox), work fine now. This also fixes the JFace Content Proposal.
Several non-alphanumeric keys had the wrong keycode, those are fixed.
Key events are no longer blocking the UI when sending the Ajax request to the server.
There is now a feature called “active keys”, which makes it possible to drastically reduce traffic traffic. It was already present in RAP 1.4, but has been greatly improved.
Another new feature is called “cancel keys”. It allows to suppress the browsers and widgets default operations associated with any given key.
The “cancel keys” replace the now-defunct support for the
doit
flag on key events.
The Active Keys
One practical problem with key events was the high amount of network traffic they can generate, one request per pressed key. Especially when you add a listener to widgets like Text, there may be hundreds of requests per user per minute - even if only a few of them are relevant to your applications logic. To counter that, “active keys” allows you to limit the number of requests to the server to only those that are actually necessary. You simply attach a list of key combinations to the widget that has the key listener, and subsequently RAP will only fire key events on this widget that match any of the given combinations.
Example:
widget.setData( RWT.ACTIVE_KEYS, new String[]{ "ALT+SHIFT+X",
"F1", "/"
); widget.addKeyListener( new KeyListener(){ ... } );
The widgets and browsers behavior is not changed by this at all. Also, even if you would handle all active keys the same way in the listener, it would be good practice to still explicitly check the pressed key and modifiers on the event itself - especially if you are working on a multi-platform project. Then this approach is also Single Sourcing friendly.
Though the example limits the active key to the given widget, this feature can also be used to implement global key bindings. Just add the list to the display instead to a widget. RAP will send key events for these keys, no matter what widget is focused. (This aspect of “active keys” already worked in RAP 1.4). Typically you want to use this feature together with a display filter, so you can also process them globally.
Example:
display.setData( RWT.ACTIVE_KEYS, new String[]{ "CTRL+X",``"CTRL+Y",``"CTRL+Z"
); display.addFilter( SWT.KeyDown, new Listener(){ ... }
);
The Cancel Keys
One issue specific to keyboard shortcuts in web applications is that you are basically sharing your pool of possible key combos with the browser itself. For example, “CTRL+F” will bring up search dialog in almost every browser, so you can’t just use it to do the same in your application - you would have both dialogs pop up at the same time. Up until now RAP supported the doit
flag on key events, which made it possible to suppress not only widget-specific behavior (like in SWT), but also some browser-native shortcuts. However, depending on the browser this was working only for some keys and shortcuts.
As time went on the doit
support became an obstacle to us RAP developers. It was originally implemented to better support JFace cell editors. This worked well, but outside that use case it had - as mentioned - some limitations. It also prevented us to fix a number of bugs for key event handling, so for the first time in RAP history, we decided to remove a feature. It was not an easy decision to make, and we only did it after we had a solid replacement.
This replacement is called “cancel keys”. It works pretty much like “active keys”, and can also be combined with that. Like before you attach a list of keys or key-combinations to the widget, and those will all be “prevented”. That means that while the widget is focused, whatever the pressed keys default action is will not happen. This is true for all RAP widget behavior, as well as for most browser features. (Some browser features can not be prevented, like CTRL+TAB for switching tabs, or ALT to focus the menu bar.)
Example:
widget.setData( RWT.CANCEL_KEYS, new String[]{ "CTRL+F", "CTRL+T" );
You can also change the set of cancel keys at any time. All keys not on the list will still work, even if they are part of a listed combination. If the widget from the example is a Text, pressing only “F” or “T” will still insert that character into the field. Again, this feature also works globally when setting the list on Display. You should keep in mind though that the user might be accustomed for certain shortcuts to trigger the default action, like CTRL+T to open a new browser tab, and might not appreciate it when its completely “overwritten” in your application. If you want your code to also work in SWT, you still need to set the doit
flag to false.
Showcase
You can see those features in action in our updated demo on the “TableViewer” page. For example, pressing “CTRL+F” will switch to the filter textfield, and from there “Escape”, “Enter” or the down-arrow key will focus the Table again. You’ll notice that your browsers search field will not pop up if you press “CTRL+F”, as long as the table is focused. If you use Firebug or any other debugging tool, you can also see that no requests are sent if any other keys are pressed.
For the applications user to actually use the keyboard controls, he first has to know they exist. So as a UI designer/developer, you might want to place some hints. In the case of our demo I simply placed a short help-text below the Table in a small, grayish font, so it doesn’t distract form the rest of the UI. If there are too many shortcuts to list them all, the Link widget could be used in a similar manner, directing the user to a more comprehensive help dialog.