Skip to content

Commit

Permalink
made it easier to get ordinal primary/secondary buttons (#47)
Browse files Browse the repository at this point in the history
* made it easier to get ordinal primary/secondary buttons

* bump version

* fix tests and lint
  • Loading branch information
lunarcloud authored Dec 14, 2023
1 parent 827d79e commit ffa8926
Show file tree
Hide file tree
Showing 8 changed files with 625 additions and 144 deletions.
15 changes: 9 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,19 @@ const gameInput = new GameInput()
.onButtonDown((playerIndex, sectionName, buttonName) => {
const player = gameInput.getPlayer(playerIndex)
console.debug(`Player ${player} pushed ${player.getButtonText(sectionName, buttonName)} (${buttonName})`)
switch (buttonName) {
case GameInputButtons.menu:
break
default:
break
}
})
.onButtonUp((playerIndex, sectionName, buttonName) => {
const player = gameInput.getPlayer(playerIndex)
console.debug(`Player ${player} released ${player.getButtonText(sectionName, buttonName)} (${buttonName})`)
if (sectionName === 'center' && buttonName === 'menu') {
console.debug('menu requested')
return
}
if (sectionName === 'face' && buttonName === player.schema.ordinalButton(0)) {
console.debug('Jump / Confirm pushed')
}
})
// Game-Loop Style
Expand Down
4 changes: 2 additions & 2 deletions demo/tester.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ const gi = new GameInput()
el.textContent = gi.Players[i].getButtonText(sectionName, buttonName)
}

/** @type {Button} */
/** @type {HTMLButtonElement} */
const weakRumbleEl = clone.querySelector('.rumble .weak')
/** @type {Button} */
/** @type {HTMLButtonElement} */
const strongRumbleEl = clone.querySelector('.rumble .strong')

