Technical Articles
Hotkeys / Keyboard shortcuts in SAP UI5 using Open Source Plugin
Recently I had a requirement where the end users want to interact with the Fiori applications using the keyboard keys(Hotkeys). Off course SAP UI5 controls are by default can be interacted using the keyboard as accessibility is one of the main features of Fiori. Eg: Using Tab, page down/up, arrow buttons…
The application that I’ve developed is mainly used in desktops and users needed keyboard shortcuts that are similar to SAP GUI(F8, SHIFT+F5.., etc combinations)
To achieve this functionality, we can always go for the traditional jquery as shown below:
$(document).keydown(function(evt){
if (evt.keyCode==83 && (evt.ctrlKey)){
evt.preventDefault();
alert('worked');
}
});
The complexity of the above code is that we have to spend a lot of time to find the Keyboard key codes like for example “83” is one of the keycodes for a key in the keyboard. Also, it will be more complex if we want to deregister a function for a keycode combination.
While I was investigating the above issues and complexity, I came across an open source plugin “jQuery HotKeys”.
https://github.com/jeresig/jquery.hotkeys
The above library is very simple and will offer the registration and deregistration for hotkeys easily. I will go through the code below for better understanding.
Requirement:
- Quick focus on the filter bar search fields using Alt + Function key combination eg: Alt+F1
- Posting the documents on the click of F8- We have a post button available but on the click of F8 key, the documents should be posted.
- Much more options can be provided like Tab Bar navigations(Changing the selected Tabs using the function key combinations) etc.., which I am not showing in the current blog
Step 1:
Copy the Hotkey API to the project util folder:
Step 2:
Create an interface for the Hotkey API & our application (This is an optional one).
sap.ui.define([
"sap/ui/base/Object"
], function(ui5Object) {
"use strict";
var HotkeyInterface = ui5Object.extend("sap.test.listreport.util.hotkeyInterface", {
constructor: function() {
// Nothing
},
bindHotKeys: function(combinations) {
// remove the old key combinations that are buffered
if(this.tempCombinations){
this.tempCombinations.forEach(function(mItem) {
this.unBindHotKey(mItem.keyCombination);
}, this);
}
// Buffer the combinations for removing later
this.tempCombinations = combinations;
combinations.forEach(function(mItem) {
// Now call the actual binding
this.bindHotKey(mItem.keyCombination, mItem.control, mItem.fnHandler, mItem.hanlder);
}, this);
},
bindHotKey: function(keyCombination, control, fnHandler, hanlder) {
$(document).bind("keydown." + this.getNameSpace(keyCombination), keyCombination, function(oEvent) {
if (control && control.getDomRef() && control.getDomRef().getBoundingClientRect()) {
// Check if the control is visible in DOM currently,
// sometimes,the control might be hidden becuase of a tab change or view change
var aMargin = control.getDomRef().getBoundingClientRect();
if (aMargin.width) {// If the width is availble, then it is visible
fnHandler.call(this, oEvent, control);
}
}
}.bind(hanlder));
},
unBindHotKeys: function(keyCombinations) {
// Remove the hotkeys
keyCombinations.forEach(function(mItem) {
this.unBindHotKey(mItem.keyCombination);
}, this);
},
unBindHotKey: function(keyCombination) {
$(document).unbind("keydown." + this.getNameSpace(keyCombination));
},
getNameSpace: function(keyCombination) {
// Create a unique key for the hotkey we are using
return "pocApplication_" + keyCombination.replace("+", "_");
}
});
return {
getInstance: function() {
// Singleton
if (!this.instance) {
this.instance = new HotkeyInterface();
}
return this.instance;
}
};
});
Include the both APIs in the manifest file:
Step 3:
Now use the API we have developed in our views as shown below:
Include the API in our view Controller:
In the Init method, create an object which will have the hotkey and event handler methods:
this.hotKeyHanlders = [{
keyCombination: "Alt+f1",
control: this.getView().byId("inputPopup"),
fnHandler: this.focusOnSearchFields,
hanlder: this
}, {
keyCombination: "Alt+f2",
control: this.getView().byId("idOrderInput"),
fnHandler: this.focusOnSearchFields,
hanlder: this
}, {
keyCombination: "F8",
control: this.getView().byId("idPostDocuments"),
fnHandler: this.handleHotKeyPost,
hanlder: this
}];
Now instantiate the API and register our hotkeys:
hotkeyInterface.getInstance().bindHotKeys(this.hotKeyHanlders);
focusOnSearchFields: function(oEvent, oControl) {
oEvent.preventDefault();
oControl.focus();
},
handleHotKeyPost: function(oEvent, oControl) {
oEvent.preventDefault();
this.postDocuments();
},
For Unbinding the hotkeys, we can also unbind the hotkeys individually. It will be done at onexit event.
unBindAllHotKeys: function() {
hotkeyInterface.getInstance()).unBindHotKeys(this.hotKeyHanlders);
},
Now we have instantiated the hotkeys API and registered the Hotkeys with event handler functions.
Once the Fiori App is loaded, then on the press of the above function key combinations, the respective event handlers will get triggered.
Sorry to disappoint the ones who are expecting the UI5 screens, this blog is just about the jQuery Hotkey plug usage in UI5 ;p
Note: just be careful while assigning the Hotkeys, go through the plugin URL that I’ve mentioned, there are some limitations as in few cases browser shortcuts will take more priority than the shortcuts we have assigned.
Thanks,
Mahesh
Great Job. Expecting many more to come from your bucket..
how can i navigate through the keyboard on the days of calender without using mouse?
i am able to navigate on the right and left dash arrows using TAB and shift+tab.
Hello,
first of all thank you for the blog post.
But I have a problem: After I change the selected key of a segmented button via shortcut, I automatically set the focus to an input field.
As soon as the focus is on a control, the shortcuts don't work anymore. I first have to click in the whitespace to release the focus and then the shortcuts work again.
Is there a way to work with shortcuts even though the focus is on a control?
Thank you!
I have the same problem. Did you find any solution?