I have an onKeyDown Event which is supposed to display an image once triggered, but I have noticed that despite pressing the corresponding key several times, the image does not appear until I click anywhere on the canvas with my mouse. Any suggestions on the actual problem and how to proceed? Pretty new to the concept so not quite sure what may be missing.
*Edited and pasted class in its entirety.
Thanks
public class BuccaneerView extends TileView {
public static final int PLAYER = 1;
public static final int GREEN_STAR = 2;
Coordinate P_Location;
public BuccaneerView(Context context, AttributeSet attrs) {
super(context, attrs);
initBucc();
}
private void initBucc() {
this.setFocusable(true);
Resources r = this.getContext().getResources();
resetTiles(4);
loadTile(PLAYER, r.getDrawable(R.drawable.aerialplayer));
loadTile(GREEN_STAR, r.getDrawable(R.drawable.greenstar));
/**/
P_Location = new Coordinate(5,5);
setTile(PLAYER, P_Location.x, P_Location.y);
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent msg) {
if (keyCode == KeyEvent.KEYCODE_SPACE)
{
setTile(GREEN_STAR, 1, 0);
}
return super.onKeyDown(keyCode, msg);
}
public void update()
{
}
}
You seem to be treating onKeyDown as one of your on methods.
return super.onKeyDown(keyCode, msg);
Is a bad thing to do, its as if you have called this function and want to return what key has been pressed. Change it to simply be return false which will mean you are handling what they keyboard is doing.
EDIT
Is there any reason you use onKeyDown and not onKey? Here is some extra code which I use, it uses an array of booleans (pressedKeys, which is 128 in length) and you can later use it to check the array to see if a key is pressed
public boolean onKey(View v, int keyCode, KeyEvent event)
{
if (event.getAction() == android.view.KeyEvent.ACTION_DOWN)
{
if(keyCode > 0 && keyCode < 127)
pressedKeys[keyCode] = true;
}
if (event.getAction() == android.view.KeyEvent.ACTION_UP)
{
if(keyCode > 0 && keyCode < 127)
pressedKeys[keyCode] = false;
}
keyEventsBuffer.add(keyEvent);
}
return false;
}
So with this you can then say
If(pressedKeys[KeyYouWantToCheck])
{
//Do some stuff if that key is down
}
At a guess, the key event is not being delivered to whatever you have set the key listener on. This can happen if there is another view in between which is a listener and which stops the propagation of the key event (i.e. returning true from this method). There are some views which do this by default (e.g. EditText for most keys). It would be helpful if you could edit your question and include more code, or describe how your activity is setup.
By 'clicking on the canvas' you are probably changing the focus and making the key event being delivered to a different view. This could explain why you suddenly see the key listener working after clicking.
Related
This question already has answers here:
Detect two hardware button press simultaneously
(2 answers)
Closed 6 years ago.
public boolean onKeyDown(int keyCode, KeyEvent event){
if(keyCode==KeyEvent.KEYCODE_VOLUME_DOWN && keyCode==KeyEvent.KEYCODE_VOLUME_UP )
textView.setText("both buttons are pressed");
return true;
}
The problem is, when I use single comparison in if () then it works correctly. but when I use 2 comparison in single if() using && then it doesn't work. actually I want to perform action when volume up and volume down buttons are pressed at a same time.
onKeyDown() is fired twice when each key is pressed down. what you need is to use two individual if()s which increment an int onKeyDown that is initialised to zero and decrement it onKeyUp then also each check if the int is equal to 2 in onKeyUp, if true carry out an action u require which will be in a method you call
Sudo code:
int i = 0;
public void onKeyDown(int keyCode, KeyEvent event){
if(keyCode==KeyEvent.KEYCODE_VOLUME_DOWN){
i++;
}
if(keyCode==KeyEvent.KEYCODE_VOLUME_UP ){
i++;
}
if(i == 2 ){
action();
}
}
public void onKeyUp(int keyCode, KeyEvent event){
if(keyCode==KeyEvent.KEYCODE_VOLUME_DOWN){
i--;
}
if(keyCode==KeyEvent.KEYCODE_VOLUME_UP ){
i--;
}
}
private void action(){
// AND ACTION!!!
}
I am implementing GestureDetector.OnGestureListener in Activity,
whose overridden onTouchEvent is :
public boolean onTouchEvent(MotionEvent event) {
//gestureDetector is new GestureDetector(this,this) in Activity's onCreate()
this.gestureDetector.onTouchEvent(event);
return super.onTouchEvent(event);
}
Using getEdgeFlags from MotionEvent Class for edge detection as follows:
#Override
public boolean onDown(MotionEvent e) {
final int edgeInfo = e.getEdgeFlags();
return ((edgeInfo == MotionEvent.EDGE_LEFT) || (edgeInfo == MotionEvent.EDGE_RIGHT)) ||
(edgeInfo == MotionEvent.EDGE_BOTTOM);
}
But onDown always returns false.
I have also tried changing
final int edgeInfo = e.getEdgeFlags(); to
final int edgeInfo = e.getAction() & e.getEdgeFlags();
and also to final int edgeInfo = e.getActionMasked() & e.getEdgeFlags(); in case.
But to avail no benefit.
I have seen this question and this one, more relevant to me but I found that only
Only some older phones return non zero value
I should do it myself.
Am I Using API wrong?
Is there a better alternative to getEdgeFlags()?
Even if onDown is returning false,in logcat, I can still see other methods of GestureDetector.OnGestureListener getting fired,Why?
A little snippet would help if any.
I have a view which handles input for me, I pop up a keyboard and set the view focusable. Now I can get certain key presses...
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DEL) {
} else if (keyCode == KeyEvent.KEYCODE_BACK) {
} else if (keyCode == KeyEvent.KEYCODE_ENTER) {
} else {
}
}
and so on... the character pressed I get by using
event.getDisplayLabel()
That works as long as I only want the normal letters A-Z.
In other languages, more letters can be reached by long pressing a normal letter on the soft keyboard... however, these alternative letters cannot be detected by onKeyDown/Up. I can only detect the normal letters, the labels of the soft keyboard.
Now my app has to process foreign input and letters, I have changed the keyboard to turkish and I can find letters like í ì ú ù on the keyboard, but if I press them, I don't get any response. Not with event.getDisplayLabel nor event.getUnicodeChar();
How do I detect these letters?
When the keyboard is open, onKeyDown() and onKeyUp() methods don't work properly because Android considers on-screen keyboard as a separate activity.
The easiest way to achieve what you want is to override onKeyPreIme() method on your view. For example, if you're trying to capture onKeyDown from an EditText, create a new Class which extends EditText, and override the onKeyPreIme() method:
public class LoseFocusEditText extends EditText {
private Context mContext;
protected final String TAG = getClass().getName();
public LoseFocusEditText(Context context) {
super(context);
mContext = context;
}
public LoseFocusEditText(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
}
public LoseFocusEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mContext = context;
}
#Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
//hide keyboard
InputMethodManager mgr = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
mgr.hideSoftInputFromWindow(this.getWindowToken(), 0);
//lose focus
this.clearFocus();
return true;
}
return false;
}
}
This was tested on kitkat / htc one.
Edit:
I'm not sure what is causing the onKeyDown not to be called at all. Perhaps it's an issue with your view? There may be a better answer than my solution because of this. Either way, this might work:
Instead of using the onKeyDown from the view, override dispatchKeyEvent at the activity level. This will handle your key event before it gets to the window manager, so make sure to call super on any key events you do not explicitly handle.
Example using the ACTION_DOWN (as every event has both ACTION_UP and ACTION_DOWN) since your example used onKeyDown:
#Override
public boolean dispatchKeyEvent(KeyEvent event){
if(event.getAction() == KeyEvent.ACTION_UP) {
return super.dispatchKeyEvent(event);
}
if (keyCode == KeyEvent.KEYCODE_DEL) {
} else if (keyCode == KeyEvent.KEYCODE_BACK) {
} else if (keyCode == KeyEvent.KEYCODE_ENTER) {
} else {
return super.dispatchKeyEvent(event);
}
}
NOW (sorry about that)
You can try:
char key = (char)event.getUnicodeChar();
Instead of
char key = event.getDisplayLabel();
getDisplayLabel() will only give you the key that is displayed on the keyboard, which as you point out, is not necessarily the character the user has selected.
Got it :)
public boolean onKey(View v, int keyCode, KeyEvent event) {
if(event.getAction()==KeyEvent.ACTION_DOWN) return true;
if(keyCode==KeyEvent.KEYCODE_ALT_LEFT || keyCode==KeyEvent.KEYCODE_ALT_RIGHT || keyCode==KeyEvent.KEYCODE_SHIFT_LEFT || keyCode==KeyEvent.KEYCODE_SHIFT_RIGHT) return true;
if (keyCode == KeyEvent.KEYCODE_DEL) {
doBackspace();
return true;
} else if (keyCode == KeyEvent.KEYCODE_BACK) {
if(this.avl!=null) this.avl.onInputCancelled(this);
return false;
} else if (keyCode == KeyEvent.KEYCODE_ENTER) {
inputstarted=false;
if(this.avl!=null) this.avl.onInputFinished(this,this.text,celldata);
return true;
}
String key = "";
if (event.getAction()==KeyEvent.ACTION_UP) key = String.valueOf((char)event.getUnicodeChar()).toUpperCase();
else if (event.getAction()==KeyEvent.ACTION_MULTIPLE) key = String.valueOf(event.getCharacters()).toUpperCase();
return process(key);
}
The important part is blocking the ALT_LEFT/SHIFT_LEFT/etc keycodes and differentiate between ACTION_UP/ACTION_MULTIPLE and either use event.getUnicodeChar() or event.getCharacters().
It works now, I can get all of the chars and even KEYCODE_DEL works on the mobile. But on the tablet I still get no callback for the delete key. Seems like a bad bug, as today in the morning it worked fine even on tablet.
I have a custom WebView and I want to simulate a click when I get a MotionEvent.ACTION_DOWN. I don't want to have any kind of input on the WebView , I must not even make it clickable(.setClickable(false)). So what i have done is override the onTouchEvent() in my custom WebView to return false.
this works fine but I'm missing the click. I have seen in the source code of WebView that it send messages to class called WebViewCore but this communication is done differently in every version of android.
Does anyone knows how can I programmatically send a click to a webView?
Here is what I'm trying to do:
public class VoidWebView extends WebView {
public VoidWebView(Context context) {
super(context);
}
public VoidWebView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN){
//tell the webview that a click has been performed , it doesn't matter where the click happened
}
return false;
}
}
I think you are looking for the performClick() method of the View.
You can get some more information here.
Pass up and down event to super class.
#Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
if(action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_UP){
super.onTouchEvent(event);
return true;
}
return false;
}
I am using a keylistener to get key taps. The problem is that once you tap the delete key, the next key tap is not registering. The key tap after that keeps working. If I tap 2 deletes in a row, they work, just no other keys. They just disappear.
I put in a log test before the "if (keycode" section and it shows nothing after the first delete is pressed, unless it is another delete.
I am using the following code (Thanks Shawn).:
itemPrice.setKeyListener(new CalculatorKeyListener());
itemPrice.setRawInputType(Configuration.KEYBOARD_12KEY);
class CalculatorKeyListener extends NumberKeyListener {
public int getInputType() {
return InputType.TYPE_CLASS_NUMBER;
}
#Override
public boolean onKeyDown(View view, Editable content, int keyCode, KeyEvent event)
{
if (keyCode >= KeyEvent.KEYCODE_0 && keyCode <= KeyEvent.KEYCODE_9) {
digitPressed(keyCode - KeyEvent.KEYCODE_0);
} else if (keyCode == KeyEvent.KEYCODE_DEL) {
deletePressed();
}
return true;
}
#Override
protected char[] getAcceptedChars() {
return new char[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
}
}
With this problem the keylistener provides no value to me. There must be something that I am missing.
Thanks,