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.
Related
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'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
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.
Every time I pressed enter the toast keeps popping out even if it should not come out...
take a lot at my code:
etAddMove.setOnKeyListener(new OnKeyListener() {
#SuppressLint("NewApi")
public boolean onKey(View v, int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
if(keyCode == KeyEvent.KEYCODE_ENTER && event.getRepeatCount() == 0){
String ssmoveName = etAddMove.getText().toString();
int x = ssmoveName.length() - 1;
if (ssmoveName.isEmpty() || Character.isWhitespace(ssmoveName.charAt(0)) || Character.isWhitespace(ssmoveName.charAt(x))) {
Toast.makeText(ListMovingNames.this,
"Please enter a valid name! Avoid giving a blank name or white space at the beginning or end of the name",
Toast.LENGTH_LONG).show();
}else{
try {
SQLHandler check = new SQLHandler(ListMovingNames.this);
check.open();
String scheck = check.checkMove(ssmoveName);
check.close();
if (!scheck.equals(ssmoveName)) {
Toast.makeText(ListMovingNames.this, "Move name already exist please give a different name", Toast.LENGTH_LONG).show();
} else{
SQLHandler entry = new SQLHandler(ListMovingNames.this);
entry.open();
entry.createMove(ssmoveName);
entry.setTodo(ssmoveName);
entry.close();
Intent i = new Intent(getApplicationContext(), StartMoving.class);
i.putExtra("moveName", ssmoveName);
startActivity(i);
}
} catch (Exception e) {
// TODO Auto-generated catch block
SQLHandler entry = new SQLHandler(ListMovingNames.this);
entry.open();
entry.createMove(ssmoveName);
entry.setTodo(ssmoveName);
entry.close();
Intent i = new Intent(getApplicationContext(), StartMoving.class);
i.putExtra("moveName", ssmoveName);
startActivity(i);
}
}
return true;
}
return onKeyDown(keyCode, event);
}
});
how can you make this guy stop if I don't want it to show...
EDIT
I think I know why this is happening, It must be because each time i press enter keyup and keydown is initialize thats why the first initialization is keydown which calls the condition and returns false and when keydown is called the condition is called again which will return true, making the toast display. thats what i think so far...
Try with following if not work then come to know.
Toast toast;
toast.makeText(getApplicationContext(), "text", Toast.LENGTH_SHORT).show();
if(Yourcondition)
{
toast.show();
}
else
{
//nothing to display
}
Finally solve this shit. As I was suspecting the reason why toast keeps showing is that everytime the enter key is press, the keydown and keyup is called that's why the process is called twice making the toast appear because the condition to show the toast is meet when the process is called the second time.
So to avoid that KeyEvent.ACTION_DOWN must be present.
public boolean onKey(View v, int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
if ( (event.getAction() == KeyEvent.ACTION_DOWN ) && (keyCode== KeyEvent.KEYCODE_ENTER) )
{
// do something here
}
return true;
}
Use this:
Toast toast;
toast.makeText(getApplicationContext(), "text", Toast.LENGTH_SHORT);
if(Yourcondition)
{
toast.show();
}
else
{
//nothing to display
}
In the last answer, you are using .show method, when you are creating the toast. It will show the even, if the statement is true or not.
So, remove .show from
toast.makeText(getApplicationContext(), "text", Toast.LENGTH_SHORT).show();
this statement.
This might help.
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
}
}