Android Question Detect keypress regardless of focussed view

JdV

Active Member
Licensed User
Longtime User
Hello

Is it possible to detect a keypress event regardless of which view currently has focus?

In a simple app I can rely on Activity_KeyPress. For an app which is displaying a web view however, once the user starts interacting with the web view it seems to consume all key press events.

I want to be able to detect more than just the back or home keys being pressed.

Regards

Joe
 

JdV

Active Member
Licensed User
Longtime User
Thanks for the reply.

Can you give me an example? The only events I can see for the standard webview are OverrideUrl, PageFinished and UserAndPasswordRequired.
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
I want to be able to detect more than just the back or home keys being pressed.
See this answer
 
Upvote 0

Ivica Golubovic

Active Member
Licensed User
Or use UltimateWebView library, it has OnKeyEvent event.

 
Upvote 0

JdV

Active Member
Licensed User
Longtime User
Your library looks very fully featured. It would appear that all I want in this case is to intercept/handle the webview's onKeyEvent.
 
Upvote 0

Ivica Golubovic

Active Member
Licensed User
As I promised yesterday, here is the code.

Add the following lines to Activity_Create:

Example::
Dim jo As JavaObject=WebView1
Dim KeyEvent As Object = jo.CreateEvent("android.view.View.OnKeyListener", "OnKeyListener", False) 'Creates KeyListener interface and OnKeyListener event; False-default return value
jo.RunMethod("setOnKeyListener", Array As Object(KeyEvent)) 'Set KeyListener interface to view (in this case WebView)

Add the following Sub somewhere in the code:

Example::
Private Sub OnKeyListener_Event (MethodName As String, Args() As Object) As Object
    Log(MethodName)
    'Args(0) - View which trigered event, Args(1) - pressed key code, Args(2) - android.view.KeyEvent
    Dim KeyCode As Int=Args(1)
    Dim AndroidViewKeyEvent As JavaObject=Args(2)
    Dim KeyCodeString As String=AndroidViewKeyEvent.RunMethod("keyCodeToString",Array(KeyCode))
    Log(KeyCodeString & "=" & KeyCode)
    Return False 'Or return True to consume event.
End Sub
 
Upvote 0

JdV

Active Member
Licensed User
Longtime User
I've input the code into a simple app (attached) but the event isn't firing when I press anything on the keyboard. The web view responds to the keyboard inputs though.
 

Attachments

  • WebViewButtons.zip
    9.1 KB · Views: 133
Upvote 0

JdV

Active Member
Licensed User
Longtime User
The web page being displayed won't necessarily have any input fields.

I have a physical keyboard and I just want to intercept all input.
 
Upvote 0

Ivica Golubovic

Active Member
Licensed User
Okay, I didn't understand you right away at first time. Your problem is hard to solve with a classic WebView object, and here's why:

1. In order to catch the key when entering text in the text field, you must enter the javascript code and the javascrip interface through which you will capture the event.

2. To capture the key when your webview is in focus but you are not typing text in the field, you need to implement WebViewClient through which you will capture the onUnhandledKeyEvent event.

So there is no simple solution. It takes a lot of java and javascript programming.
 
Upvote 0

drgottjr

Expert
Licensed User
Longtime User
in the interest of science, here is 1 way to demonstrate
how keystrokes behave with a webview. a zipped
example is attached.

it could be used in connection with a library. for the
purposes of a demonstration, it is standalone. there
are also other ways to achieve the same end. in fact,
in a production environment, you would most likely
need a library or know how to write your own
complete webviewclient*. but based on the
description of the problem as posted above, this
example solves that problem.

there are 2 views in the example: a webview and an edittext.
they each occupy 1/2 the screen. the idea is to show what
happens to your keystrokes when one view or the other has
the focus.

the correct way to use the example is to tap on one view
to get its focus. tap a few keys slowly. tap the
other view to gain its focus and tap a few keys
slowly. 1 or 2 keystrokes will suffice. you will see what
you need to see in the log. if you start typing wildly, the
log will quickly run off the screen, and you won't see how
the strokes are being monitored.

when the edittext is in focus, you should see the
log reporting normal typing (as expected).

when the webview is in focus, it behaves similarly,
"capturing" the keystrokes for itself. this is fine if you
are, in fact, filling in a form in the webview. but not fine
if you want to use the keyboard as a trigger to unfocus
the webview and do something else. this, i believe is
what the op was describing

you have to override that default behavior in order for your
app to see the strokes and decide if certain strokes are actually
meant for something else in your app. (this is not unlike the
shouldOverrideUrlLoading() method that some of us who use
a webview may be familiar with.)

this is done by raising an event when the webview
detects keyboard activity. instead of keeping the
strokes for itself, it will pass the stroke to your
app. if the app wants the keystroke for itself,
it returns "true" to the webview. if the app is not
interested in the keystroke, it returns "false" to
the webview. false causes the webview to keep
the keystroke for its own use, if any.

in this case, i tell the app to ignore all keystrokes
coming from the webview, except for the letter
"O" (for override). i show it in the log. i could
do something else. i could have chosen a different
key. in fact, under normal circumstances, the
magic key would not be one used in normal typing,
otherwise you would not be able to type the letter
"O", although, technically, you could intercept the
"O" and still return false, but we can leave that for
a different discussion.

*technically, it is a webview's webviewclient that
intercepts the keystroke. so you have to add a custom
webviewclient to your webview. a webview can have
only 1 webviewclient. if you use a library that supplies
its own webviewclient, you cannot add your own unless
you only want this 1 method. and you cannot create
your own webviewclient and then add a library which has
its own webviewclient. if your library exposes a
webviewclient's shouldInterceptKeyStroke() method,
read its documentation on how to handle the event in
b4a.
 

