I have a physical barcode scanner and I want to get it's input, i.e the barcode, in the app without having a focused EditText.
I tried adding a KeyListener in my Activity. However, none of its implemented methods (onKeyUp, onKeyDown etc) was called.
Then I added the dispatchKeyEvent, which worked, but is never called as many times as the barcode length. Instead, before the barcode is read, some random button in my view gets focus from the barcode scanner.
String barcode = "";
#Override
public boolean dispatchKeyEvent(KeyEvent e) {
char pressedKey = (char) e.getUnicodeChar();
barcode += pressedKey;
if (e.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
Toast.makeText(getApplicationContext(), "barcode--->>>" + barcode, Toast.LENGTH_LONG)
.show();
}
return super.dispatchKeyEvent(e);
}
I've seen a few questions out there in SO but none really gave a concrete answer.
For me, for a barcode scanner (USB, reference STA pcs) works the next code:
#Override
public boolean dispatchKeyEvent(KeyEvent e) {
if(e.getAction()==KeyEvent.ACTION_DOWN){
Log.i(TAG,"dispatchKeyEvent: "+e.toString());
char pressedKey = (char) e.getUnicodeChar();
barcode += pressedKey;
}
if (e.getAction()==KeyEvent.ACTION_DOWN && e.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
Toast.makeText(getApplicationContext(),
"barcode--->>>" + barcode, Toast.LENGTH_LONG)
.show();
barcode="";
}
return super.dispatchKeyEvent(e);
}
First, thank you all.
Since my App has to look up the barcode in the DB I had to not add the ENTER_KEY input to the Barcode String, also to prevent any focused button of going off I made the Method return false.
String barcode = "";
#Override
public boolean dispatchKeyEvent(KeyEvent e) {
if(e.getAction()==KeyEvent.ACTION_DOWN
&& e.getKeyCode() != KeyEvent.KEYCODE_ENTER){ //Not Adding ENTER_KEY to barcode String
char pressedKey = (char) e.getUnicodeChar();
barcode += pressedKey;
}
if (e.getAction()==KeyEvent.ACTION_DOWN
&& e.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
Log.i(TAG,"Barcode Read: "+barcode);
barcodeLookup(barcode);// or Any method handling the data
barcode="";
}
return false;
}
Using kotlin
private val barcode = StringBuffer()
override fun dispatchKeyEvent(event: KeyEvent?): Boolean {
if (event?.action == KeyEvent.ACTION_DOWN) {
val pressedKey = event.unicodeChar.toChar()
barcode.append(pressedKey)
}
if (event?.action == KeyEvent.ACTION_DOWN && event?.keyCode == KeyEvent.KEYCODE_ENTER) {
Toast.makeText(baseContext, barcode.toString(), Toast.LENGTH_SHORT).show()
barcode.delete(0, barcode.length)
}
return super.dispatchKeyEvent(event)
}
e.getCharacters() should give you the complete barcode.
This works for me on a PL-40L device with embedded 2d barcode reader, running Android 5.1
dispatchKeyEvent(KeyEvent e) is triggered once for each read barcode, not for each character in the barcode
Hope this helps
DispatchKeyEvent Hardware key events are always delivered to the View currently in focus. They are dispatched starting from the top of the View hierarchy, and then down, until they reach the appropriate destination. If your View (or a child of your View) currently has focus, then you can see the event travel through the dispatchKeyEvent() method. In short, dispatchKeyEvent() will be only called if TextView/EditText is in focus.
You can do it even without any focused View. You need to subscribe for broadcast intent like this:
const val QR_ACTION: String = "android.intent.ACTION_DECODE_DATA"
const val QR_EXTRA: String = "barcode_string"
private val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
try {
Timber.d("Get intent ${intent.action}")
if (QR_ACTION == intent.action) {
if (intent.hasExtra(QR_EXTRA)) {
val code = intent.getStringExtra(QR_EXTRA)
Timber.d("New QR code $code")
// now you have qr code here
}
} }
} catch (t: Throwable) {
// handle errors
}
}
}
Please check QR_ACTION and QR_EXTRA in your scanner settings first, it can be different for different brands.
Related
I am writing barcode scanner app for PDA device. In this device there is only LF terminator. So When I scan the barcode, the cursor jumped to another line.Even thought I set edittext.requestFocus() the cursor will not come back to the start of the edit text. I would like to call back the cursor to the first line and position"0". How can I do that? And another thing is , Can I get the pressed trigger keycode? Here is the code -
ID.setOnKeyListener(View.OnKeyListener { _, keyCode, event ->
if (event.keyCode == KeyEvent.KEYCODE_ENTER && event.action == KeyEvent.ACTION_DOWN ) {
if (edt_location.text.toString() == "" || edt_qty.text.toString() == "") {
Toast.makeText(this, "Make Sure To Enter Location And Qty", Toast.LENGTH_SHORT)
.show()
edt_id.setText("")
} else{
try {
val item=Item(
edt_id.text.toString(),
Integer.parseInt(edt_qty.text.toString()),
edt_location.text.toString()
)
qt=edt_qty.text.toString().toInt()
record_code=edt_id.text.toString()
record_location=edt_location.text.toString()
db.addItem(item)
db.viewData()
txt_article.setText(code.toString())
txt_price.setText(price.toString())
txt_description.setText(desc.toString())
txt_isbn.setText(record_code.toString())
txt_tran_qty.setText(qty.toString())
record_id=edt_id.text.toString()
edt_id.setText("")
edt_id.requestFocus()
} catch (nfe: NumberFormatException) {
nfe.printStackTrace()
}
}
}
false
})
So regarding the solution to this question I assume the solution to your problem should be quite easy:
edt_id.setSelection(position)
whereposition is your desired cursor position.
What exactely is your keycode?
I am using 1D scanner i.e "https://www.issyzonepos.com/ipda018-android-7-0-pda-bluetooth-4-1-support-gprs-wifi_p326.html" for my app. The app is basically to scan code and order data. I have also implemented a scanner through a camera. My APP is working perfectly on this device but when I try to run it on a mobile device then it crashes on "sm = new ScanDevice();" as it is a non-scanner device. I tried a lot to resolve this can you tell me how can I solve this. I have used this device's SDK for the scanner.
Code:
sm = new ScanDevice();
public void onKeyDown(int keyCode, KeyEvent event) {
int charCode = event.getKeyCode();
System.out.println("charCode = " + keyCode + " " + event);
//sm.openScan();
if (charCode == 302 || charCode == 301 || charCode == 303) {
if (spBar.getSelectedItem().toString().trim().equals("SELECT BAR")) {
Toast.makeText(getActivity(), getResources().getString(R.string.select_a_bar), Toast.LENGTH_SHORT).show();
} else {
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(
Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(actSearchCode.getApplicationWindowToken(), 0);
System.out.println("openScannerL = " + sm.getOutScanMode());
sm.openScan();
}
} else if (charCode == 82) {
} else {
sm.closeScan();
}
}
For the sake of completeness, here's the stack trace of the error from the OP - unfortunately, as a screenshot.
Line 76 is sm = new ScanDevice();
As I mentioned in my comment, you can just create your scanner instance inside a try-catch block. For this, you'll have to declare the variable in a class, but instantiate it in a method. Your code still doesn't show where you're declaring your sm, but you may end up with something like this:
public class MyScanActivity extends Activity {
ScanDevice sm;
public void onCreate(Bundle bundle) {
try {
...
sm = new ScannerDevice();
...
} catch (Exception ex) {
Log.w("SCANNER_ACTIVITY", "Could not create scanner device - not a scanner?");
}
...
}
public void onKeyDown(int keyCode, KeyEvent event) {
...
if (sm == null) {
Log.i("SCANNER_ACTIVITY", "Scanner not instantiated - not a scanner?");
} else {
// all your scanning code goes here
}
}
}
I wanted to check programmatically that whether the input given by user is either from soft keyboard or the barcode scanner attached to the android tablet.
There is no edit text in activity where I want to apply this so please avoid providing solutions that are applicable through EditText.
With dispatchKeyEvent you can listen for any KeyEvent from the barcode scanner.
#Override
public boolean dispatchKeyEvent(KeyEvent e) {
// do something on input
return false; // prevent default behaviour
}
Use following code to read input/values from barcode scanner, so onKeyDown you need to override in your activity/dialog
String barcode="";
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
log("Key Down keyCode " + keyCode);
if (keyCode == KeyEvent.KEYCODE_BACK) {
return super.onKeyDown(keyCode, event);
} else if (keyCode == KeyEvent.KEYCODE_ENTER) {//if scanner doesn't return enter key code then make sure that any view must not have focus in window
//write your code to process the scanned barcode input
barcode = "";
} else {
Character input = (char) event.getUnicodeChar();
log("Scanner Input " + input);
if (Character.isDigit(input) || Character.isLetter(input)) {
barcode += input;//concat the characters
}
}
return true;
}
I want to read barcodes using a bluetooth barcode scanner.
I don't want to use Bluetooth Keyboard Emulation (HID) mode, because is too hard to point to a textbox before any scan.
I read this developer.android.com/guide/topics/connectivity/bluetooth.html but I don't found yet something usable.
Must listen for an write event with a end-code delimiter (CR, LF, etc).
If your bluetooth barcode scanner does not have a switch* for change HID mode to SSP mode, then you can't connect with him. (* hardware or software switch)
Android connect natively with HID bluetooth (Human Interface Device) and don't let them go :).
So, I solve my problem reading and overriding a keyboard event.
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (barCodeRadearIsOn && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER || (event.getKeyCode() >= 7 && event.getKeyCode() <= 16))) {
if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
if (event.getAction() == KeyEvent.ACTION_UP){
Toast.makeText(context, barCode, Toast.LENGTH_LONG).show();
....... .......
barCode = "";
}
} else {
if (event.getAction() == KeyEvent.ACTION_UP){
barCode = barCode + (char)event.getUnicodeChar();
}
}
return true;
} else {
return super.dispatchKeyEvent(event);
}
}
Notes:
barCodeRadearIsOn - users have a switch on/off
This code "intercept" only Enter and numeric characters from 0 to 9.
I have been trying to built an app based on GHOST game.
I have written an onKeyUp function which only accepts lowercase alphabets and adds it to a string called wordfragment and then calling the function computerTurn in it. But i had seen after successfully running first time i.e. calling the computerTurn function and getting return statement from computerturn function it(onkeyup) does not works second time.
Here my code to onKeyUp function.
#Override
public boolean onKeyUp(int KeyCode, KeyEvent event) {
char ch = (char)event.getUnicodeChar();
if( !( ch >= 'a' && ch <='z' ) ) {
return super.onKeyUp(KeyCode, event);
}
wordFragment = wordFragment + ch;
label.setText(COMPUTER_TURN);
text.setText(wordFragment);
userTurn = false;
computerTurn();
return true;
}
and my code to computerTurn function is
private boolean computerTurn() {
if(wordFragment.length() >= 4 && dictionary.isWord(wordFragment)){
label.setText("Computer wins");
// challenge.setEnabled(false);
return true;
}
else {
String word = dictionary.getAnyWordStartingWith(wordFragment.toLowerCase());
if(word!=null){
Toast.makeText(GhostActivity.this, "comp word found", Toast.LENGTH_SHORT).show();
wordFragment += word.charAt(wordFragment.length());
}
else{
Toast.makeText(GhostActivity.this, "comp word not found", Toast.LENGTH_SHORT).show();
label.setText("User Wins!!");
//challenge.setEnabled(false);
// wordFragment += (char)(random.nextInt(26) + 61);
}
}
// Do computer turn stuff then make it the user's turn again
userTurn = true;
label.setText(USER_TURN);
text.setText(wordFragment);
Toast.makeText(GhostActivity.this, "return true", Toast.LENGTH_SHORT).show();
return true;
}
Android softkeyboards rarely use key events. The correct way to use an android soft keyboard is via InputConnection. Only hardware keys generally issue key events. Basically you're coding this the right way for Windows or web, but the wrong way for Android.