Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【手柄操作】gamepad api #126

Open
AlexZ33 opened this issue Sep 5, 2022 · 0 comments
Open

【手柄操作】gamepad api #126

AlexZ33 opened this issue Sep 5, 2022 · 0 comments

Comments

@AlexZ33
Copy link
Owner

AlexZ33 commented Sep 5, 2022




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 {
        //处理摇杆和轴等信息
    }
};



Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant