Skip to content

Commit

Permalink
Adding support for horizontal scrolling (touch pad and touch screen) (#…
Browse files Browse the repository at this point in the history
…6154)

Also, adding support for devices which report fractional scrolling
amounts. E.g. a mouse with a continuous mouse wheel, or a Mac touch
pad. This is currently only supported in lwjgl3. It can probably be
added to android and maybe to gwt.

InputProcessor scrolled method now receives scroll amount for X and
Y. Changed type to float to support devices which report fractional
scroll amounts. Keeping the original scroll method of InputProcessor
for backward compatibility.  Updated InputEvent in scene2d
accordingly: added scrollAmountX, scrollAmountY attributes and
corresponding setters and getters.

Input event queue can receive float scrolling values.

Updated backends accordingly: lwjgl, lwjgl3, android and gwt.

Co-authored-by: Julien Pauty <julien@griottemail.com>
Co-authored-by: Benjamin Schulte <MrStahlfelge@users.noreply.github.com>
  • Loading branch information
3 people committed Oct 13, 2020
1 parent 858dc54 commit 432df1b
Show file tree
Hide file tree
Showing 29 changed files with 76 additions and 81 deletions.
1 change: 1 addition & 0 deletions CHANGES
Expand Up @@ -37,6 +37,7 @@
- API Change: Enabling fullscreen mode on the lwjgl3 backend now automatically sets the vsync setting again.
- API Addition: Added put(key, value, defaultValue) for maps with primitive keys, so the old value can be returned.
- API Addition: Added ObjectLongMap.
- API Change: InputProcessor scrolled method now receives scroll amount for X and Y. Changed type to float to support devices which report fractional scroll amounts. Updated InputEvent in scene2d accordingly: added scrollAmountX, scrollAmountY attributes and corresponding setters and getters.
- Added Intersector#intersectRayOrientedBoundsFast to detect if a ray intersects an oriented bounding box, see https://github.com/libgdx/libgdx/pull/6139
- API Addition: Added Table#clip() and Container#clip() methods.
- API Addition: Added getBackgroundDrawable() to Button.
Expand Down
Expand Up @@ -35,7 +35,8 @@ public boolean onGenericMotion (MotionEvent event, DefaultAndroidInput input) {
final int action = event.getAction() & MotionEvent.ACTION_MASK;

int x = 0, y = 0;
int scrollAmount = 0;
int scrollAmountX = 0;
int scrollAmountY = 0;

long timeStamp = System.nanoTime();
synchronized (input) {
Expand All @@ -44,15 +45,16 @@ public boolean onGenericMotion (MotionEvent event, DefaultAndroidInput input) {
x = (int)event.getX();
y = (int)event.getY();
if ((x != deltaX) || (y != deltaY)) { // Avoid garbage events
postTouchEvent(input, TouchEvent.TOUCH_MOVED, x, y, 0, timeStamp);
postTouchEvent(input, TouchEvent.TOUCH_MOVED, x, y, 0, 0, timeStamp);
deltaX = x;
deltaY = y;
}
break;

case MotionEvent.ACTION_SCROLL:
scrollAmount = (int)-Math.signum(event.getAxisValue(MotionEvent.AXIS_VSCROLL));
postTouchEvent(input, TouchEvent.TOUCH_SCROLLED, 0, 0, scrollAmount, timeStamp);
scrollAmountY = (int)-Math.signum(event.getAxisValue(MotionEvent.AXIS_VSCROLL));
scrollAmountX = (int)-Math.signum(event.getAxisValue(MotionEvent.AXIS_HSCROLL));
postTouchEvent(input, TouchEvent.TOUCH_SCROLLED, 0, 0, scrollAmountX, scrollAmountY, timeStamp);

}
}
Expand All @@ -75,13 +77,14 @@ else if (action == MotionEvent.ACTION_SCROLL)
Gdx.app.log("AndroidMouseHandler", "action " + actionStr);
}

