Catch Keypress with Android

Catch keypress with android

You can either handle key events from a view or in general for your whole application:

Handle onKey from a View:

public boolean onKey(View v, int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_ENTER:
/* This is a sample for handling the Enter button */
return true;
}
return false;
}

Remember to implement OnKeyListener and to set your listener YourView.setOnKeyListener(this);

The second possibility would be:

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_MENU:
/* Sample for handling the Menu button globally */
return true;
}
return false;
}

You could also ta a look at onKeyUp.

Resource: http://developer.android.com/reference/android/view/View.html

And here you can see a list with all KeyEvents

Android:how to get any KeyPress event with example?

Answer to this question should be twofold. It is determined by the way how the key was generated. If it was press on the hardware key, then both approaches described below are valid. If it was press on the software key, then it depends on actual context.

1.) If key was result of the pressing on the soft keyboard that was obtained by long press on the Menu key:

You need to carefully override the following function:

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

switch (keyCode) {
case KeyEvent.KEYCODE_A:
{
//your Action code
return true;
}
}
return super.onKeyDown(keyCode, event);
}

2.) If your activity contains EditText, and softkeyboard was obtained from it, then first approach does not work because key event was already consumed by EditText. You need to use text changed Listener:

mMyEditText.addTextChangedListener(new TextWatcher()
{
public void afterTextChanged(Editable s)
{
}
public void beforeTextChanged(CharSequence s, int start, int count, int after)
{
/*This method is called to notify you that, within s, the count characters beginning at start are about to be replaced by new text with length after. It is an error to attempt to make changes to s from this callback.*/
}
public void onTextChanged(CharSequence s, int start, int before, int count)
{
}
);

How to make KeyDown and KeyUp on android device?

I'd say, that OnKeyUp & OnKeyDown events won't cut it, because soft keyboards barely emit any of these. Here's a rough prototype, which filters the input of characters according to the expected string. there is lots of space for improvement; while a custom implementation is still a better approach than trying to use framework methods, which may only catch the key... the FilteredEditText catches any input before it may appear on screen - in order to realize a keystroke pattern recorder, the expected string would need to be split into an ArrayList, which would also hold the duration in between the individual keystrokes; once recorded one can use the gathered information for comparison.

/**
* Filtered {@link AppCompatEditText}
* @author Martin Zeitler
*/
public class FilteredEditText extends AppCompatEditText {

private static final String LOG_TAG = FilteredEditText.class.getSimpleName();

private String expectedString = null;

public FilteredEditText(Context context) {
super(context);
}

public FilteredEditText(Context context, AttributeSet attrs) {
super(context, attrs);
}

public FilteredEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}

public void setExpectedString(@NonNull String value) {
this.expectedString = value;
this.setupInputFilter();
}

public void setupInputFilter() {
this.setFilters(new InputFilter[] {
new InputFilter() {
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int destStart, int destEnd) {
if (source.length() > 0 && source.charAt(end-1) == expectedString.charAt(destEnd)) {

/* valid input received */
Log.d(LOG_TAG, "input accepted: " + String.valueOf(source.charAt(end-1)));
return source;

} else {

/* invalid input received */
Log.d(LOG_TAG, "input rejected: " + String.valueOf(source.charAt(end-1)) + " - expected: " + String.valueOf(expectedString.charAt(destEnd)));
return "";
}
}
}
});
}

/** hardware event */
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
Log.d(LOG_TAG, "onKeyDown()");
return super.onKeyDown(keyCode, event);
}

/** hardware event */
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
Log.d(LOG_TAG, "onKeyUp()");
return super.onKeyUp(keyCode, event);
}
}

Usage example:

FilteredEditText mTextInput = findViewById(R.id.text_input);
mTextInput.setExpectedString("9RJhl6aH0n");

Logcat output:

D/FilteredEditText: input accepted: 9
D/FilteredEditText: input rejected: r - expected: R
D/FilteredEditText: input rejected: 4 - expected: R
D/FilteredEditText: input accepted: R

So far I've tested it with a software keyboard ...while I currently cannot test it with a BT hardware keyboard, because the batteries are empty. I'd assume, that the InputFilter catches all input.

That barely any OnKeyUp and OnKeyDown event is being triggered by software keyboards can be compensated, because when knowing when a keystroke is being filtered, this still leads to a comparable pattern - even if the duration of the keystroke cannot be measured, nor the attack velocity of the keystroke, due to the limitations of a software keyboard - the only possible workarounds would be enforcing hardware keyboards or creating a software keyboard which emits these events for all the keys (contrary to the default GBoard, nor SwiftKey). I'd just wonder about swipe-typing and voice-typing now ... because this is something barely considered by physical keystroke dynamics. even left a feedback for GBoard, because optionally emitting key-codes would be helpful in some cases.

The documentation also clearly states it:

When handling keyboard events with the KeyEvent class and related APIs, you should expect that such keyboard events come only from a hardware keyboard. You should never rely on receiving key events for any key on a soft input method (an on-screen keyboard).

One can still use hardware events, while having buttons, which emit them; for example:

/**
* Fake Hardware {@link AppCompatButton}
* @see <a href="https://developer.android.com/reference/android/view/KeyEvent">KeyEvent</a>
* @author Martin Zeitler
*/
public class FakeHardwareButton extends AppCompatButton {

private BaseInputConnection mInputConnection;

private int keyCode = KeyEvent.KEYCODE_9;
private KeyEvent keyDown;
private KeyEvent keyUp;

public FakeHardwareButton(Context context) {
this(context, null);
}

public FakeHardwareButton(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public FakeHardwareButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}

@SuppressLint("ClickableViewAccessibility")
private void setupInputConnection(View targetView) {

this.mInputConnection = new BaseInputConnection(targetView, true);
this.keyDown = new KeyEvent(KeyEvent.ACTION_DOWN, this.keyCode);
this.keyUp = new KeyEvent(KeyEvent.ACTION_UP, this.keyCode);

this.setOnTouchListener(new View.OnTouchListener() {

@Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
mInputConnection.sendKeyEvent(keyDown);
return true;

case MotionEvent.ACTION_UP:
mInputConnection.sendKeyEvent(keyUp);
return true;
}
return false;
}
});
}
}

The issue is just, that eg. KeyEvent.KEYCODE_9 and KeyEvent.KEYCODE_NUMPAD_9 are not the same, therefore one always has to compare the String representation in case of numeric keys.

Android - Get keyboard key press

For handling hardware keys and Back key you could use dispatchKeyEvent(KeyEvent event) in your Activity

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
Log.i("key pressed", String.valueOf(event.getKeyCode()));
return super.dispatchKeyEvent(event);
}

UPD: unfortunately you can't handle soft keyboard events (see Handle single key events), unless you develop your own custom keyboard (follow the link to learn how Creating input method).

How to catch a Done key press from the soft keyboard

Note: This answer is old and no longer works. See the answers below.

You catch the KeyEvent and then check its keycode. FLAG_EDITOR_ACTION is used to identify enter keys that are coming from an IME whose enter key has been auto-labelled "next" or "done"

if (event.getKeyCode() == KeyEvent.FLAG_EDITOR_ACTION)
//your code here

Find the docs here.



Related Topics



Leave a reply



Submit