Getting current android gamepad axis position - java

I receive axes position from my bluetooth gamepad controller in dispatchGenericMotionEvent(android.view. MotionEvent) method.
My method:
#Override
public boolean dispatchGenericMotionEvent(final MotionEvent event) {
if( mPadListener==null ||
(event.getSource()&InputDeviceCompat.SOURCE_JOYSTICK)!=InputDeviceCompat.SOURCE_JOYSTICK ){
return super.dispatchGenericMotionEvent(event);
}
int historySize = event.getHistorySize();
for (int i = 0; i < historySize; i++) {
// Process the event at historical position i
Log.d("JOYSTICKMOVE",event.getHistoricalAxisValue(MotionEvent.AXIS_Y,i)+" "+event.getHistoricalAxisValue(MotionEvent.AXIS_Z,i));
}
// Process current position
Log.d("JOYSTICKMOVE",event.getAxisValue(MotionEvent.AXIS_Y)+" "+event.getAxisValue(MotionEvent.AXIS_Z));
return true;
}
The problem is that when I release all joystick axes, I'm not getting last axes values (0,0) in my log. It stops for example in (0.23,0.11) and appropriate values appear in logcat only after next move event. What's more - situation is the same even if I press normal button (button event is catch by completely other method dispatchKeyEvent(android.view.KeyEvent) )
What's going on ?

