mobile/ebitenmobileview: Implement gamepads' SDLID on Android

Fixes #1083
This commit is contained in:
Hajime Hoshi 2020-03-25 01:40:25 +09:00
parent 4ec49dd4cf
commit bc3d1393a6
3 changed files with 164 additions and 4 deletions

View File

@ -532,7 +532,140 @@ public class EbitenView extends ViewGroup implements InputManager.InputDeviceLis
axisNum--;
}
Ebitenmobileview.onGamepadAdded(deviceId, inputDevice.getName(), buttonNum, axisNum);
String descriptor = inputDevice.getDescriptor();
int vendorId = inputDevice.getVendorId();
int productId = inputDevice.getProductId();
// These values are required to calculate SDL's GUID.
int buttonMask = getButtonMask(inputDevice);
int axisMask = getAxisMask(inputDevice);
Ebitenmobileview.onGamepadAdded(deviceId, inputDevice.getName(), buttonNum, axisNum, descriptor, vendorId, productId, buttonMask, axisMask);
}
// The implementation is copied from SDL:
// https://hg.libsdl.org/SDL/file/bc90ce38f1e2/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java#l308
private int getButtonMask(InputDevice joystickDevice) {
int button_mask = 0;
int[] keys = new int[] {
KeyEvent.KEYCODE_BUTTON_A,
KeyEvent.KEYCODE_BUTTON_B,
KeyEvent.KEYCODE_BUTTON_X,
KeyEvent.KEYCODE_BUTTON_Y,
KeyEvent.KEYCODE_BACK,
KeyEvent.KEYCODE_BUTTON_MODE,
KeyEvent.KEYCODE_BUTTON_START,
KeyEvent.KEYCODE_BUTTON_THUMBL,
KeyEvent.KEYCODE_BUTTON_THUMBR,
KeyEvent.KEYCODE_BUTTON_L1,
KeyEvent.KEYCODE_BUTTON_R1,
KeyEvent.KEYCODE_DPAD_UP,
KeyEvent.KEYCODE_DPAD_DOWN,
KeyEvent.KEYCODE_DPAD_LEFT,
KeyEvent.KEYCODE_DPAD_RIGHT,
KeyEvent.KEYCODE_BUTTON_SELECT,
KeyEvent.KEYCODE_DPAD_CENTER,
// These don't map into any SDL controller buttons directly
KeyEvent.KEYCODE_BUTTON_L2,
KeyEvent.KEYCODE_BUTTON_R2,
KeyEvent.KEYCODE_BUTTON_C,
KeyEvent.KEYCODE_BUTTON_Z,
KeyEvent.KEYCODE_BUTTON_1,
KeyEvent.KEYCODE_BUTTON_2,
KeyEvent.KEYCODE_BUTTON_3,
KeyEvent.KEYCODE_BUTTON_4,
KeyEvent.KEYCODE_BUTTON_5,
KeyEvent.KEYCODE_BUTTON_6,
KeyEvent.KEYCODE_BUTTON_7,
KeyEvent.KEYCODE_BUTTON_8,
KeyEvent.KEYCODE_BUTTON_9,
KeyEvent.KEYCODE_BUTTON_10,
KeyEvent.KEYCODE_BUTTON_11,
KeyEvent.KEYCODE_BUTTON_12,
KeyEvent.KEYCODE_BUTTON_13,
KeyEvent.KEYCODE_BUTTON_14,
KeyEvent.KEYCODE_BUTTON_15,
KeyEvent.KEYCODE_BUTTON_16,
};
int[] masks = new int[] {
(1 << 0), // A -> A
(1 << 1), // B -> B
(1 << 2), // X -> X
(1 << 3), // Y -> Y
(1 << 4), // BACK -> BACK
(1 << 5), // MODE -> GUIDE
(1 << 6), // START -> START
(1 << 7), // THUMBL -> LEFTSTICK
(1 << 8), // THUMBR -> RIGHTSTICK
(1 << 9), // L1 -> LEFTSHOULDER
(1 << 10), // R1 -> RIGHTSHOULDER
(1 << 11), // DPAD_UP -> DPAD_UP
(1 << 12), // DPAD_DOWN -> DPAD_DOWN
(1 << 13), // DPAD_LEFT -> DPAD_LEFT
(1 << 14), // DPAD_RIGHT -> DPAD_RIGHT
(1 << 4), // SELECT -> BACK
(1 << 0), // DPAD_CENTER -> A
(1 << 15), // L2 -> ??
(1 << 16), // R2 -> ??
(1 << 17), // C -> ??
(1 << 18), // Z -> ??
(1 << 20), // 1 -> ??
(1 << 21), // 2 -> ??
(1 << 22), // 3 -> ??
(1 << 23), // 4 -> ??
(1 << 24), // 5 -> ??
(1 << 25), // 6 -> ??
(1 << 26), // 7 -> ??
(1 << 27), // 8 -> ??
(1 << 28), // 9 -> ??
(1 << 29), // 10 -> ??
(1 << 30), // 11 -> ??
(1 << 31), // 12 -> ??
// We're out of room...
0xFFFFFFFF, // 13 -> ??
0xFFFFFFFF, // 14 -> ??
0xFFFFFFFF, // 15 -> ??
0xFFFFFFFF, // 16 -> ??
};
boolean[] has_keys = joystickDevice.hasKeys(keys);
for (int i = 0; i < keys.length; ++i) {
if (has_keys[i]) {
button_mask |= masks[i];
}
}
return button_mask;
}
private int getAxisMask(InputDevice joystickDevice) {
final int SDL_CONTROLLER_AXIS_LEFTX = 0;
final int SDL_CONTROLLER_AXIS_LEFTY = 1;
final int SDL_CONTROLLER_AXIS_RIGHTX = 2;
final int SDL_CONTROLLER_AXIS_RIGHTY = 3;
final int SDL_CONTROLLER_AXIS_TRIGGERLEFT = 4;
final int SDL_CONTROLLER_AXIS_TRIGGERRIGHT = 5;
int naxes = 0;
for (InputDevice.MotionRange range : joystickDevice.getMotionRanges()) {
if ((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
if (range.getAxis() != MotionEvent.AXIS_HAT_X && range.getAxis() != MotionEvent.AXIS_HAT_Y) {
naxes++;
}
}
}
// The variable is_accelerometer seems always false, then skip the checking:
// https://hg.libsdl.org/SDL/file/bc90ce38f1e2/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java#l207
int axisMask = 0;
if (naxes >= 2) {
axisMask |= ((1 << SDL_CONTROLLER_AXIS_LEFTX) | (1 << SDL_CONTROLLER_AXIS_LEFTY));
}
if (naxes >= 4) {
axisMask |= ((1 << SDL_CONTROLLER_AXIS_RIGHTX) | (1 << SDL_CONTROLLER_AXIS_RIGHTY));
}
if (naxes >= 6) {
axisMask |= ((1 << SDL_CONTROLLER_AXIS_TRIGGERLEFT) | (1 << SDL_CONTROLLER_AXIS_TRIGGERRIGHT));
}
return axisMask;
}
@Override

File diff suppressed because one or more lines are too long

View File

@ -15,6 +15,8 @@
package ebitenmobileview
import (
"encoding/hex"
"hash/crc32"
"unicode"
"github.com/hajimehoshi/ebiten/internal/driver"
@ -277,11 +279,36 @@ func OnGamepadAxesChanged(deviceID int, axisID int, value float32) {
updateInput()
}
func OnGamepadAdded(deviceID int, name string, buttonNum int, axisNum int) {
func OnGamepadAdded(deviceID int, name string, buttonNum int, axisNum int, descriptor string, vendorID int, productID int, buttonMask int, axisMask int) {
// This emulates the implementation of Android_AddJoystick.
// https://hg.libsdl.org/SDL/file/bc90ce38f1e2/src/joystick/android/SDL_sysjoystick.c#l386
const SDL_HARDWARE_BUS_BLUETOOTH = 0x05
var sdlid [16]byte
sdlid[0] = byte(SDL_HARDWARE_BUS_BLUETOOTH)
sdlid[1] = byte(SDL_HARDWARE_BUS_BLUETOOTH >> 8)
if vendorID != 0 && productID != 0 {
sdlid[4] = byte(vendorID)
sdlid[5] = byte(vendorID >> 8)
sdlid[8] = byte(productID)
sdlid[9] = byte(productID >> 8)
} else {
crc := crc32.ChecksumIEEE(([]byte)(descriptor))
copy(sdlid[4:8], ([]byte)(descriptor))
sdlid[8] = byte(crc)
sdlid[9] = byte(crc >> 8)
sdlid[10] = byte(crc >> 16)
sdlid[11] = byte(crc >> 24)
}
sdlid[12] = byte(buttonMask)
sdlid[13] = byte(buttonMask >> 8)
sdlid[14] = byte(axisMask)
sdlid[15] = byte(axisMask >> 8)
id := gamepadIDFromDeviceID(deviceID)
gamepads[id] = &mobile.Gamepad{
ID: id,
SDLID: "", // TODO: Implement this
SDLID: hex.EncodeToString(sdlid[:]),
Name: name,
ButtonNum: buttonNum,
AxisNum: axisNum,