Problem Statement:

It’s common knowledge that on a mobile device, if you tap (set focus) on a field, that the on screen keyboard pops up expecting the user to type in a value.

This is a problem for users using RF scanners who simply want to view data and scan a barcode without having to close the on screen keyboard to get to said data.

Using Slipstream/Screen personas proved a struggle to solve this issue, as the device keyboard is more hardware related and cannot be controlled by front end scripting offered by the Screen Personas engine.

Smaller RF devices such as the Zebra-TC830 suffer because of this, with a bulk of their screen being taken up by the keyboard.

Picture 1

Option Findings:

Finding 1: 

Our first finding was that we could implement a custom keyboard from the devices app store. In this case it was a keyboard called ‘Null keyboard’, which basically simulates an invisible keyboard. This means that if we set this keyboard as the devices default, that no keyboard would appear when a field is focused on.

This would not work however as the customer had the requirement where they may need to use the keyboard to type in a values when no barcodes were available to scan.

Finding 2:

We then found that if you set a field as readOnly (enabled = false), that the field can still be focused on but you cannot type in the field, which in turn results in no keyboard appearing. We found that via Slipstream scripting we could still paste values into the read only field, which looked promising to fix the issue.

We then discovered that the built in the scanner of the device actually simulates a keyboard when scanning a value, so as a result would not paste any values into a read only field.

Finding 3:

We then looked at using plug-ins / external APIs that might allow us to handle the keyboard behaviour. The standard Fiori Client the customer was using the render the flavors contains a number of Cordova plug-ins as standard, but we found that a specific plug-in called ‘Cordova Ionic-Keyboard” was not included in the plug-ins available by the standard Fiori Client.

This lead us to develop a custom Fiori Client which we added said plug-in to. This gave us access to functions and events delivered by the plug-in inside the front-end slipstream scripting engine.

Utilising a simple ‘keyboard.hide()” command delivered by the plug-in, we were able to create a script to close the keyboard every-time it would open.

The issue with this option is that to hide a keyboard, it obviously first has to be visible. The keyboard did indeed close as soon as it opened, as hoped, but not before the keyboard was fully visible for a split second first. This option solved the customers issue, but it was not perfect so we looked deeper into more options to find a perfect fix.

Finding 4:

We found that there was in-fact events and functions available within the standard Android API’s, but due to using Slipstream and not a standalone custom application where we can control the files etc, we were unable to utilise these API’s.

 

The Fix:

In the end we found a setting in the RF device scanner settings (data wedge in this case), which allows scanned values to be accessed/sent to the front end layer.

Going back to what we found earlier, where the scanner actually simulates a keyboard when scanning, we discovered that each value sent by the scanner behaves the same as if someone was typing the value on a keyboard.

This lead us to try using a standard browser event listener called ‘keypress’, which as the name suggests, will run a function every time a key is pressed.

 

In our scenario, the scanned value is sent 1 character at a time instead of all at once. This means whatever function we attach the keypress event will run over and over again until it’s finished. This meant any variable we defined in the function was getting overwritten by the next character, so the final result was just the last character of the scanned value.

What we ended up doing was defining a global array, and inside the keypress function we simply pushed the sent character into that array. We chose to store the array globally as we wanted to access this array in a 2nd screen personas script which we would call asynchronously.

As we now had a way to capture the scanned value in the scripting engine, we could go back to the earlier finding and make the field readOnly which would prevent the keyboard appearing.

 


Script 1:

window.removeEventListener(‘keypress’, window.ourFunction , true);
window.arrayName = [];

window.ourFunction = function(e) {
if(document.activeElement.readOnly){
window.arrayName.push(e.key);

}

if (window.ArrayName.length === 20){
session.utils.executeScriptAsync(‘2nd script ID’);
}
};

window.addEventListener(‘keypress’, window.ourFunction , true);


Script 2:

var value = window.arrayName.join(”);

session.findById(“fieldID”).text = value;


The above Script 1 code is added to the onLoad event of the Slipstream transaction.

To summarise what it does:

  1. Removes any existing function added to the keypress event. This is because we attach it globally, so if we add it to 1 transaction and then navigate to another transaction, it will still exist.
  2. Define the global array that will hold the scanned characters
  3. Create the function which says, if the currently focused element is read only (so we know its the correct field we are scanning to), then push the pressed key to the global array
  4. As stated earlier, the function will run every time a character is sent, which may result in a performance lag if the value is large. To work around this we add an if condition which only runs if the global array length hits 20. In our case we say 20 because the example field is for SSCC in the warehouse and we know it is always going to be 20 characters long. In your case this field length may be different, so adjust to fit. The if condition calls the 2nd above script which will paste the value into the field
  5. Add the function fo the keypress event.

Script 2 is called from within script 1 and simple combines all the values in the global array into a single string and then pastes it into the desired field.