You get a MotionEvent.ACTION_MOVE event for the zero position, but the value you receive is not necessarily zero. You need to get the flat range of the joystick, which gives you the values at which we should consider the joystick to be at rest (ie. if we are below the flat range, then we're at the zero position). See getCenteredAxis, which corrects for the flat range (https://developer.android.com/training/game-controllers/controller-input.html):
private static float getCenteredAxis(MotionEvent event,
InputDevice device, int axis, int historyPos) {
final InputDevice.MotionRange range =
device.getMotionRange(axis, event.getSource());
// A joystick at rest does not always report an absolute position of
// (0,0). Use the getFlat() method to determine the range of values
// bounding the joystick axis center.
if (range != null) {
final float flat = range.getFlat();
final float value =
historyPos < 0 ? event.getAxisValue(axis):
event.getHistoricalAxisValue(axis, historyPos);
// Ignore axis values that are within the 'flat' region of the
// joystick axis center.
if (Math.abs(value) > flat) {
return value;
}
}
return 0;
}

Related

Draw circles permanetly given an if statement - Processing

I have an if statement which checks for collision as such:
if (BallY == y && BallX == x) // check for collision
{
x = 80; // reset x to initial
y = 240; // reset y to initial
z = 100; //reset z to initial
}
I have a for loop inside this if statement as such:
if (BallY == y && BallX == x) // check for collision
{
x = 80; // reset x to initial
y = 240; // reset y to initial
z = 100; //reset z to initial
for (int i=50; i<width; i+=80)
{
fill(250,0,0);
ellipse(i, 50, 70, 70);
}
}
So the point is to draw a line of circles on the top of the screen once the collision occurs. This code however, only draws them for a split second then they disappear. How would I make them stay given that a collision has occurred?
You might want to use a boolean value that tracks whether the ball has collided. Set it to true when you detect a collision, and then check the value to decide what to draw. Here's a simplified example:
boolean drawRed = false;
void draw() {
if (mouseY > height/2) {
drawRed = true;
}
if (drawRed) {
background(255, 0, 0);
}
}
This code draws a gray background by default, but then turns to red if the mouse goes in the lower half of the window. It stays red even if you move the mouse back to the top part.
This is just a simple example, but the idea is the same: use a variable to track the state of the sketch, set that variable when your condition is met, and check that variable to decide what to draw.
By the way, your collision detection is a little bit suspicious. You probably don't want to check whether the ball is at an exact location. Instead you probably want to check whether the ball overlaps some area. Here is a guide on collision detection in Processing that might be useful.
If you still can't get it working, please narrow your problem down to a MCVE instead of posting disconnected snippets or your full sketch. Good luck!

Select lines from line margin - mouseDragged event not keeping up with selection processing

I am building a text editor and trying to add the ability to select lines using the line number margin. My current approach is to use mouseDragged to update the selected lines. This works fine when doing slow mouse movements, but when doing faster movements the selection isn't able to keep up and just stops updating.
I have tried using a new thread for the processing of the selected range but it still freezes.
Update: Changed to a mouse range of two values (min/max) rather than every line - this fixed the issue
The mouseDragged method
private void mouseDragged(MouseEvent event, Mouse mouse) {
int eventY = event.getY();
int currentLineNumber = this.getLineNumber(eventY);
mouse.endRange(currentLineNumber);
if(mouse.getRange()[0] != mouse.getRange()[1]) {
this.selectLineRange(mouse);
} else {
this.selectLineForOffset(eventY);
}
}
Mouse state
private class Mouse {
int mouseY = -1;
int[] range = new int[2];
private void resetMouse(boolean resetBeginLine) {
this.mouseY = -1;
this.range = new int[2];
}
void endRange(int lineNumber) {
range[1] = lineNumber;
}
void beginRange(int lineNumber) {
range[0] = lineNumber;
}
int[] getRange() {
return range;
}
boolean validRange() {
return ((range[0] | range[1]) > 0);
}
}
And finally the select line range method
private void selectLineRange(Mouse mouse) {
if (mouse.validRange()) {
int minLine = Math.min(mouse.getRange()[0], mouse.getRange()[1]);
int maxLine = Math.max(mouse.getRange()[0], mouse.getRange()[1]);;
Element root = editor.getDocument().getDefaultRootElement();
int startSelection = root.getElement(minLine).getStartOffset();
int endSelection = root.getElement(maxLine).getEndOffset();
//editor.setCaretPosition(mouse.mouseDirection == Direction.UP ? startSelection : endSelection - 1);
editor.select(startSelection, Math.max(endSelection - 1, 0));
}
}
Having code in the same function that knows both about the concept of a mouse and the concept of a document is a recipe for disaster. Split your code into multiple functions where each function works at a different level of abstraction.
All you need is to know at which Y the mouse went down, and at which Y the mouse currently is. From this, you can at any given moment re-calculate the range of selected lines. First you convert viewport-Y to workspace-Y, then you convert workspace-Y to line-number, and voila, you have each line number.
This: selectedLineNumbers.add(currentLineNumber); presumes that you will receive a mouse event on each line. If you don't, then your list will contain gaps. And you won't, because mouse events come few and far apart when you are moving the mouse too quickly. That's why your selectedLineNumbers should be a range, (startingLineNumber, endingLineNumber) not a list of distinct line numbers.

Co-ordinates of the ACTION_UP and ACTION_POINTER_UP event

I am trying to check what is touching the screen whenever it is pressed, a pointer is moved, or a touch is released.
The problem is that when a touch is released, getPointerCount() includes the pointer that just left the screen in its count. And so when I try to gather all the current X and Y values, it includes an x/y pair that has left the screen.
I am currently doing something like:
int count = e.getPointerCount();
for(i = 0; i < count; i++) {
x = e.getX(i);
y = e.getY(i);
/* do stuff with them */
}
Is there a way of getting the X and Y coordinates of that pointer that left the screen, or remove the pointer that left the screen and get only coordinates that are touching the screen?
Thanks
Have you tried using the onTouchEvent in your application?
import android.view.MotionEvent;
...
private int mActivePointerId;
protected void onCreate(Bundle savedInstanceState){
...
}
public boolean onTouchEvent(MotionEvent event){
// Get the pointer ID
mActivePointerId = event.getPointerId(0);
// ... Many touch events later...
// Use the pointer ID to find the index of the active pointer
// and fetch its position
int pointerIndex = event.findPointerIndex(mActivePointerId);
// Get the pointer's current position
float x = event.getX(pointerIndex);
float y = event.getY(pointerIndex);
return true;
}
I think the method you want is getActionIndex(). From the documentation, it seems that when getActionMasked() returns ACTION_POINTER_UP, this method will return the corresponding pointer index and you can then ignore it in your loop (or do something else with it).

Getting current fingers position on Android

I'm developing an application that needs to get all fingers on the screen of the Android. That's not complex, and I could make it in a few lines of code.
However, the way android sends callbacks is not what I need. I have done many tests, and here is what I could find out:
Once he sent the fingers positions, if no "big" movement has been made, he will not send a onTouch event.
Also, when a finger is REMOVED from the screen (for example: there are 3 fingers, and one is removed), it seems that it ONLY sends the next event, if at least one of the remaining fingers move on the screen.
I'm doing some tracking on fingers, and matching with objects, and to do this properly, I need to know all the fingers positions all the time. If there is not a way to "request" finger's touch event even when it didn't moved, how can I access the current finger positions without an callback event? Is there any other solution?
Here is my code:
ArrayList<Vector3> fingerTips = new ArrayList<Vector3>();
#Override
public boolean onTouchEvent(MotionEvent event) {
final int points = event.getPointerCount();
String out = "==========\n";
fingerTips.clear();
for(int i = 0; i < points; i++){
out += "\tPoint "+i+"\t("+event.getX(i)+", "+event.getY(i) + ")\n";
fingerTips.add( new Vector3(event.getX(i), event.getY(i)) );
}
Log.i(TAG, out);
// Send touches to SurfaceView
chwaziViewGL.onUpdateFingerTips(fingerTips);
return true;
}
My problem was that I didn't received one event with all the finger positions AFTER removing a finger...
After lot's of tests and logging, I discovered that it's true (in part).
Whenever you REMOVE a finger on the SCREEN, the NEXT event sent is an ACTION_POINTER_UP or ACTION_UP, meaning that the finger x is no longer touching the screen.
Since there was NO motion after removing the finger, the last MotionEvent sent was the UP, containg the removed finger also.
So, to fix that, I check if the action is UP, and on the loop that get's all the fingers, I created an if checking if that was the finger removed from the screen. If so, I just didn't add it to the array.
Here is my final code:
ArrayList<Vector3> fingerTips = new ArrayList<Vector3>();
#Override
public boolean onTouchEvent(MotionEvent event) {
final int points = event.getPointerCount();
// Check if it's an event that a finger
// was removed, if so, set removedPoint
int removedPoint = -1;
final int action = event.getAction() & MotionEvent.ACTION_MASK;
if(action == MotionEvent.ACTION_POINTER_UP || action == MotionEvent.ACTION_UP)
removedPoint = (action & MotionEvent.ACTION_POINTER_INDEX_MASK)
>> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
String out = "==========\n";
fingerTips.clear();
for(int i = 0; i < points; i++){
// Find out pointer ID
int pointerID = event.getPointerId(i);
if(pointerID == MotionEvent.INVALID_POINTER_ID){
out += "\tPoint "+pointerID+" INVALID\n";
continue;
}
// Check if it's the removed finger
if(removedPoint == i){
out += "\tPoint "+pointerID+" REMOVED\n";
continue;
}
out += "\tPoint "+pointerID+"\t("+event.getX(i)+", "+event.getY(i) + ")\n";
fingerTips.add( new Vector3(event.getX(i), event.getY(i), pointerID) );
}
Log.i(TAG, out);
// Send touches to SurfaceView
chwaziViewGL.onUpdateFingerTips(fingerTips);
return true;
}
Sorry, but your code cost me a lot of hairs;-(( After days I found the problem finally before I got insane. This code
final int action = event.getAction() & MotionEvent.ACTION_MASK;
if(action == MotionEvent.ACTION_POINTER_UP || action == MotionEvent.ACTION_UP)
removedPoint = (action & MotionEvent.ACTION_POINTER_INDEX_MASK)
>> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
could have never been worked!!!
Why? Because if you mask the value that is coming from getAction() it is simply a plain integer value of the action. And when you try to use this plain value and masking it again with something, it has no meaning at all!
The correction is to use again event.getAction() in the seconds masking:
removedPoint = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
>> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
It was really a nightmare to find this. But anyway, I think you just wanted the best and help others:-))) Its ok.