private void postTouchEvent (DefaultAndroidInput input, int type, int x, int y, int scrollAmount, long timeStamp) {
private void postTouchEvent (DefaultAndroidInput input, int type, int x, int y, int scrollAmountX, int scrollAmountY, long timeStamp) {
TouchEvent event = input.usedTouchEvents.obtain();
event.timeStamp = timeStamp;
event.x = x;
event.y = y;
event.type = type;
event.scrollAmount = scrollAmount;
event.scrollAmountX = scrollAmountX;
event.scrollAmountY = scrollAmountY;
input.touchEvents.add(event);
}

Expand Down
Expand Up @@ -77,7 +77,8 @@ static class TouchEvent {
int type;
int x;
int y;
int scrollAmount;
int scrollAmountX;
int scrollAmountY;
int button;
int pointer;
}
Expand Down Expand Up @@ -419,7 +420,7 @@ public void processEvents () {
processor.mouseMoved(e.x, e.y);
break;
case TouchEvent.TOUCH_SCROLLED:
processor.scrolled(e.scrollAmount);
processor.scrolled(e.scrollAmountX, e.scrollAmountY);
}
usedTouchEvents.free(e);
}
Expand Down
Expand Up @@ -367,7 +367,7 @@ public void processEvents () {
processor.mouseMoved(e.x, e.y);
break;
case TouchEvent.TOUCH_SCROLLED:
processor.scrolled(e.scrollAmount);
processor.scrolled(0, e.scrollAmount);
}
usedTouchEvents.free(e);
}
Expand Down
Expand Up @@ -383,7 +383,7 @@ void processEvents () {
processor.mouseMoved(e.x, e.y);
break;
case TouchEvent.TOUCH_SCROLLED:
processor.scrolled(e.scrollAmount);
processor.scrolled(0, e.scrollAmount);
break;
}
usedTouchEvents.free(e);
Expand Down
Expand Up @@ -87,31 +87,10 @@ public void invoke(long window, int codepoint) {
};

private GLFWScrollCallback scrollCallback = new GLFWScrollCallback() {
private long pauseTime = 250000000L; //250ms
private float scrollYRemainder;
private long lastScrollEventTime;
@Override
public void invoke(long window, double scrollX, double scrollY) {
DefaultLwjgl3Input.this.window.getGraphics().requestRendering();
if (scrollYRemainder > 0 && scrollY < 0 || scrollYRemainder < 0 && scrollY > 0 ||
TimeUtils.nanoTime() - lastScrollEventTime > pauseTime ) {
// fire a scroll event immediately:
// - if the scroll direction changes;
// - if the user did not move the wheel for more than 250ms
scrollYRemainder = 0;
int scrollAmount = (int)-Math.signum(scrollY);
eventQueue.scrolled(scrollAmount);
lastScrollEventTime = TimeUtils.nanoTime();
}
else {
scrollYRemainder += scrollY;
while (Math.abs(scrollYRemainder) >= 1) {
int scrollAmount = (int)-Math.signum(scrollY);
eventQueue.scrolled(scrollAmount);
lastScrollEventTime = TimeUtils.nanoTime();
scrollYRemainder += scrollAmount;
}
}
eventQueue.scrolled(-(float)scrollX, -(float)scrollY);
}
};