if (gi.Players[i].hasRumble()) {
Expand Down
589 changes: 509 additions & 80 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"publishConfig": {
"@lunarcloud:registry": "https://npm.pkg.github.com"
},
"version": "13.0.1",
"version": "13.1.0",
"description": "Browser library to upgrade the Gamepad API experience",
"private": false,
"scripts": {
Expand Down Expand Up @@ -39,6 +39,7 @@
"license": "MIT",
"author": "Samuel Sarette",
"jest": {
"testEnvironment": "jsdom",
"verbose": true,
"reporters": [
[
Expand All @@ -50,5 +51,8 @@
"default"
],
"testLocationInResults": true
},
"dependencies": {
"jest-environment-jsdom": "^29.7.0"
}
}
4 changes: 2 additions & 2 deletions src/gameinput-models.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ const GameInputModels = [
'Windows',
StandardGamepadMapping.variant({
dpad: new GamepadDirectionsMapping(12, 15, 13, 14),
face: new GamepadFaceMapping(3, 1, 0, 2),
face: new GamepadFaceMapping(3, 1, 0, 2)
})
),
new GameInputModel(
Expand Down Expand Up @@ -428,7 +428,7 @@ const GameInputModels = [
'USB Gamepad (STANDARD GAMEPAD Vendor: 0079 Product: 0011)',
'Windows',
StandardGamepadMapping.variant({
face: new GamepadFaceMapping(2,0, 1, 3),
face: new GamepadFaceMapping(2, 0, 1, 3),
shoulder: new GamepadLRMapping(6, 7),
trigger: new GamepadLRMapping(5, 4),
leftStick: undefined,
Expand Down
135 changes: 90 additions & 45 deletions src/gameinput-schema.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { FaceDirections, IsJapan } from './gamepad-mapping.js'

/**
* @typedef {{ up: GameInputSchemaButtonName, down: GameInputSchemaButtonName, left: GameInputSchemaButtonName, right: GameInputSchemaButtonName }} GameInputSchemaDirectionNames
*/
Expand Down Expand Up @@ -44,6 +46,22 @@
* @property {GameInputSchemaLRNames} [trigger] trigger override
*/

/**
* Get button name by ordinal priority and direction.
* @param {number} value button ordinal (0 for primary/accept, 1 for secondary/cancel, etc)
* @param {import('./gamepad-mapping.js').FaceDirection|boolean} ltr if Left-to-Right (false for rtl)
* @returns {GameInputSchemaButtonName} button name.
*/
export function OrdinalButtonName (value, ltr) {
switch (value) {
case 0: return ltr ? 'down' : 'right'
case 1: return ltr ? 'right' : 'down'
case 2: return ltr ? 'left' : 'up'
case 3: return ltr ? 'up' : 'left'
default: return undefined
}
}

/**
* Possible Section Names
* @type {GameInputSchemaSectionNames}
Expand Down Expand Up @@ -72,7 +90,6 @@ export const GameInputSchemaButtonNames = {
click: 'click'
}


/**
* Defines what each button is displayed as, what should be on the physical device for each button.
*/
Expand Down Expand Up @@ -167,7 +184,7 @@ export class GameInputSchema {
/**
* Sega/Xbox style
*/
static Hedgehog = new GameInputSchema('Hedgehog', {
static Hedgehog = new GameInputSchema('Hedgehog', FaceDirections.ltr, {
face: {
up: 'Y',
down: 'A',
Expand All @@ -187,7 +204,7 @@ export class GameInputSchema {
/**
* Nintendo style
*/
static Plumber = new GameInputSchema('Plumber', {
static Plumber = new GameInputSchema('Plumber', FaceDirections.rtl, {
face: {
up: 'X',
down: 'B',
Expand All @@ -211,7 +228,7 @@ export class GameInputSchema {
/**
* Nintendo64 style
*/
static PlumberTrident = new GameInputSchema('Plumber', {
static PlumberTrident = new GameInputSchema('Plumber', FaceDirections.rtl, {
face: {
up: '',
down: 'A',
Expand All @@ -235,7 +252,7 @@ export class GameInputSchema {
/**
* Nintendo Gamecube style
*/
static PlumberCube = new GameInputSchema('Plumber', {
static PlumberCube = new GameInputSchema('Plumber', FaceDirections.rtl, {
face: {
up: 'Y',
down: 'A',
Expand All @@ -259,7 +276,7 @@ export class GameInputSchema {
/**
* Nintendo style (Horizontal Right Joy-Con)
*/
static PlumberRotatedRight = new GameInputSchema('Plumber', {
static PlumberRotatedRight = new GameInputSchema('Plumber', FaceDirections.rtl, {
face: {
up: 'Y',
down: 'A',
Expand All @@ -283,7 +300,7 @@ export class GameInputSchema {
/**
* Nintendo style (Horizontal Left Joy-Con)
*/
static PlumberRotatedLeft = new GameInputSchema('Plumber', {
static PlumberRotatedLeft = new GameInputSchema('Plumber', FaceDirections.rtl, {
face: {
up: '↑',
down: '↓',
Expand All @@ -307,45 +324,47 @@ export class GameInputSchema {
/**
* Older Sony style
*/
static RagdollOld = new GameInputSchema('Ragdoll', {
face: {
up: '△',
down: 'x',
left: '□',
right: 'o'
},
center: {
menu: 'start',
back: 'select'
},
shoulder: {
left: 'L1',
right: 'R1'
},
trigger: {
left: 'L2',
right: 'R2'
},
leftStick: {
up: '↑',
down: '↓',
left: '←',
right: '→',
click: 'L3'
},
rightStick: {
up: '↑',
down: '↓',
left: '←',
right: '→',
click: 'R3'
}
})
static RagdollOld = new GameInputSchema('Ragdoll',
IsJapan ? FaceDirections.rtl : FaceDirections.ltr,
{
face: {
up: '△',
down: 'x',
left: '□',
right: 'o'
},
center: {
menu: 'start',
back: 'select'
},
shoulder: {
left: 'L1',
right: 'R1'
},
trigger: {
left: 'L2',
right: 'R2'
},
leftStick: {
up: '↑',
down: '↓',
left: '←',
right: '→',
click: 'L3'
},
rightStick: {
up: '↑',
down: '↓',
left: '←',
right: '→',
click: 'R3'
}
})

/**
* Newer Sony style
*/
static Ragdoll = new GameInputSchema('Ragdoll', {
static Ragdoll = new GameInputSchema('Ragdoll', FaceDirections.ltr, {
face: {
up: '△',
down: 'x',
Expand Down Expand Up @@ -385,13 +404,39 @@ export class GameInputSchema {
*/
name = ''

/**
* Direction of face buttons
* @type {import("./gamepad-mapping.js").FaceDirection|boolean}
*/
direction = FaceDirections.ltr

/**
* Constructor.
* @param {string} name schema/theme name
* @param {GameInputSchemaOverrides} overrides list of overrides for button names to text
* @param {string} name schema/theme name
* @param {import("./gamepad-mapping.js").FaceDirection|boolean} direction Direction of ordinality for face buttons
* @param {GameInputSchemaOverrides} overrides list of overrides for button names to text
*/
constructor (name, overrides) {
constructor (name, direction, overrides) {
this.name = name
this.direction = direction
Object.assign(this, Object.assign(GameInputSchema.Defaults, overrides))
}

/**
* Get button text by ordinal priority.
* @param {number} value button ordinal (0 for primary/accept, 1 for secondary/cancel, etc)
* @returns {string} button text.
*/
ordinal (value) {
return this.face[OrdinalButtonName(value, this.direction)]
}

/**
* Get button name by ordinal priority.
* @param {number} value button ordinal (0 for primary/accept, 1 for secondary/cancel, etc)
* @returns {GameInputSchemaButtonName} button name.
*/
ordinalButton (value) {
return OrdinalButtonName(value, this.direction)
}
}
10 changes: 2 additions & 8 deletions src/gameinput-state.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { OrdinalButtonName } from './gameinput-schema.js'
import { FaceDirections } from './gamepad-mapping.js'

export class GameInputItemState {
Expand Down Expand Up @@ -130,14 +131,7 @@ export class GameInputFaceState extends GameInputDirectionsState {
* @returns {GameInputItemState} button mapping.
*/
ordinal (value) {
const ltr = this.direction === FaceDirections.ltr
switch (value) {
case 0: return ltr ? this.down : this.right
case 1: return ltr ? this.right : this.down
case 2: return ltr ? this.left : this.up
case 3: return ltr ? this.up : this.left
default: return undefined
}
return this[OrdinalButtonName(value, this.direction)]
}

/**
Expand Down
6 changes: 6 additions & 0 deletions src/gamepad-mapping.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ export const FaceDirections = {
rtl: false
}

/**
* Used later to let Playstation prior to PS5 use RTL direction for Japan
*/
export const IsJapan = navigator.language.toLowerCase() === 'ja-jp' ||
Intl.DateTimeFormat().resolvedOptions().timeZone === 'Asia/Tokyo'

/**
* Mapping Of Schema Buttons for the 4 cardinal directions
*/
Expand Down

0 comments on commit ffa8926

Please sign in to comment.