I'm making a remote app that requires a keyboard. I'm not using an EditText, I am forcing it to invoke pragmatically.
In the activity, I have a semi intelligent onKeyDown code that translates the android keycode into the ascii code processable by my server and sends it:
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
int asciiKey = -1;
if (keyCode >= KeyEvent.KEYCODE_A && keyCode <= KeyEvent.KEYCODE_Z) {
asciiKey = keyCode - KeyEvent.KEYCODE_A + 'A';
} else if (keyCode==KeyEvent.KEYCODE_DEL) {
asciiKey = 8;
} else if (keyCode==KeyEvent.KEYCODE_ENTER) {
asciiKey = 13;
} else {
asciiKey = event.getUnicodeChar(event.getMetaState());
}
out.println("k "+asciiKey);
return super.onKeyDown(keyCode, event);
}
But when I press the Enter key, it's not sending (I've tried the Jelly Bean Default and Hacker's Keyboard). Not even a "-1". The method isn't even being called. It works for most other keys (Numbers, Letters, Backspace, Some Symbols) so it's not the app itself.
The code that invokes the keyboard and hides it later:
InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
Is there something I'm missing? Also, is there a better way to translate Android keycodes into Ascii keys (specifically replicatable by java.awt.Robot).
Thanks for any help in advance.
Use this function to capture the enter key too.
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
try
{
//
if(event.getAction()== KeyEvent.ACTION_UP)
{
System.out.println(event.getAction() + " " + event.getKeyCode() + " - " + (char) event.getUnicodeChar());
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
return true;
}
Try logging the keycode
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
Log.d("KeyEvent", Integer.toString(KeyEvent.getKeyCode()));
return super.onKeyDown(keyCode, event);
}
Than go here to look up the keycode KeyEvent
Related
I am writing a game where you keep pressing the screen to let a helicopter fly. Now when the helicopter collides with the screen-borders (Hight & width of individual device) the activity finishes by
((Activity) context).finish();
It works perfectly fine when the player stops fastly after the collision, but if he holds on, I get the hated error.
Thant's why I suspect the onTouchEvent-method
#Override
public boolean onTouchEvent(MotionEvent event) {
// background music
mp.start();
mp.setLooping(true);
copter.setVolume((float) 0.2, (float) 0.2);
if (event.getAction() == MotionEvent.ACTION_DOWN && fuel > 0) {
copter.start();
copter.setLooping(true);
if (!player.getPlaying()) {
player.setPlaying(true);
player.setUp(true);
fuel--;
} else {
player.setUp(true);
fuel--;
}
return true;
}
if (event.getAction() == MotionEvent.ACTION_UP) {
copter.pause();
player.setUp(false);
return true;
}
return super.onTouchEvent(event);
}
Is there some way to ignore TouchEvents after a collision? Or is the OnTouchEvent not even the problem?
Check if Activity is null inside onTouchEvent()
Here the code:
#Override
public boolean onTouchEvent(MotionEvent event) {
Activity activity = getActivity();
if(activity != null){
// background music
mp.start();
mp.setLooping(true);
copter.setVolume((float) 0.2, (float) 0.2);
if (event.getAction() == MotionEvent.ACTION_DOWN && fuel > 0) {
copter.start();
copter.setLooping(true);
if (!player.getPlaying()) {
player.setPlaying(true);
player.setUp(true);
fuel--;
} else {
player.setUp(true);
fuel--;
}
return true;
}
if (event.getAction() == MotionEvent.ACTION_UP) {
copter.pause();
player.setUp(false);
return true;
}
return super.onTouchEvent(event);
}
//return super.onTouchEvent(event);
return false;
}
Depending on your code you should use:
if(((Activity)context) != null){
instead of
Activity activity = getActivity();
if(activity != null){
If this is not the problem, please add the error stacktrace.
Update
To send stacktrace via e-mail:
Intent mailIntent = new Intent(Intent.ACTION_SENDTO);
mailIntent.setData(Uri.parse("mailto:"));
mailIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{"mail#gmail.com"});
mailIntent.putExtra(Intent.EXTRA_SUBJECT, "Subject");
mailIntent.putExtra(Intent.EXTRA_TEXT, stacktraceText);
Intent mailChooserIntent = Intent.createChooser(mailIntent, "Title");
context.startActivity(mailChooserIntent);
I'm developing an Android app in Java which must detect events from a real mouse connected in USB, and send them over the network to a computer which will use those events.
My problem : I can detect mouse wheel button events (scroll, pressed, released), but when the user presses the wheel button, the app exits, and the callback is called afterwards.
My question : is it possible to catch the event before the app exits, and prevent the default behavior ? If so, how ? Why do I catch the event too late ?
Here is the functios declared in my activity :
#Override
public boolean onGenericMotionEvent(MotionEvent event) {
int action = MotionEventCompat.getActionMasked(event);
int pointerId = event.getPointerId(0);
if (event.getAction() == MotionEvent.ACTION_HOVER_MOVE) {
Log.d(name, "onGenericMotionEvent : MotionEvent.ACTION_HOVER_MOVE " + MotionEvent.ACTION_HOVER_MOVE);
return true;
} else if (event.getAction() == MotionEvent.ACTION_SCROLL) {
Log.d(name, "onGenericMotionEvent : MotionEvent.ACTION_SCROLL " + MotionEvent.ACTION_SCROLL);
return true;
} else if (event.getAction() == MotionEvent.ACTION_HOVER_EXIT) {
Log.d(name, "why does is happen after onPause ??? onGenericMotionEvent : MotionEvent.ACTION_HOVER_EXIT " + MotionEvent.ACTION_HOVER_EXIT);
return true;
} else {
//Log.d(name, "onGenericMotionEvent : " + MotionEvent.actionToString(event.getAction()) + " " + event.getAction());
}
return super.onGenericMotionEvent(event);
}
And here is how I prevented mouse right click from closing the app :
public boolean onKeyUp(int keyCode, KeyEvent event) {
int source = event.getSource();
boolean mouseRightButton = false;
if (source == InputDevice.SOURCE_TOUCHSCREEN) {
Log.e(name, "onKeyUp from touchscreen");
} else if (source == InputDevice.SOURCE_MOUSE) {
Log.e(name, "onKeyUp from mouse");
if (keyCode == KeyEvent.KEYCODE_BACK) {
Log.e(name, "right click");
mouseRightButton = true;
return true;
}
}
}
Thanks for your help
Return true if you have handled the event. Don't propagate it forward. The app will not close that way.
i have a problem with handling back button in my game on android, developed on MonoGame with MonoDroid. I can't catch back button click event.
I tried:
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
{
LoadingScreen.Load(ScreenManager, true, null, new BackgroundScreen(),
new LevelSelectScreen());
}
And on main Activity
public override bool OnKeyUp(Keycode keyCode, KeyEvent e)
{
if (keyCode == Keycode.Back)
{
...
return true;
}
return base.OnKeyDown(keyCode, e);
}
public override void OnBackPressed()
{
...
Toast.MakeText(this, keyCode + " key! + " + keyCode.ToString(), ToastLength.Short).Show();
}
public override bool OnKeyDown(Keycode keyCode, KeyEvent e)
{
if (keyCode == Keycode.Back)
{
...
return true;
}
return base.OnKeyDown(keyCode, e);
}
Nothing helps, on WP first variant works perfectly
YEAH!
I found solution:
When you call
GamePad.GetState(PlayerIndex.One)
in Android GamePadState cleared
public static GamePadState GetState(PlayerIndex playerIndex)
{
var instance = GamePad.Instance;
var state = new GamePadState(new GamePadThumbSticks(), new GamePadTriggers(), new GamePadButtons((Buttons)instance._buttons), new GamePadDPad());
instance.Reset(); // <- CLEAR BUTTONS
return state;
}
So, do not call GetState in Android several times.
I have edited the SoftKeyboard IME Android sample code to pass a custom KeyEvent to my application.
I do this using this KeyEvent Constructor:
private void handleCharacter(int primaryCode, int[] keyCodes) {
if (isInputViewShown()) {
if (mInputView.isShifted()) {
primaryCode = Character.toUpperCase(primaryCode);
}
}
if (isAlphabet(primaryCode)) {
String characterString = new String();
for (int c : keyCodes) {
characterString += (char)c;
}
Log.e(TAG, "sending: " + characterString);
KeyEvent ke = new KeyEvent(SystemClock.uptimeMillis(),
characterString, 0, KeyEvent.FLAG_CANCELED);
getCurrentInputConnection().sendKeyEvent(ke);
}
}
In my Application, I have a CustomTextView that I have set up following this thread, and I've written the onKey() thus:
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
Log.d(TAG, "onKeyListener");
CustomEditor context = (CustomEditor) mWeakContext.get();
assertNotNull("Context invalid", context);
if (event.getAction() == KeyEvent.ACTION_UP) {
if (keyCode == KeyEvent.KEYCODE_DELETE) {
// Handle delete.
return true;
}
if (keyCode == KeyEvent.KEYCODE_SPACE) {
// Handle space.
return true;
}
}
// Ignore all non-custom Events.
if (event.getAction() != KeyEvent.ACTION_MULTIPLE) {
return true;
}
if (keyCode == KeyEvent.KEYCODE_UNKNOWN) {
Log.e(TAG, event.toString());
// Pull out characters.
final String chars = event.getCharacters();
if (chars != null) {
// Do some stuff. This is never called!
}
}
return true;
}
However event.getCharacters() never returns a non-null String! Is there something here that I'm missing? There is not much documentation governing the use of this specific KeyEvent constructor that I'm trying to manipulate to my own ends.
EDIT:
It seems likely that the KeyEvent.writeToParcel(...) function does not parcel the character string, and so that data is lost when the KeyEvent is sent to the TextView.
I experimented with marshaling and unmarshaling a KeyEvent constructed in this way and in fact the string is no longer there. This behaviour is very strange. Does anyone know why this is?
...
KeyEvent ke = new KeyEvent(SystemClock.uptimeMillis(),
characterString, 0, KeyEvent.FLAG_CANCELED);
// Drop it into a parcel
Parcel p = Parcel.obtain();
ke.writeToParcel(p, 0);
// Get it out of this parcel.
KeyEvent kee = KeyEvent.CREATOR.createFromParcel(p);
Log.e(TAG, "unparcelled cstring: " + kee.getCharacters());
... (etc)
The last log statement always produces null.
i have an application which has this layout. now when the user touches some button and releases his finger from that button, the key is entered into the textbox. mean while it also pronounces that letter to the user. saying "B is entered". so it is during ACTION_UP. during this event handling i need to prevent touch events even if by accident the user touches them.
i am disabling the touchlistener during touch events(in UP state), but it is not happening.The touch events are getting queued and i am not getting how to disable the touch event while the current one is being handled.but i could able to accomplish it during the hardkeys event handling. i could not understand this weird behavior.
here is my code
public boolean onTouch(View v, MotionEvent event)
{
// TODO Auto-generated method stub
String s = null;
s = ((Button) v).getText().toString().trim();
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
b_prev=(Button)v;
//while(tts.isSpeaking());
tts.speak(s, TextToSpeech.QUEUE_FLUSH, null);
break;
case MotionEvent.ACTION_UP:
fun(false); //disabling the touch event for all buttons
for(int i=0;i<mybtn.length;i++)
{
if(isPointInsideView(event.getRawX(),event.getRawY(),mybtn[i]))
{
s = (mybtn[i]).getText().toString().trim();
btn=mybtn[i];
break;
//et.setText("up android" + s, TextView.BufferType.EDITABLE);
}
}
if(btn.equals(mybtn[27])) //clear button pressed
{
//do something
}
else if(btn.equals(mybtn[26])) //space button
{
//do soemthing
}
else
{
//do soemthing
}
fun(true); //enabling touch event for all buttons
break;
case MotionEvent.ACTION_MOVE:
for(int i=0;i<mybtn.length;i++)
{
if(isPointInsideView(event.getRawX(),event.getRawY(),mybtn[i]))
{
s = (mybtn[i]).getText().toString().trim();
btn=mybtn[i];
break;
//et.setText("down android" + s, TextView.BufferType.EDITABLE);
}
}
break;
}
return true;
}
void fun(boolean flag)
{
int i;
for(i=0;i<mybtn.length;i++)
{
if(flag==true)
mybtn[i].setOnTouchListener(this);
else
mybtn[i].setOnTouchListener(null);
mybtn[i].setEnabled(flag);
}
}
Even though i am disabling the touch events using fun(), they are getting queued and executing after the completion of current touch event. so please tell me what i need to do to fix this problem.
i have made an observation that i am using two hardkeys in confirmation events.during hard key events the disabling/enabling of layout buttons is working fine. But it is not working same in the above scenario. what could be the problem with it? i am attaching that code as well. look at it.why this is happening i am not getting.
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_SEARCH
&& event.getRepeatCount() == 0)
{
String s = et.getText().toString().trim();
fun(false); //disable touch events
if(pass==1 && quit==1)
{
name= et.getText().toString().trim();
number=get_Number(name);
if(number!=null)
{
pass++; // go for confirmation
in = new Intent(ContactActivity.this, Calling.class);
tts.speak("contact found", TextToSpeech.QUEUE_FLUSH, null);
while(tts.isSpeaking());
tts.speak("Do u want to continue", TextToSpeech.QUEUE_FLUSH, null);
while(tts.isSpeaking());
}
else
{
tts.speak( name +"does not exist", TextToSpeech.QUEUE_FLUSH, null);
while(tts.isSpeaking());
tts.speak("try again", TextToSpeech.QUEUE_FLUSH, null);
while(tts.isSpeaking());
fun(true); //enable touch events
}
}
else if(pass==2)
{
b.putString("number", number);
in.putExtras(b);
tts.speak( "calling"+name, TextToSpeech.QUEUE_FLUSH, null);
while(tts.isSpeaking());
tts.shutdown();
startActivity(in);
//int pid = android.os.Process.myPid();
//android.os.Process.killProcess(pid);
finish();
//Intent
}
else if (quit==2) {
while(tts.isSpeaking());
tts.speak("Quitting application",TextToSpeech.QUEUE_FLUSH, null);
while(tts.isSpeaking());
tts.shutdown();
finish();
}
}//end of if
else if (keyCode == KeyEvent.KEYCODE_MENU
&& event.getRepeatCount() == 0)
{
fun(false);//disable touch events
if(pass==2)
{
pass=1;
//while(tts.isSpeaking());
tts.speak("Going back",TextToSpeech.QUEUE_FLUSH, null);
while(tts.isSpeaking());
fun(true);
//mhandler.postDelayed(mUpdateTimeTask, 1000);
}
else if(quit==2)
{
quit=1;
//while(tts.isSpeaking());
tts.speak("Going back",TextToSpeech.QUEUE_FLUSH, null);
while(tts.isSpeaking());
fun(true);//enable touch events
}
else if(quit==1)
{
quit++;
//mhandler.removeCallbacks(mUpdateTimeTask);
//while(tts.isSpeaking());
tts.speak("Do u want to quit",TextToSpeech.QUEUE_FLUSH, null);
while(tts.isSpeaking());
//Toast.makeText(TimerActivity.this,"Do u want to quit",Toast.LENGTH_LONG).show();
}
}
return true;
}
Try the workaround mentioned here Android button enabling/disabling not working
onClick(View v)
{
if(condition)
{
return;
}
else
{
//perform onClick stuff
}
}