Expand Down
Expand Up @@ -715,7 +715,7 @@ private void handleEvent (NativeEvent e) {
}
if (e.getType().equals(getMouseWheelEvent())) {
if (processor != null) {
processor.scrolled((int)getMouseWheelVelocity(e));
processor.scrolled(0, (int)getMouseWheelVelocity(e));
}
this.currentEventTimeStamp = TimeUtils.nanoTime();
e.preventDefault();
Expand Down
Expand Up @@ -350,11 +350,11 @@ public OrthoCamController (OrthographicCamera camera) {
}

@Override
public boolean scrolled (int amount) {
worldCamera.zoom += amount * 0.01f;
public boolean scrolled (float amountX, float amountY) {
worldCamera.zoom += amountY * 0.01f;
worldCamera.zoom = MathUtils.clamp(worldCamera.zoom, 0.01f, 5000);
worldCamera.update();
return super.scrolled(amount);
return super.scrolled(amountX, amountY);
}

@Override
Expand Down Expand Up @@ -599,7 +599,7 @@ public boolean mouseMoved (int x, int y) {
}

@Override
public boolean scrolled (int amount) {
public boolean scrolled (float amountX, float amountY) {
return false;
}

Expand Down
2 changes: 1 addition & 1 deletion gdx/src/com/badlogic/gdx/InputAdapter.java
Expand Up @@ -50,7 +50,7 @@ public boolean mouseMoved (int screenX, int screenY) {
}

@Override
public boolean scrolled (int amount) {
public boolean scrolled (float amountX, float amountY) {
return false;
}
}
10 changes: 6 additions & 4 deletions gdx/src/com/badlogic/gdx/InputEventQueue.java
Expand Up @@ -18,6 +18,7 @@

import com.badlogic.gdx.utils.IntArray;
import com.badlogic.gdx.utils.TimeUtils;
import com.badlogic.gdx.utils.NumberUtils;

/** Queues events that are later passed to the wrapped {@link InputProcessor}.
* @author Nathan Sweet */
Expand Down Expand Up @@ -92,7 +93,7 @@ public void drain () {
localProcessor.mouseMoved(q[i++], q[i++]);
break;
case SCROLLED:
localProcessor.scrolled(q[i++]);
localProcessor.scrolled(NumberUtils.intBitsToFloat(q[i++]) , NumberUtils.intBitsToFloat(q[i++]));
break;
default:
throw new RuntimeException();
Expand Down Expand Up @@ -133,7 +134,7 @@ private synchronized int next (int nextType, int i) {
i += 2;
break;
case SCROLLED:
i++;
i += 2;
break;
default:
throw new RuntimeException();
Expand Down Expand Up @@ -218,10 +219,11 @@ public synchronized boolean mouseMoved (int screenX, int screenY) {
return false;
}

public synchronized boolean scrolled (int amount) {
public synchronized boolean scrolled(float amountX, float amountY) {
queue.add(SCROLLED);
queueTime();
queue.add(amount);
queue.add(NumberUtils.floatToIntBits(amountX));
queue.add(NumberUtils.floatToIntBits(amountY));
return false;
}

Expand Down
4 changes: 2 additions & 2 deletions gdx/src/com/badlogic/gdx/InputMultiplexer.java
Expand Up @@ -150,11 +150,11 @@ public boolean mouseMoved (int screenX, int screenY) {
return false;
}

public boolean scrolled (int amount) {
public boolean scrolled (float amountX, float amountY) {
Object[] items = processors.begin();
try {
for (int i = 0, n = processors.size; i < n; i++)
if (((InputProcessor)items[i]).scrolled(amount)) return true;
if (((InputProcessor)items[i]).scrolled(amountX, amountY)) return true;
} finally {
processors.end();
}
Expand Down
5 changes: 3 additions & 2 deletions gdx/src/com/badlogic/gdx/InputProcessor.java
Expand Up @@ -67,7 +67,8 @@ public interface InputProcessor {
public boolean mouseMoved (int screenX, int screenY);

/** Called when the mouse wheel was scrolled. Will not be called on iOS.
* @param amount the scroll amount, -1 or 1 depending on the direction the wheel was scrolled.
* @param amountX the horizontal scroll amount, negative or positive depending on the direction the wheel was scrolled.
* @param amountY the vertical scroll amount, negative or positive depending on the direction the wheel was scrolled.
* @return whether the input was processed. */
public boolean scrolled (int amount);
public boolean scrolled (float amountX, float amountY);
}
Expand Up @@ -203,8 +203,8 @@ public boolean touchDragged (int screenX, int screenY, int pointer) {
}

@Override
public boolean scrolled (int amount) {
return zoom(amount * scrollFactor * translateUnits);
public boolean scrolled (float amountX, float amountY) {
return zoom(amountY * scrollFactor * translateUnits);
}

public boolean zoom (float amount) {
Expand Down
2 changes: 1 addition & 1 deletion gdx/src/com/badlogic/gdx/input/RemoteSender.java
Expand Up @@ -198,7 +198,7 @@ public boolean mouseMoved (int x, int y) {
}

@Override
public boolean scrolled (int amount) {
public boolean scrolled (float amountX, float amountY) {
return false;
}

Expand Down
22 changes: 15 additions & 7 deletions gdx/src/com/badlogic/gdx/scenes/scene2d/InputEvent.java
Expand Up @@ -24,8 +24,8 @@
* @see InputListener */
public class InputEvent extends Event {
private Type type;
private float stageX, stageY;
private int pointer, button, keyCode, scrollAmount;
private float stageX, stageY, scrollAmountX, scrollAmountY;
private int pointer, button, keyCode;
private char character;
private @Null Actor relatedActor;
private boolean touchFocus = true;
Expand Down Expand Up @@ -103,13 +103,21 @@ public void setCharacter (char character) {
this.character = character;
}

/** The amount the mouse was scrolled. Valid for: scrolled. */
public int getScrollAmount () {
return scrollAmount;
/** The amount the mouse was scrolled horizontally. Valid for: scrolled. */
public float getScrollAmountX () {
return scrollAmountX;
}
/** The amount the mouse was scrolled vertically. Valid for: scrolled. */
public float getScrollAmountY () {
return scrollAmountY;
}

public void setScrollAmountX (float scrollAmount) {
this.scrollAmountX = scrollAmount;
}

public void setScrollAmount (int scrollAmount) {
this.scrollAmount = scrollAmount;
public void setScrollAmountY (float scrollAmount) {
this.scrollAmountY = scrollAmount;
}

/** The actor related to the event. Valid for: enter and exit. For enter, this is the actor being exited, or null. For exit,
Expand Down
4 changes: 2 additions & 2 deletions gdx/src/com/badlogic/gdx/scenes/scene2d/InputListener.java
Expand Up @@ -76,7 +76,7 @@ public boolean handle (Event e) {
case mouseMoved:
return mouseMoved(event, tmpCoords.x, tmpCoords.y);
case scrolled:
return scrolled(event, tmpCoords.x, tmpCoords.y, event.getScrollAmount());
return scrolled(event, tmpCoords.x, tmpCoords.y, event.getScrollAmountX(), event.getScrollAmountY());
case enter:
enter(event, tmpCoords.x, tmpCoords.y, event.getPointer(), event.getRelatedActor());
return false;
Expand Down Expand Up @@ -130,7 +130,7 @@ public void exit (InputEvent event, float x, float y, int pointer, @Null Actor t
}

/** Called when the mouse wheel has been scrolled. When true is returned, the event is {@link Event#handle() handled}. */
public boolean scrolled (InputEvent event, float x, float y, int amount) {
public boolean scrolled (InputEvent event, float x, float y, float amountX, float amountY) {
return false;
}

Expand Down
5 changes: 3 additions & 2 deletions gdx/src/com/badlogic/gdx/scenes/scene2d/Stage.java
Expand Up @@ -389,15 +389,16 @@ public boolean mouseMoved (int screenX, int screenY) {

/** Applies a mouse scroll event to the stage and returns true if an actor in the scene {@link Event#handle() handled} the
* event. This event only occurs on the desktop. */
public boolean scrolled (int amount) {
public boolean scrolled (float amountX, float amountY) {
Actor target = scrollFocus == null ? root : scrollFocus;

screenToStageCoordinates(tempCoords.set(mouseScreenX, mouseScreenY));

InputEvent event = Pools.obtain(InputEvent.class);
event.setStage(this);
event.setType(InputEvent.Type.scrolled);
event.setScrollAmount(amount);
event.setScrollAmountX(amountX);
event.setScrollAmountY(amountY);
event.setStageX(tempCoords.x);
event.setStageY(tempCoords.y);
target.fire(event);
Expand Down
11 changes: 5 additions & 6 deletions gdx/src/com/badlogic/gdx/scenes/scene2d/ui/ScrollPane.java
Expand Up @@ -208,13 +208,12 @@ public boolean handle (Event event) {
addListener(flickScrollListener);

addListener(new InputListener() {
public boolean scrolled (InputEvent event, float x, float y, int amount) {
public boolean scrolled (InputEvent event, float x, float y, float scrollAmountX, float scrollAmountY) {
setScrollbarsVisible(true);
if (scrollY)
setScrollY(amountY + getMouseWheelY() * amount);
else if (scrollX) //
setScrollX(amountX + getMouseWheelX() * amount);
else
if (scrollY || scrollX) {
setScrollY(amountY + getMouseWheelY() * scrollAmountY);
setScrollX(amountX + getMouseWheelX() * scrollAmountX);
} else
return false;
return true;
}
Expand Down
Expand Up @@ -121,7 +121,7 @@ public boolean mouseMoved (int x, int y) {
}

@Override
public boolean scrolled (int amount) {
public boolean scrolled (float amountX, float amountY) {
return false;
}

Expand Down
Expand Up @@ -162,8 +162,8 @@ public boolean mouseMoved (int x, int y) {
}

@Override
public boolean scrolled (int amount) {
return tests[testIndex].scrolled(amount);
public boolean scrolled (float amountX, float amountY) {
return tests[testIndex].scrolled(amountX, amountY);
}

@Override
Expand Down
4 changes: 2 additions & 2 deletions tests/gdx-tests/src/com/badlogic/gdx/tests/InputTest.java
Expand Up @@ -109,8 +109,8 @@ public boolean mouseMoved (int x, int y) {
}

@Override
public boolean scrolled (int amount) {
Gdx.app.log("Input Test", "scrolled: " + amount);
public boolean scrolled (float amountX, float amountY) {
Gdx.app.log("Input Test", "scrolled: " + amountY);
return false;
}

Expand Down
Expand Up @@ -119,9 +119,9 @@ public void changed (ChangeEvent event, Actor actor) {
stage.addActor(table);

Gdx.input.setInputProcessor(new InputMultiplexer(new InputAdapter() {
public boolean scrolled (int amount) {
public boolean scrolled (float amountX, float amountY) {
if (!Gdx.input.isKeyPressed(Keys.CONTROL_LEFT)) return false;
duration -= amount / 15f;
duration -= amountY / 15f;
duration = MathUtils.clamp(duration, 0, Float.POSITIVE_INFINITY);
return true;
}
Expand Down
Expand Up @@ -93,7 +93,7 @@ public boolean mouseMoved (int x, int y) {
}

@Override
public boolean scrolled (int amount) {
public boolean scrolled (float amountX, float amountY) {
// TODO Auto-generated method stub
return false;
}
Expand Down

0 comments on commit 432df1b

Please sign in to comment.