selecting textViews and getting their values

I am trying to accomplish following things
Suppose I have 5-6 TextViews with values S N A K E
Now, I want to press S textView then slide my finger over N to select it too and then move my way to E. I want to do that so that i can get "SNAKE" in my string or char sequence etc
If there is any idea do share me. I can't get it how to use onTouch here.
Also, i am adding textViews dynamically so i am setting their ids dynamically too
Best Regards
I've never done this, but here's a thought.
Assuming all your textviews are in some sort of layout, you could disable the focusability on your textview and create an onTouch listener on your underlying container.
Start tracking on Mouse Down events
#Override public boolean onTouch(View v, MotionEvent event) {
if(event.getAction == MotionEvent.ACTION_DOWN)
{
captureInput = true;
}
}
*On your ACTION_MOVE event, check if the current position is above a textview, if so, capture that value*
#Override public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
if(action == MotionEvent.ACTION_DOWN)
{
captureInput = true;
}
else if(action == MotionEvent.ACTION_MOVE
{
//get x/y of your finger
int X = (int)event.getX();
int Y = (int)event.getY();
//Somehow check if the x,y are overlapping with one of your textivews
// If so, add that textview's text to your list
// Below is pseudo code
/* for(TextView curTV: allTextViews)
{
if(isOverlapping(X,Y))
{
listOfSwipedCharacters.add(curTV.getText());
}
}
}
}
Lastly, when the user releases their finger, stop tracking and do something with the word list
#Override public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
if(action == MotionEvent.ACTION_DOWN)
{
captureInput = true;
}
else if(action == MotionEvent.ACTION_MOVE
{
//get x/y of your finger
int X = (int)event.getX();
int Y = (int)event.getY();
//Somehow check which textview the X,Y coords are overlapping
// Below is pseudo code
/* for(TextView curTV: allTextViews)
{
if(isOverlapping(X,Y))
{
listOfSwipedCharacters += (curTV.getText());
}
}*/
}
else if(action == MotionEvent.ACTION_UP)
{
captureInput = false;
//Do whatever you want with the string of information that you've captured
}
}
Once again, I have no idea if that will work, it's just a guess at an approach. I suspect performance of cycling through each textview to check for overlaps will be pretty crappy, so there may be a more efficient approach than running a for loop.
Since you know you can't jump over letters when swyping, you could create a short list of all the possible swipe locations (surrounding letters) whenever you add a new letter. Then on your mouse event, check if any of those letters have been hit by the mouse move event. For example, in a standard word search game, once you select a letter, there are only 9 other possible locations for you to swipe (the surrounding letters), so you should only bother checking if those 9 locations have been hit when you capture the mouse move event.
Edit: I suppose you could use the solution above if you attached an onTouch listener to each and every textview. The same premise in regards to touch would apply: Down = start capture, move = capture text, up = stop capture. It would save you from having to identify which textview is being hovered as the textview that fires the onTouch event will be the one that the user is swiping across.

Categories