Attachments

  • key.zip
    7.8 KB · Views: 121
  • key.png
    key.png
    42.3 KB · Views: 135
  • key2.png
    key2.png
    36.3 KB · Views: 110
Upvote 0

JdV

Active Member
Licensed User
Longtime User
Thanks everyone for your replies and help with this.

For the purpose of my app I've decided to cheat:
- I put a transparent panel in front of the webview to prevent interaction with it
- I set the focus to the panel in the PageFinished event
- I use Ivica's code to capture keypresses
- Any keypresses I'm not interested in are ignored

This works for me as the web pages are static and shouldn't require any interaction.
 
Upvote 0

JdV

Active Member
Licensed User
Longtime User
in the interest of science, here is 1 way to demonstrate
how keystrokes behave with a webview. a zipped
example is attached.

it could be used in connection with a library. for the
purposes of a demonstration, it is standalone. there
are also other ways to achieve the same end. in fact,
in a production environment, you would most likely
need a library or know how to write your own
complete webviewclient*. but based on the
description of the problem as posted above, this
example solves that problem.

there are 2 views in the example: a webview and an edittext.
they each occupy 1/2 the screen. the idea is to show what
happens to your keystrokes when one view or the other has
the focus.

the correct way to use the example is to tap on one view
to get its focus. tap a few keys slowly. tap the
other view to gain its focus and tap a few keys
slowly. 1 or 2 keystrokes will suffice. you will see what
you need to see in the log. if you start typing wildly, the
log will quickly run off the screen, and you won't see how
the strokes are being monitored.

when the edittext is in focus, you should see the
log reporting normal typing (as expected).

when the webview is in focus, it behaves similarly,
"capturing" the keystrokes for itself. this is fine if you
are, in fact, filling in a form in the webview. but not fine
if you want to use the keyboard as a trigger to unfocus
the webview and do something else. this, i believe is
what the op was describing

you have to override that default behavior in order for your
app to see the strokes and decide if certain strokes are actually
meant for something else in your app. (this is not unlike the
shouldOverrideUrlLoading() method that some of us who use
a webview may be familiar with.)

this is done by raising an event when the webview
detects keyboard activity. instead of keeping the
strokes for itself, it will pass the stroke to your
app. if the app wants the keystroke for itself,
it returns "true" to the webview. if the app is not
interested in the keystroke, it returns "false" to
the webview. false causes the webview to keep
the keystroke for its own use, if any.

in this case, i tell the app to ignore all keystrokes
coming from the webview, except for the letter
"O" (for override). i show it in the log. i could
do something else. i could have chosen a different
key. in fact, under normal circumstances, the
magic key would not be one used in normal typing,
otherwise you would not be able to type the letter
"O", although, technically, you could intercept the
"O" and still return false, but we can leave that for
a different discussion.

*technically, it is a webview's webviewclient that
intercepts the keystroke. so you have to add a custom
webviewclient to your webview. a webview can have
only 1 webviewclient. if you use a library that supplies
its own webviewclient, you cannot add your own unless
you only want this 1 method. and you cannot create
your own webviewclient and then add a library which has
its own webviewclient. if your library exposes a
webviewclient's shouldInterceptKeyStroke() method,
read its documentation on how to handle the event in
b4a.
This solution is brilliant.

However I noticed that each keypress is logged twice. Is there any way to suppress the second keypress?
 
Upvote 0

Ivica Golubovic

Active Member
Licensed User
These are two events for the same key, just different actions (ACTION_DOWN and ACTION_UP). You only need to filter one event in java code, for example ACTION_DOWN.

Example:
if (event.getAction() == KeyEvent.ACTION_DOWN){
//Rest of code
}else{
return false;
}
 
Last edited:
Upvote 0

JdV

Active Member
Licensed User
Longtime User
These are two events for the same key, just different actions (ACTION_DOWN and ACTION_UP). You only need to filter one event in java code, for example ACTION_DOWN.

Example:
if (event.getAction() == KeyEvent.ACTION_DOWN){
//Rest of code
}else{
return false;
}
I've added this to the #if Java block:

B4X:
         if (b != null && event.getAction() == KeyEvent.ACTION_UP) {
               return( b.booleanValue() );
         } else {
            return(false);
         }

But I'm still getting two messages for each keypress.
 
Upvote 0

Ivica Golubovic

Active Member
Licensed User
I've added this to the #if Java block:

B4X:
         if (b != null && event.getAction() == KeyEvent.ACTION_UP) {
               return( b.booleanValue() );
         } else {
            return(false);
         }

But I'm still getting two messages for each keypress.
No, no, no. Whole event code inside IF statement.

public boolean shouldoverride....
If (event.getAction....
// whole event code
} else{
return false;
}

Sorry, I don't have a computer on hand so I'm typing the code on my phone.
 
Upvote 0

drgottjr

Expert
Licensed User
Longtime User
i see this one is still clinging to life. mea culpa. ivicagolubovic's fix works fine. if you don't want to deal with it yourself, here's an updated version.

before withdrawing, i want to mention yet again that this solution only works so long as you do not get the bright idea of using a webview-related library which does not have this snippet (or something similar) in it.

i tried my updated version before uploading. i'm not seeing the up and down. just the down.
 

Attachments

  • key.zip
    7.8 KB · Views: 117
Upvote 0
Top