jsnes
jsnes copied to clipboard
Gamepad web API integration
🎮
https://developer.mozilla.org/en-US/docs/Web/API/Gamepad_API/Using_the_Gamepad_API
YES PLEASE!
It's a pretty straighforward process for adapting the HTML5 gamepad API. Feel free to modify any of what I've done to suit your needs. This was a service I wrote in Angular 4. Sorry about the styling, couldn't get it to fit into a single code tag ` import { Injectable } from "@angular/core"; import { BehaviorSubject } from "rxjs/BehaviorSubject"; import { Observable } from "rxjs/Rx";
import { Controller } from "jsnes";
@Injectable() export class GamepadService { private scanTimer: any; private gamepadHash: boolean[] = []; player1Device: InputDevice = this.availableDevices()[0]; private player2Device: any = "Keyboard";
private msgSource = new BehaviorSubject<InputButton>(null);
changed = this.msgSource.asObservable();
constructor() { }
gamepadMap = {
0: Controller.BUTTON_A,
1: Controller.BUTTON_B,
8: Controller.BUTTON_SELECT,
9: Controller.BUTTON_START,
12: Controller.BUTTON_UP,
13: Controller.BUTTON_DOWN,
14: Controller.BUTTON_LEFT,
15: Controller.BUTTON_RIGHT
};
KEYS = {
88: Controller.BUTTON_A, // X
89: Controller.BUTTON_B, // Y (Central European keyboard)
90: Controller.BUTTON_B, // Z
17: Controller.BUTTON_SELECT, // Right Ctrl
13: Controller.BUTTON_START, // Enter
38: Controller.BUTTON_UP, // Up
40: Controller.BUTTON_DOWN, // Down
37: Controller.BUTTON_LEFT, // Left
39: Controller.BUTTON_RIGHT, // Right
/*103: [2, Controller.BUTTON_A], // Num-7
105: [2, Controller.BUTTON_B], // Num-9
99: [2, Controller.BUTTON_SELECT], // Num-3
97: [2, Controller.BUTTON_START], // Num-1
104: [2, Controller.BUTTON_UP], // Num-8
98: [2, Controller.BUTTON_DOWN], // Num-2
100: [2, Controller.BUTTON_LEFT], // Num-4
102: [2, Controller.BUTTON_RIGHT], // Num-6*/
};
update(button: InputButton) {
this.msgSource.next(button);
}
gamepadSupported(): boolean {
return "getGamepads" in navigator;
}
availableDevices(): InputDevice[] {
var devices: InputDevice[] = [];
if(!this.gamepadSupported()) return [new InputDevice({ id: 0, isGamepad: false, name: "Keyboard" })];
var gamepads = navigator.getGamepads();
for(var i = 0; i < gamepads.length; ++i) {
if(gamepads[i] != null && this.isValidGamepad(gamepads[i])) {
devices.push(new InputDevice({ id: devices.length, isGamepad: true, name: gamepads[i].id }));
}
}
devices.push(new InputDevice({ id: devices.length, isGamepad: false, name: "Keyboard" }));
return devices;
}
connect() {
document.addEventListener("keydown", this.keydown.bind(this));
document.addEventListener("keyup", this.keyup.bind(this));
for(let key of Object.keys(this.gamepadMap)) {
this.gamepadHash.push(false);
}
this.scanTimer = Observable.interval(100);
this.scanTimer.subscribe(x => { this.onGamepad() });
}
disconnect() {
document.removeEventListener("keydown", this.keydown);
document.removeEventListener("keyup", this.keyup);
}
setPlayerDevice(id: number) {
var devices = this.availableDevices();
if(id >= devices.length) throw new Error("Input device doesn't exist");
this.player1Device = devices[id];
return devices[id];
}
onGamepad() {
if(!this.player1Device.isGamepad) return;
var gp = this.getSystemDevice(this.player1Device);
if(gp == null) return;
var id = gp.id;
Object.keys(this.gamepadMap).forEach((key, index) => {
var btn = gp.buttons[key];
if(btn.pressed != this.gamepadHash[index]) {
this.gamepadHash[index] = btn.pressed;
this.update(new InputButton({ button: this.gamepadMap[key], pressed: btn.pressed, player: 1 }));
}
});
}
keydown(e) {
if(this.player1Device.isGamepad) return;
var code = this.KEYS[e.keyCode];
if(code == undefined) return;
this.update(new InputButton({ button: code, pressed: true, player: 1 }));
}
keyup(e) {
if(this.player1Device.isGamepad) return;
var code = this.KEYS[e.keyCode];
if(code == undefined) return;
this.update(new InputButton({ button: code, pressed: false, player: 1 }));
}
private isValidGamepad(gp: Gamepad):boolean {
return gp.buttons.length >= 6;
}
private getSystemDevice(device: InputDevice) {
var gamepads = navigator.getGamepads();
for(var i = 0; i < gamepads.length; ++i) {
if(gamepads[i].id == device.name) return gamepads[i];
}
return null;
}
}
export class InputButton { button: any; pressed: boolean; player: number;
public constructor(init?:Partial<InputButton>) {
Object.assign(this, init);
}
} export class InputDevice { id: number; isGamepad: boolean; name: string;
public constructor(init?:Partial<InputDevice>) {
Object.assign(this, init);
}
}`
@brianushman Do you have any reference for onscreen controller?