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.
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);
Is there any way to find out if screen is split if I have no access to Activity? (Structurally I can't call isInMultiWindowMode method.
I see that default Activity#isInMultiWindowMode() implementation is:
public boolean isInMultiWindowMode() {
try {
return ActivityManagerNative.getDefault().isInMultiWindowMode(mToken);
} catch (RemoteException e) {
}
return false;
}
Is there any workaround ?
I think the only way to do this without an Activity is by using an AccessibilityService that has the permissions to get the list of windows currently displayed and check if there's a window whose type is AccessibilityWindowInfo.TYPE_SPLIT_SCREEN_DIVIDER.
For example, you could have the following method to do so:
private boolean inSplitScreenMode(List<AccessibilityWindowInfo> windows) {
for (AccessibilityWindowInfo window : windows) {
if (window.getType() == AccessibilityWindowInfo.TYPE_SPLIT_SCREEN_DIVIDER) {
return true;
}
}
return false;
}
check this method when receiving window state changed accessibility events
#Override
public void onAccessibilityEvent(AccessibilityEvent event) {
if ((event.getEventType() & AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) != 0) {
if (inSplitScreenMode(getWindows()) {
Log.d(TAG, "Split screen mode detected");
} else {
Log.d(TAG, "No split screen");
}
}
}
Inside Fragment you can use
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
if (((Activity)getContext()).isInMultiWindowMode()){
// ...
}
}
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 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.