-
Notifications
You must be signed in to change notification settings - Fork 2
Open
Description
- https://zhuanlan.zhihu.com/p/30630559
- https://developer.mozilla.org/zh-CN/docs/Web/API/Gamepad
- https://web.dev/doodles-gamepad/
- https://github.com/ArunMichaelDsouza/joypad.js#readme
let AXIS_LXLY = 2007, //左摇杆标识
AXIS_RXRY = 2008, //右摇杆标识
AXIS_LT = 2009, //LT杆标识
AXIS_RT = 2010, //RT杆标识
KEY_DOWN = 2011, // 按键按下
KEY_UP = 2012; // 按键抬起
let gamepadconnected,
gamepaddisconnected;
let gamepadControl = () => {
let hadleStart = null,
controllers = {}, // 手柄控制信息,是个对象
handleStatus = [],
// 准备更新动画时调用此方法
rAF = window.mozRequestAnimationFrame || window.requestAnimationFrame,
// 取消先前通过 requestAnimationFrame 添加到计划中的动画帧请求
rAFStop = window.mozCancelAnimationFrame || window.cancelAnimationFrame,
notStandardMap = {};
const getGamepadsCompatible = () => navigator.getGamepads ? navigator.getGamepads() : navigator.webkitGetGamepads ? navigator.webkitGetGamepads() : [];
gamepadconnected = () => {
WelinkGamePadLoop();
};
gamepaddisconnected = (e) => {
const noGamepads = getGamepadsCompatible().every(o => o === null);
if (noGamepads) {
rAFStop(hadleStart);
}
delete notStandardMap[e.gamepad.index];
}
// 监听手柄连接
// 实测发现,只在第一次连接/第一次按下手柄按键时有用
window.addEventListener('gamepadconnected', gamepadconnected);
// 监听手柄断开
window.addEventListener('gamepaddisconnected', gamepaddisconnected);
// 扫描全部手柄信息
let WelinkScanGamepads = () => {
let gamepads = getGamepadsCompatible();
if (!gamepads) return;
for (let i = 0; i < gamepads.length; i++) {
if (gamepads[i]) {
const index = gamepads[i].index;
if (gamepads[i].mapping !== 'standard') {
if (!notStandardMap[index]) {
notStandardMap[index] = 1;
console.warn(`手柄 '${index}' 按键映射是不标准的,无法使用`);
}
break;
} else {
delete notStandardMap[index];
}
controllers[index] = gamepads[i];
}
}
};
// 物理手柄状态
let WelinkGamePadLoop = () => {
// 开启扫描
WelinkScanGamepads();
// 解析手柄
WelinkhandleShank(controllers);
hadleStart = null;
hadleStart = rAF(WelinkGamePadLoop);
};
// 解析实体手柄
let WelinkhandleShank = (data) => {
for (let j in data) {
let thisStatus = { buttons: [], axes: [] },
handle = data[j],
handModel = handle.id.toLowerCase();
// 遍历按键
for (let i = 0; i < handle.buttons.length; i++) {
let btn = handle.buttons[i],
status = btn.touched ? 1 : 0,
conf = [4096, 8192, 16384, 32768, 256, 512, 255, 255, 32, 16, 64, 128, 1, 2, 4, 8, 0],
type = '';
if (handModel.indexOf('wireless controller') != -1) {
// ps4应该是18个
conf = [4096, 8192, 16384, 32768, 256, 512, 255, 255, 32, 16, 64, 128, 1, 2, 4, 8, 0, 0];
}
type = i == 6 ? 'OP_XINPUT_LEFT_TRIGGER' : i == 7 ? 'OP_XINPUT_RIGHT_TRIGGER' : 'OP_XINPUT_BUTTONS';
if (handleStatus && handleStatus[j]) {
// 有记录的处理
if (handleStatus[j].buttons[i] != status) {
if (btn.touched) {
WelinkSendHald(conf[i], type, j, conf[i]);
} else {
WelinkSendHald(0, type, j, conf[i]);
}
}
} else {
// 无记录的
if (btn.touched) {
WelinkSendHald(conf[i], type, j, conf[i]);
}
}
thisStatus.buttons[i] = status;
}
// 处理摇杆
let rocker = handle.axes,
LX = Math.round(rocker[0] * 32767),
LY = Math.round(rocker[1] * -32767),
RX = Math.round(rocker[2] * 32767),
RY = 0,
CR = 0;
// 判断是否Xbox360模式
if (handModel.indexOf('360') != -1 || handModel.indexOf('xbox') != -1 || handModel.indexOf('wireless controller') != -1) {
// Xbox360模式键位
RY = Math.round(rocker[3] * -32767);
CR = 0;
} else {
//安卓模式键位
RY = Math.round(rocker[5] * -32767);
// 处理十字键
CR = Math.round(rocker[9] * 1000);
}
if (handleStatus && handleStatus[j]) {
// 有记录的处理
if (handleStatus[j].axes[0] != LX) {
WelinkSendHald(LX, 'OP_XINPUT_THUMB_LX', j);
}
if (handleStatus[j].axes[1] != LY) {
WelinkSendHald(LY, 'OP_XINPUT_THUMB_LY', j);
}
if (handleStatus[j].axes[2] != RX) {
WelinkSendHald(RX, 'OP_XINPUT_THUMB_RX', j);
}
if (handleStatus[j].axes[3] != RY) {
WelinkSendHald(RY, 'OP_XINPUT_THUMB_RY', j);
}
if ((handModel.indexOf('360') == -1 && handModel.indexOf('xbox') == -1) || handModel.indexOf('wireless controller') != -1) {
// 处理安卓模式十字键
if (handleStatus[j].axes[4] != CR) {
// 判断是否按下
if (CR <= 1000) {
if (CR == 714) {
WelinkSendHald(4, 'OP_XINPUT_BUTTONS', j, 4);
} else if (CR == 143) {
WelinkSendHald(2, 'OP_XINPUT_BUTTONS', j, 2);
} else if (CR == -429) {
WelinkSendHald(8, 'OP_XINPUT_BUTTONS', j, 8);
} else if (CR == -1000) {
WelinkSendHald(1, 'OP_XINPUT_BUTTONS', j, 1);
}
} else {
WelinkSendHald(0, 'OP_XINPUT_BUTTONS', j);
}
}
}
} else {
// 无记录的
if (LX != 0) {
WelinkSendHald(LX, 'OP_XINPUT_THUMB_LX', j);
}
if (LY != 0) {
WelinkSendHald(LY, 'OP_XINPUT_THUMB_LY', j);
}
if (RX != 0) {
WelinkSendHald(RX, 'OP_XINPUT_THUMB_RX', j);
}
if (RY != 0) {
WelinkSendHald(RY, 'OP_XINPUT_THUMB_RY', j);
}
// 判断是否安卓模式并且按下
if ((handModel.indexOf('360') == -1 && handModel.indexOf('xbox') == -1) || handModel.indexOf('wireless controller') != -1) {
if (CR <= 1000) {
if (CR == 714) {
WelinkSendHald(4, 'OP_XINPUT_BUTTONS', j, 4);
} else if (CR == 143) {
WelinkSendHald(2, 'OP_XINPUT_BUTTONS', j, 2);
} else if (CR == -429) {
WelinkSendHald(8, 'OP_XINPUT_BUTTONS', j, 8);
} else if (CR == -1000) {
WelinkSendHald(1, 'OP_XINPUT_BUTTONS', j, 1);
}
} else {
WelinkSendHald(0, 'OP_XINPUT_BUTTONS', j);
}
}
}
thisStatus.axes = [LX, LY, RX, RY, CR];
// 记录状态
handleStatus[j] = thisStatus;
}
};
};
// 处理虚拟手柄按键<键盘按键/touch事件>
let WelinkOnGamePadButton = (userIndex, keycode, action) => {
if (action == KEY_DOWN) {
WelinkSendHald(keycode * 1, 'OP_XINPUT_BUTTONS', userIndex, keycode * 1);
} else {
WelinkSendHald(0, 'OP_XINPUT_BUTTONS', userIndex, keycode * 1);
}
};
// 处理虚拟手柄摇杆<键盘按键/touch事件>
let WelinkOnGamePadAxis = (userIndex, type, xValue, yValue) => {
// 处理左摇杆
if (type == AXIS_LXLY) {
WelinkSendHald(xValue, 'OP_XINPUT_THUMB_LX', userIndex);
WelinkSendHald(yValue, 'OP_XINPUT_THUMB_LY', userIndex);
}
// 处理右摇杆
if (type == AXIS_RXRY) {
WelinkSendHald(xValue, 'OP_XINPUT_THUMB_RX', userIndex);
WelinkSendHald(yValue, 'OP_XINPUT_THUMB_RY', userIndex);
}
// 处理LT
if (type == AXIS_LT) {
WelinkSendHald(xValue, 'OP_XINPUT_LEFT_TRIGGER', userIndex);
}
// 处理RT
if (type == AXIS_RT) {
WelinkSendHald(yValue, 'OP_XINPUT_RIGHT_TRIGGER', userIndex);
}
};
const clearAllEvents = () => {
window.removeEventListener('gamepadconnected', gamepadconnected);
window.removeEventListener('gamepaddisconnected', gamepaddisconnected);
gamepadconnected = null;
gamepaddisconnected = null;
}
///统一响应按键
let WelinkSendHald = (msg, type = 'OP_XINPUT_BUTTONS', index, action) => {
// let index = index ? parseInt(index) : 0;
if (type == 'OP_XINPUT_BUTTONS') {
if (msg !== 0) {
endMsg += action;
} else {
endMsg -= action;
}
//处理按键
} else {
//处理摇杆和轴等信息
}
};
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels