godot/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
2020-04-03 11:18:59 +02:00

372 lines
11 KiB
Java

/*************************************************************************/
/* GodotInputHandler.java */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
package org.godotengine.godot.input;
import static org.godotengine.godot.utils.GLUtils.DEBUG;
import android.util.Log;
import android.view.InputDevice;
import android.view.InputDevice.MotionRange;
import android.view.KeyEvent;
import android.view.MotionEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.godotengine.godot.GodotLib;
import org.godotengine.godot.GodotRenderView;
import org.godotengine.godot.input.InputManagerCompat.InputDeviceListener;
/**
* Handles input related events for the {@link GodotRenderView} view.
*/
public class GodotInputHandler implements InputDeviceListener {
private final ArrayList<Joystick> mJoysticksDevices = new ArrayList<Joystick>();
private final GodotRenderView mRenderView;
private final InputManagerCompat mInputManager;
public GodotInputHandler(GodotRenderView godotView) {
mRenderView = godotView;
mInputManager = InputManagerCompat.Factory.getInputManager(mRenderView.getView().getContext());
mInputManager.registerInputDeviceListener(this, null);
}
private void queueEvent(Runnable task) {
mRenderView.queueOnRenderThread(task);
}
private boolean isKeyEvent_GameDevice(int source) {
// Note that keyboards are often (SOURCE_KEYBOARD | SOURCE_DPAD)
if (source == (InputDevice.SOURCE_KEYBOARD | InputDevice.SOURCE_DPAD))
return false;
return (source & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK || (source & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD || (source & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD;
}
public boolean onKeyUp(final int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
return true;
}
if (keyCode == KeyEvent.KEYCODE_VOLUME_UP || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
return false;
};
int source = event.getSource();
if (isKeyEvent_GameDevice(source)) {
final int button = getGodotButton(keyCode);
final int device_id = findJoystickDevice(event.getDeviceId());
// Check if the device exists
if (device_id > -1) {
queueEvent(new Runnable() {
@Override
public void run() {
GodotLib.joybutton(device_id, button, false);
}
});
}
} else {
final int scanCode = event.getScanCode();
final int chr = event.getUnicodeChar(0);
queueEvent(new Runnable() {
@Override
public void run() {
GodotLib.key(keyCode, scanCode, chr, false);
}
});
};
return true;
}
public boolean onKeyDown(final int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
mRenderView.onBackPressed();
// press 'back' button should not terminate program
//normal handle 'back' event in game logic
return true;
}
if (keyCode == KeyEvent.KEYCODE_VOLUME_UP || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
return false;
};
int source = event.getSource();
//Log.e(TAG, String.format("Key down! source %d, device %d, joystick %d, %d, %d", event.getDeviceId(), source, (source & InputDevice.SOURCE_JOYSTICK), (source & InputDevice.SOURCE_DPAD), (source & InputDevice.SOURCE_GAMEPAD)));
if (isKeyEvent_GameDevice(source)) {
if (event.getRepeatCount() > 0) // ignore key echo
return true;
final int button = getGodotButton(keyCode);
final int device_id = findJoystickDevice(event.getDeviceId());
// Check if the device exists
if (device_id > -1) {
queueEvent(new Runnable() {
@Override
public void run() {
GodotLib.joybutton(device_id, button, true);
}
});
}
} else {
final int scanCode = event.getScanCode();
final int chr = event.getUnicodeChar(0);
queueEvent(new Runnable() {
@Override
public void run() {
GodotLib.key(keyCode, scanCode, chr, true);
}
});
};
return true;
}
public boolean onGenericMotionEvent(MotionEvent event) {
if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK && event.getAction() == MotionEvent.ACTION_MOVE) {
final int device_id = findJoystickDevice(event.getDeviceId());
// Check if the device exists
if (device_id > -1) {
Joystick joy = mJoysticksDevices.get(device_id);
for (int i = 0; i < joy.axes.size(); i++) {
InputDevice.MotionRange range = joy.axes.get(i);
final float value = (event.getAxisValue(range.getAxis()) - range.getMin()) / range.getRange() * 2.0f - 1.0f;
final int idx = i;
queueEvent(new Runnable() {
@Override
public void run() {
GodotLib.joyaxis(device_id, idx, value);
}
});
}
for (int i = 0; i < joy.hats.size(); i += 2) {
final int hatX = Math.round(event.getAxisValue(joy.hats.get(i).getAxis()));
final int hatY = Math.round(event.getAxisValue(joy.hats.get(i + 1).getAxis()));
queueEvent(new Runnable() {
@Override
public void run() {
GodotLib.joyhat(device_id, hatX, hatY);
}
});
}
return true;
}
} else if ((event.getSource() & InputDevice.SOURCE_STYLUS) == InputDevice.SOURCE_STYLUS) {
final int x = Math.round(event.getX());
final int y = Math.round(event.getY());
final int type = event.getAction();
queueEvent(new Runnable() {
@Override
public void run() {
GodotLib.hover(type, x, y);
}
});
return true;
}
return false;
}
public void initInputDevices() {
/* initially add input devices*/
int[] deviceIds = mInputManager.getInputDeviceIds();
for (int deviceId : deviceIds) {
InputDevice device = mInputManager.getInputDevice(deviceId);
if (DEBUG) {
Log.v("GodotInputHandler", String.format("init() deviceId:%d, Name:%s\n", deviceId, device.getName()));
}
onInputDeviceAdded(deviceId);
}
}
@Override
public void onInputDeviceAdded(int deviceId) {
int id = findJoystickDevice(deviceId);
// Check if the device has not been already added
if (id < 0) {
InputDevice device = mInputManager.getInputDevice(deviceId);
//device can be null if deviceId is not found
if (device != null) {
int sources = device.getSources();
if (((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) ||
((sources & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK)) {
id = mJoysticksDevices.size();
Joystick joy = new Joystick();
joy.device_id = deviceId;
joy.name = device.getName();
joy.axes = new ArrayList<InputDevice.MotionRange>();
joy.hats = new ArrayList<InputDevice.MotionRange>();
List<InputDevice.MotionRange> ranges = device.getMotionRanges();
Collections.sort(ranges, new RangeComparator());
for (InputDevice.MotionRange range : ranges) {
if (range.getAxis() == MotionEvent.AXIS_HAT_X || range.getAxis() == MotionEvent.AXIS_HAT_Y) {
joy.hats.add(range);
} else {
joy.axes.add(range);
}
}
mJoysticksDevices.add(joy);
final int device_id = id;
final String name = joy.name;
queueEvent(new Runnable() {
@Override
public void run() {
GodotLib.joyconnectionchanged(device_id, true, name);
}
});
}
}
}
}
@Override
public void onInputDeviceRemoved(int deviceId) {
final int device_id = findJoystickDevice(deviceId);
// Check if the evice has not been already removed
if (device_id > -1) {
mJoysticksDevices.remove(device_id);
queueEvent(new Runnable() {
@Override
public void run() {
GodotLib.joyconnectionchanged(device_id, false, "");
}
});
}
}
@Override
public void onInputDeviceChanged(int deviceId) {
onInputDeviceRemoved(deviceId);
onInputDeviceAdded(deviceId);
}
private static class RangeComparator implements Comparator<MotionRange> {
@Override
public int compare(MotionRange arg0, MotionRange arg1) {
return arg0.getAxis() - arg1.getAxis();
}
}
public static int getGodotButton(int keyCode) {
int button;
switch (keyCode) {
case KeyEvent.KEYCODE_BUTTON_A: // Android A is SNES B
button = 0;
break;
case KeyEvent.KEYCODE_BUTTON_B:
button = 1;
break;
case KeyEvent.KEYCODE_BUTTON_X: // Android X is SNES Y
button = 2;
break;
case KeyEvent.KEYCODE_BUTTON_Y:
button = 3;
break;
case KeyEvent.KEYCODE_BUTTON_L1:
button = 9;
break;
case KeyEvent.KEYCODE_BUTTON_L2:
button = 15;
break;
case KeyEvent.KEYCODE_BUTTON_R1:
button = 10;
break;
case KeyEvent.KEYCODE_BUTTON_R2:
button = 16;
break;
case KeyEvent.KEYCODE_BUTTON_SELECT:
button = 4;
break;
case KeyEvent.KEYCODE_BUTTON_START:
button = 6;
break;
case KeyEvent.KEYCODE_BUTTON_THUMBL:
button = 7;
break;
case KeyEvent.KEYCODE_BUTTON_THUMBR:
button = 8;
break;
case KeyEvent.KEYCODE_DPAD_UP:
button = 11;
break;
case KeyEvent.KEYCODE_DPAD_DOWN:
button = 12;
break;
case KeyEvent.KEYCODE_DPAD_LEFT:
button = 13;
break;
case KeyEvent.KEYCODE_DPAD_RIGHT:
button = 14;
break;
case KeyEvent.KEYCODE_BUTTON_C:
button = 17;
break;
case KeyEvent.KEYCODE_BUTTON_Z:
button = 18;
break;
default:
button = keyCode - KeyEvent.KEYCODE_BUTTON_1 + 20;
break;
}
return button;
}
private int findJoystickDevice(int device_id) {
for (int i = 0; i < mJoysticksDevices.size(); i++) {
if (mJoysticksDevices.get(i).device_id == device_id) {
return i;
}
}
return -1;
}
}