react-native-keyevent icon indicating copy to clipboard operation
react-native-keyevent copied to clipboard

Key event is creating a click on Component

Open Florent75 opened this issue 1 year ago • 12 comments

Hi there,

I have been using this library to capture key event coming from a barcode scanner.

I have a very strange issue : On the screen implementing the Key down event When scanning the barcode, -> I do capture the key down event, and the values are good -> BUT, at some point (I don't know which captured key is doing that), the first Touchable Opacity component is clicked without any action from my side.

What I have tried :

  • This behaviour is not happening when I use a TextInput component and focus on it.
  • For what I have understand, by catching the values of the keyboard, the textinput is preventing React native to interpreting keyboard value as action to do on the screen.

BUT : The textInput is slowing down the catching of Key event which is not a solution for me.

Do you have any clue on how I could solve this ?

Regards

Florent75 avatar Aug 18 '22 08:08 Florent75

Hey Florent7️⃣5️⃣! I ran into the exact same issue recently.

What fixed it for me was to re-write the handlers in MainActivity.java to override dispatchKeyEvent instead of onKeyDown/Up/Multiple as the docs from react-native-keyevent say to do.

In my app I'm only working with onKeyDownEvent from react-native-keyevent, so I pass the event and keyCode from dispatchKeyEvent to onKeyDownEvent, which then passes it to the JS.

@Override
public boolean dispatchKeyEvent(KeyEvent event) {

    // get the keyCode, since it is not directly passed by dispatchKeyEvent, unlike onKeyDown
    int keyCode = event.getKeyCode();

    // handle these key events normally (specific to my app, since I want for example the volume buttons to work normally)
    if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
            || keyCode == KeyEvent.KEYCODE_VOLUME_UP
            || keyCode == KeyEvent.KEYCODE_BACK
    ) {
        return super.dispatchKeyEvent(event);
    }

    // handle all other key events with the react-native-keyevent onKeyDownEvent handler
    if (event.getRepeatCount() == 0
            && event.getAction() == 0 // 0 means key down
    ) {
        KeyEventModule.getInstance().onKeyDownEvent(keyCode, event);
    }

    return true;
};

samzmann avatar Aug 24 '22 17:08 samzmann

Hi samzmann,

Thanks a lot for your feedback, and glad that someone faces the same issue. I am not sure I have understand all of your reply.

To be more precise about my issue :

  • I am reading a QR code
  • Some value of my QR code are making a click on the TouchableOpacity component
  • I do want to retrieve the value BUT without triggering the "Click" event

Please correct me If I am wrong, so far from your code I have understand that :

  • You want to handle KEYCODE_VOLUME_DOWN, KEYCODE_VOLUME_UP and KEYCODE_BACK as normal event, meaning they should have the action forecasted ?
  • All other KeyEvent. should be passed to the onKeyDownEvent without triggering action ?

Regards

Florent75 avatar Aug 25 '22 10:08 Florent75

@Florent75 In the README of this library, in the Android section, you see various examples:

@Override // <--- Add this method if you want to react to keyDown
public boolean onKeyDown(int keyCode, KeyEvent event) {
  // A. Prevent multiple events on long button press
  //    In the default behavior multiple events are fired if a button
  //    is pressed for a while. You can prevent this behavior if you
  //    forward only the first event:
  //        if (event.getRepeatCount() == 0) {
  //            KeyEventModule.getInstance().onKeyDownEvent(keyCode, event);
  //        }
  //
  // B. If multiple Events shall be fired when the button is pressed
  //    for a while use this code:
  //        KeyEventModule.getInstance().onKeyDownEvent(keyCode, event);
  //
  // Using B.
  KeyEventModule.getInstance().onKeyDownEvent(keyCode, event);

  // There are 2 ways this can be done:
  //  1.  Override the default keyboard event behavior
  //    super.onKeyDown(keyCode, event);
  //    return true;

  //  2.  Keep default keyboard event behavior
  //    return super.onKeyDown(keyCode, event);

  // Using method #1 without blocking multiple
  super.onKeyDown(keyCode, event);
  return true;
}

The solution that I found was to override dispatchKeyEvent instead of onKeyDown. So in my MainActivity.java, I have

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
  // ...
}

instead of

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
  // ...
}

Then you have to adapt the code you had in onKeyDown for it to work as you like.

samzmann avatar Aug 26 '22 10:08 samzmann

@Florent75 I have same issue. I use eas build. Did you found workaround?

sergeushenecz avatar Oct 31 '22 15:10 sergeushenecz

@Florent75 Did the solution work for you. I tried it but now some of Pages keyboard is not working

Samamoah avatar Dec 15 '22 10:12 Samamoah

Did anyone found a solution for this? Barcode scanner clicks on touchables at the top of the screen

Sargnec avatar Feb 05 '23 14:02 Sargnec

@Sargnec my solution works for me. @kevinejohn issue can be closed as far as I'm concerned.

samzmann avatar Feb 05 '23 14:02 samzmann

@samzmann I just tried it and cant use the numbers on top of the device keyboard 💀

@Sargnec my solution works for me. @kevinejohn issue can be closed as far as I'm concerned.

Sargnec avatar Feb 05 '23 15:02 Sargnec

@Sargnec I can't use your solution because i use eas build and i can't modify code in the library.

sergeushenecz avatar Feb 05 '23 15:02 sergeushenecz

Hello, I'm facing same issues.

After a scan , normally it should navigate to a specific screen but before he clicks on my first tab.

Sometimes I am directly to the screen I want but the other times the first tab is being clicked and it is rendered.

AntoineTat1 avatar Feb 23 '23 13:02 AntoineTat1

1000x this! Overriding dispatchKeyEvent works perfectly. Would be great to get this into the docs and into the expo config plugin

tamagokun avatar Apr 06 '23 15:04 tamagokun

@samzmann I just tried it and cant use the numbers on top of the device keyboard 💀

@Sargnec my solution works for me. @kevinejohn issue can be closed as far as I'm concerned.

How to fix soft-keyboard numbers not entering

I found a work-around which should fix this issue. For some reason in certain circumstances numbers entered from the soft keyboard create events which trigger dispatchKeyEvent. We can modify @samzmann's code to instead check for the device ID the event originated from. Any soft-keyboard presses should generally have a device ID of -1, while actual hardware devices such as a keyboard or HID bluetooth barcode scanner will have a non-negative device ID.

@Override
public boolean dispatchKeyEvent(KeyEvent event) {

    // get the keyCode, since it is not directly passed by dispatchKeyEvent, unlike onKeyDown
    int keyCode = event.getKeyCode();

    // Handle soft keyboard events normally
    if (event.getDeviceId() == -1) {
        return super.dispatchKeyEvent(event);
    }

    // handle all other key events with the react-native-keyevent onKeyDownEvent handler
    if (event.getRepeatCount() == 0
            && event.getAction() == 0 // 0 means key down
    ) {
        KeyEventModule.getInstance().onKeyDownEvent(keyCode, event);
    }

    return true;
};

Keep in mind that from what I have read there is no guarantee that the soft keyboard will return -1 on all devices. I imagine a more robust solution would be to allow the user to enroll their scanner by listing available keyboards and letting them to select the scanner. We can then pass events from this input device to react-native-keyevent and allow events from other keyboards to be handled as normal. I have not tested a solution like this yet, so I'm not sure how feasible it is. Will update if I do.

shanebrowncs avatar Dec 23 '23 17:12 shanebrowncs