mirror of
https://github.com/giongto35/cloud-game.git
synced 2026-01-23 10:35:44 +00:00
278 lines
8.6 KiB
JavaScript
Vendored
278 lines
8.6 KiB
JavaScript
Vendored
/**
|
|
* Joystick controls.
|
|
*
|
|
* cross == a <--> a
|
|
* circle == b <--> b
|
|
* square == x <--> start
|
|
* triangle == y <--> select
|
|
* share <--> load
|
|
* option <--> save
|
|
* L2 == LT <--> full
|
|
* R2 == RT <--> quit
|
|
* dpad <--> up down left right
|
|
* axis 0, 1 <--> second dpad
|
|
*
|
|
* change full to help (temporary)
|
|
*
|
|
* @version 1
|
|
*/
|
|
const joystick = (() => {
|
|
const deadZone = 0.1;
|
|
let joystickMap;
|
|
let joystickState = {};
|
|
let joystickAxes = [];
|
|
let joystickIdx;
|
|
let joystickTimer = null;
|
|
let dpadMode = true;
|
|
|
|
function onDpadToggle(checked) {
|
|
if (dpadMode === checked) {
|
|
return //error?
|
|
}
|
|
if (dpadMode) {
|
|
dpadMode = false;
|
|
// reset dpad keys pressed before moving to analog stick mode
|
|
checkJoystickAxisState(KEY.LEFT, false);
|
|
checkJoystickAxisState(KEY.RIGHT, false);
|
|
checkJoystickAxisState(KEY.UP, false);
|
|
checkJoystickAxisState(KEY.DOWN, false);
|
|
} else {
|
|
dpadMode = true;
|
|
// reset analog stick axes before moving to dpad mode
|
|
joystickAxes.forEach(function (value, index) {
|
|
checkJoystickAxis(index, 0);
|
|
});
|
|
}
|
|
}
|
|
|
|
// check state for each axis -> dpad
|
|
function checkJoystickAxisState(name, state) {
|
|
if (joystickState[name] !== state) {
|
|
joystickState[name] = state;
|
|
event.pub(state === true ? KEY_PRESSED : KEY_RELEASED, {key: name});
|
|
}
|
|
}
|
|
|
|
function checkJoystickAxis(axis, value) {
|
|
if (-deadZone < value && value < deadZone) value = 0;
|
|
if (joystickAxes[axis] !== value) {
|
|
joystickAxes[axis] = value;
|
|
event.pub(AXIS_CHANGED, {id: axis, value: value});
|
|
}
|
|
}
|
|
|
|
// loop timer for checking joystick state
|
|
function checkJoystickState() {
|
|
let gamepad = navigator.getGamepads()[joystickIdx];
|
|
if (gamepad) {
|
|
if (dpadMode) {
|
|
// axis -> dpad
|
|
let corX = gamepad.axes[0]; // -1 -> 1, left -> right
|
|
let corY = gamepad.axes[1]; // -1 -> 1, up -> down
|
|
checkJoystickAxisState(KEY.LEFT, corX <= -0.5);
|
|
checkJoystickAxisState(KEY.RIGHT, corX >= 0.5);
|
|
checkJoystickAxisState(KEY.UP, corY <= -0.5);
|
|
checkJoystickAxisState(KEY.DOWN, corY >= 0.5);
|
|
} else {
|
|
gamepad.axes.forEach(function (value, index) {
|
|
checkJoystickAxis(index, value);
|
|
});
|
|
}
|
|
|
|
// normal button map
|
|
Object.keys(joystickMap).forEach(function (btnIdx) {
|
|
const buttonState = gamepad.buttons[btnIdx];
|
|
|
|
const isPressed = navigator.webkitGetGamepads ? buttonState === 1 :
|
|
buttonState.value > 0 || buttonState.pressed === true;
|
|
|
|
if (joystickState[btnIdx] !== isPressed) {
|
|
joystickState[btnIdx] = isPressed;
|
|
event.pub(isPressed === true ? KEY_PRESSED : KEY_RELEASED, {key: joystickMap[btnIdx]});
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
// we only capture the last plugged joystick
|
|
const onGamepadConnected = (e) => {
|
|
let gamepad = e.gamepad;
|
|
log.info(`Gamepad connected at index ${gamepad.index}: ${gamepad.id}. ${gamepad.buttons.length} buttons, ${gamepad.axes.length} axes.`);
|
|
|
|
joystickIdx = gamepad.index;
|
|
|
|
// Ref: https://github.com/giongto35/cloud-game/issues/14
|
|
// get mapping first (default KeyMap2)
|
|
let os = env.getOs();
|
|
let browser = env.getBrowser();
|
|
|
|
if (os === 'android') {
|
|
// default of android is KeyMap1
|
|
joystickMap = {
|
|
2: KEY.A,
|
|
0: KEY.B,
|
|
3: KEY.START,
|
|
4: KEY.SELECT,
|
|
10: KEY.LOAD,
|
|
11: KEY.SAVE,
|
|
8: KEY.HELP,
|
|
9: KEY.QUIT,
|
|
12: KEY.UP,
|
|
13: KEY.DOWN,
|
|
14: KEY.LEFT,
|
|
15: KEY.RIGHT
|
|
};
|
|
} else {
|
|
// default of other OS is KeyMap2
|
|
joystickMap = {
|
|
0: KEY.A,
|
|
1: KEY.B,
|
|
2: KEY.START,
|
|
3: KEY.SELECT,
|
|
8: KEY.LOAD,
|
|
9: KEY.SAVE,
|
|
6: KEY.HELP,
|
|
7: KEY.QUIT,
|
|
12: KEY.UP,
|
|
13: KEY.DOWN,
|
|
14: KEY.LEFT,
|
|
15: KEY.RIGHT
|
|
};
|
|
}
|
|
|
|
if (os === 'android' && (browser === 'firefox' || browser === 'uc')) { //KeyMap2
|
|
joystickMap = {
|
|
0: KEY.A,
|
|
1: KEY.B,
|
|
2: KEY.START,
|
|
3: KEY.SELECT,
|
|
8: KEY.LOAD,
|
|
9: KEY.SAVE,
|
|
6: KEY.HELP,
|
|
7: KEY.QUIT,
|
|
12: KEY.UP,
|
|
13: KEY.DOWN,
|
|
14: KEY.LEFT,
|
|
15: KEY.RIGHT
|
|
};
|
|
}
|
|
|
|
if (os === 'win' && browser === 'firefox') { //KeyMap3
|
|
joystickMap = {
|
|
1: KEY.A,
|
|
2: KEY.B,
|
|
0: KEY.START,
|
|
3: KEY.SELECT,
|
|
8: KEY.LOAD,
|
|
9: KEY.SAVE,
|
|
6: KEY.HELP,
|
|
7: KEY.QUIT
|
|
};
|
|
}
|
|
|
|
if (os === 'mac' && browser === 'safari') { //KeyMap4
|
|
joystickMap = {
|
|
1: KEY.A,
|
|
2: KEY.B,
|
|
0: KEY.START,
|
|
3: KEY.SELECT,
|
|
8: KEY.LOAD,
|
|
9: KEY.SAVE,
|
|
6: KEY.HELP,
|
|
7: KEY.QUIT,
|
|
14: KEY.UP,
|
|
15: KEY.DOWN,
|
|
16: KEY.LEFT,
|
|
17: KEY.RIGHT
|
|
};
|
|
}
|
|
|
|
if (os === 'mac' && browser === 'firefox') { //KeyMap5
|
|
joystickMap = {
|
|
1: KEY.A,
|
|
2: KEY.B,
|
|
0: KEY.START,
|
|
3: KEY.SELECT,
|
|
8: KEY.LOAD,
|
|
9: KEY.SAVE,
|
|
6: KEY.HELP,
|
|
7: KEY.QUIT,
|
|
14: KEY.UP,
|
|
15: KEY.DOWN,
|
|
16: KEY.LEFT,
|
|
17: KEY.RIGHT
|
|
};
|
|
}
|
|
|
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=1076272
|
|
if (gamepad.id.includes('PLAYSTATION(R)3')) {
|
|
if (browser === 'chrome') {
|
|
joystickMap = {
|
|
1: KEY.A,
|
|
0: KEY.B,
|
|
2: KEY.Y,
|
|
3: KEY.X,
|
|
4: KEY.L,
|
|
5: KEY.R,
|
|
8: KEY.SELECT,
|
|
9: KEY.START,
|
|
10: KEY.DTOGGLE,
|
|
11: KEY.R3,
|
|
};
|
|
} else {
|
|
joystickMap = {
|
|
13: KEY.A,
|
|
14: KEY.B,
|
|
12: KEY.X,
|
|
15: KEY.Y,
|
|
3: KEY.START,
|
|
0: KEY.SELECT,
|
|
4: KEY.UP,
|
|
6: KEY.DOWN,
|
|
7: KEY.LEFT,
|
|
5: KEY.RIGHT,
|
|
10: KEY.L,
|
|
11: KEY.R,
|
|
8: KEY.L2,
|
|
9: KEY.R2,
|
|
1: KEY.DTOGGLE,
|
|
2: KEY.R3,
|
|
};
|
|
}
|
|
}
|
|
|
|
// reset state
|
|
joystickState = {[KEY.LEFT]: false, [KEY.RIGHT]: false, [KEY.UP]: false, [KEY.DOWN]: false};
|
|
Object.keys(joystickMap).forEach(function (btnIdx) {
|
|
joystickState[btnIdx] = false;
|
|
});
|
|
|
|
joystickAxes = new Array(gamepad.axes.length).fill(0);
|
|
|
|
// looper, too intense?
|
|
if (joystickTimer !== null) {
|
|
clearInterval(joystickTimer);
|
|
}
|
|
|
|
joystickTimer = setInterval(checkJoystickState, 10); // miliseconds per hit
|
|
event.pub(GAMEPAD_CONNECTED);
|
|
};
|
|
|
|
event.sub(DPAD_TOGGLE, (data) => onDpadToggle(data.checked));
|
|
|
|
return {
|
|
init: () => {
|
|
// we only capture the last plugged joystick
|
|
window.addEventListener('gamepadconnected', onGamepadConnected);
|
|
|
|
// disconnected event is triggered
|
|
window.addEventListener('gamepaddisconnected', (event) => {
|
|
clearInterval(joystickTimer);
|
|
log.info(`Gamepad disconnected at index ${event.gamepad.index}`);
|
|
event.pub(GAMEPAD_DISCONNECTED);
|
|
});
|
|
|
|
log.info('[input] joystick has been initialized');
|
|
}
|
|
}
|
|
})(event, env, KEY, navigator, window);
|