mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-27 04:08:53 +01:00
47558d20c5
Before this fix, the button and axis IDs are from the OS. These didn't match with the SDL game controller databaes unfortunately. This fix changes the assignments of the buttons and the axes to match with the database. Closes #2312
210 lines
7.1 KiB
Go
210 lines
7.1 KiB
Go
// Copyright 2016 Hajime Hoshi
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package ebitenmobileview
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"hash/crc32"
|
|
"unicode"
|
|
|
|
"github.com/hajimehoshi/ebiten/v2/internal/gamepad"
|
|
"github.com/hajimehoshi/ebiten/v2/internal/gamepaddb"
|
|
"github.com/hajimehoshi/ebiten/v2/internal/ui"
|
|
)
|
|
|
|
// https://developer.android.com/reference/android/view/KeyEvent
|
|
const (
|
|
keycodeButtonA = 0x00000060
|
|
keycodeButtonB = 0x00000061
|
|
keycodeButtonC = 0x00000062
|
|
keycodeButtonX = 0x00000063
|
|
keycodeButtonY = 0x00000064
|
|
keycodeButtonZ = 0x00000065
|
|
keycodeButtonL1 = 0x00000066
|
|
keycodeButtonR1 = 0x00000067
|
|
keycodeButtonL2 = 0x00000068
|
|
keycodeButtonR2 = 0x00000069
|
|
keycodeButtonThumbl = 0x0000006a
|
|
keycodeButtonThumbr = 0x0000006b
|
|
keycodeButtonStart = 0x0000006c
|
|
keycodeButtonSelect = 0x0000006d
|
|
keycodeButtonMode = 0x0000006e
|
|
keycodeButton1 = 0x000000bc
|
|
keycodeButton2 = 0x000000bd
|
|
keycodeButton3 = 0x000000be
|
|
keycodeButton4 = 0x000000bf
|
|
keycodeButton5 = 0x000000c0
|
|
keycodeButton6 = 0x000000c1
|
|
keycodeButton7 = 0x000000c2
|
|
keycodeButton8 = 0x000000c3
|
|
keycodeButton9 = 0x000000c4
|
|
keycodeButton10 = 0x000000c5
|
|
keycodeButton11 = 0x000000c6
|
|
keycodeButton12 = 0x000000c7
|
|
keycodeButton13 = 0x000000c8
|
|
keycodeButton14 = 0x000000c9
|
|
keycodeButton15 = 0x000000ca
|
|
keycodeButton16 = 0x000000cb
|
|
|
|
keycodeDpadUp = 0x00000013
|
|
keycodeDpadDown = 0x00000014
|
|
keycodeDpadLeft = 0x00000015
|
|
keycodeDpadRight = 0x00000016
|
|
keycodeDpadCenter = 0x00000017
|
|
|
|
keycodeBack = 0x00000004
|
|
keycodeMenu = 0x00000052
|
|
)
|
|
|
|
// https://developer.android.com/reference/android/view/InputDevice
|
|
const (
|
|
sourceKeyboard = 0x00000101
|
|
sourceGamepad = 0x00000401
|
|
sourceJoystick = 0x01000010
|
|
)
|
|
|
|
// See https://github.com/libsdl-org/SDL/blob/47f2373dc13b66c48bf4024fcdab53cd0bdd59bb/src/joystick/android/SDL_sysjoystick.c#L71-L172
|
|
// TODO: This exceeds gamepad.SDLControllerButtonMax. Is that OK?
|
|
|
|
var androidKeyToSDL = map[int]int{
|
|
keycodeButtonA: gamepaddb.SDLControllerButtonA,
|
|
keycodeButtonB: gamepaddb.SDLControllerButtonB,
|
|
keycodeButtonX: gamepaddb.SDLControllerButtonX,
|
|
keycodeButtonY: gamepaddb.SDLControllerButtonY,
|
|
keycodeButtonL1: gamepaddb.SDLControllerButtonLeftShoulder,
|
|
keycodeButtonR1: gamepaddb.SDLControllerButtonRightShoulder,
|
|
keycodeButtonThumbl: gamepaddb.SDLControllerButtonLeftStick,
|
|
keycodeButtonThumbr: gamepaddb.SDLControllerButtonRightStick,
|
|
keycodeMenu: gamepaddb.SDLControllerButtonStart,
|
|
keycodeButtonStart: gamepaddb.SDLControllerButtonStart,
|
|
keycodeBack: gamepaddb.SDLControllerButtonBack,
|
|
keycodeButtonSelect: gamepaddb.SDLControllerButtonBack,
|
|
keycodeButtonMode: gamepaddb.SDLControllerButtonGuide,
|
|
keycodeButtonL2: 15,
|
|
keycodeButtonR2: 16,
|
|
keycodeButtonC: 17,
|
|
keycodeButtonZ: 18,
|
|
keycodeDpadUp: gamepaddb.SDLControllerButtonDpadUp,
|
|
keycodeDpadDown: gamepaddb.SDLControllerButtonDpadDown,
|
|
keycodeDpadLeft: gamepaddb.SDLControllerButtonDpadLeft,
|
|
keycodeDpadRight: gamepaddb.SDLControllerButtonDpadRight,
|
|
keycodeDpadCenter: gamepaddb.SDLControllerButtonA,
|
|
keycodeButton1: 20,
|
|
keycodeButton2: 21,
|
|
keycodeButton3: 22,
|
|
keycodeButton4: 23,
|
|
keycodeButton5: 24,
|
|
keycodeButton6: 25,
|
|
keycodeButton7: 26,
|
|
keycodeButton8: 27,
|
|
keycodeButton9: 28,
|
|
keycodeButton10: 29,
|
|
keycodeButton11: 30,
|
|
keycodeButton12: 31,
|
|
keycodeButton13: 32,
|
|
keycodeButton14: 33,
|
|
keycodeButton15: 34,
|
|
keycodeButton16: 35,
|
|
}
|
|
|
|
func UpdateTouchesOnAndroid(action int, id int, x, y int) {
|
|
switch action {
|
|
case 0x00, 0x05, 0x02: // ACTION_DOWN, ACTION_POINTER_DOWN, ACTION_MOVE
|
|
touches[ui.TouchID(id)] = position{x, y}
|
|
updateInput()
|
|
case 0x01, 0x06: // ACTION_UP, ACTION_POINTER_UP
|
|
delete(touches, ui.TouchID(id))
|
|
updateInput()
|
|
}
|
|
}
|
|
|
|
func OnKeyDownOnAndroid(keyCode int, unicodeChar int, source int, deviceID int) {
|
|
switch {
|
|
case source&sourceGamepad == sourceGamepad:
|
|
// A gamepad can be detected as a keyboard. Detect the device as a gamepad first.
|
|
if button, ok := androidKeyToSDL[keyCode]; ok {
|
|
gamepad.UpdateAndroidGamepadButton(deviceID, gamepad.Button(button), true)
|
|
}
|
|
case source&sourceJoystick == sourceJoystick:
|
|
// DPAD keys can come here, but they are also treated as an axis at a motion event. Ignore them.
|
|
case source&sourceKeyboard == sourceKeyboard:
|
|
if key, ok := androidKeyToUIKey[keyCode]; ok {
|
|
keys[key] = struct{}{}
|
|
if r := rune(unicodeChar); r != 0 && unicode.IsPrint(r) {
|
|
runes = []rune{r}
|
|
}
|
|
updateInput()
|
|
}
|
|
}
|
|
}
|
|
|
|
func OnKeyUpOnAndroid(keyCode int, source int, deviceID int) {
|
|
switch {
|
|
case source&sourceGamepad == sourceGamepad:
|
|
// A gamepad can be detected as a keyboard. Detect the device as a gamepad first.
|
|
if button, ok := androidKeyToSDL[keyCode]; ok {
|
|
gamepad.UpdateAndroidGamepadButton(deviceID, gamepad.Button(button), false)
|
|
}
|
|
case source&sourceJoystick == sourceJoystick:
|
|
// DPAD keys can come here, but they are also treated as an axis at a motion event. Ignore them.
|
|
case source&sourceKeyboard == sourceKeyboard:
|
|
if key, ok := androidKeyToUIKey[keyCode]; ok {
|
|
delete(keys, key)
|
|
updateInput()
|
|
}
|
|
}
|
|
}
|
|
|
|
func OnGamepadAxisChanged(deviceID int, axisID int, value float32) {
|
|
gamepad.UpdateAndroidGamepadAxis(deviceID, axisID, float64(value))
|
|
}
|
|
|
|
func OnGamepadHatChanged(deviceID int, hatID int, xValue, yValue int) {
|
|
gamepad.UpdateAndroidGamepadHat(deviceID, hatID, xValue, yValue)
|
|
}
|
|
|
|
func OnGamepadAdded(deviceID int, name string, axisCount int, hatCount int, descriptor string, vendorID int, productID int, buttonMask int, axisMask int) {
|
|
// This emulates the implementation of Android_AddJoystick.
|
|
// https://github.com/libsdl-org/SDL/blob/0e9560aea22818884921e5e5064953257bfe7fa7/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)
|
|
|
|
gamepad.AddAndroidGamepad(deviceID, name, hex.EncodeToString(sdlid[:]), axisCount, hatCount)
|
|
}
|
|
|
|
func OnInputDeviceRemoved(deviceID int) {
|
|
gamepad.RemoveAndroidGamepad(deviceID)
|
|
}
|