like2d 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +66 -0
  2. package/dist/audio.d.ts +52 -0
  3. package/dist/audio.d.ts.map +1 -0
  4. package/dist/audio.js +250 -0
  5. package/dist/events.d.ts +36 -0
  6. package/dist/events.d.ts.map +1 -0
  7. package/dist/events.js +1 -0
  8. package/dist/gamecontrollerdb.txt +2219 -0
  9. package/dist/gamepad-button-map.d.ts +5 -0
  10. package/dist/gamepad-button-map.d.ts.map +1 -0
  11. package/dist/gamepad-button-map.js +56 -0
  12. package/dist/gamepad-db.d.ts +49 -0
  13. package/dist/gamepad-db.d.ts.map +1 -0
  14. package/dist/gamepad-db.js +192 -0
  15. package/dist/gamepad-mapping.d.ts +31 -0
  16. package/dist/gamepad-mapping.d.ts.map +1 -0
  17. package/dist/gamepad-mapping.js +191 -0
  18. package/dist/gamepad.d.ts +56 -0
  19. package/dist/gamepad.d.ts.map +1 -0
  20. package/dist/gamepad.js +216 -0
  21. package/dist/graphics.d.ts +80 -0
  22. package/dist/graphics.d.ts.map +1 -0
  23. package/dist/graphics.js +388 -0
  24. package/dist/index.d.ts +45 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +250 -0
  27. package/dist/input-state.d.ts +14 -0
  28. package/dist/input-state.d.ts.map +1 -0
  29. package/dist/input-state.js +50 -0
  30. package/dist/input.d.ts +36 -0
  31. package/dist/input.d.ts.map +1 -0
  32. package/dist/input.js +127 -0
  33. package/dist/keyboard.d.ts +9 -0
  34. package/dist/keyboard.d.ts.map +1 -0
  35. package/dist/keyboard.js +33 -0
  36. package/dist/mouse.d.ts +20 -0
  37. package/dist/mouse.d.ts.map +1 -0
  38. package/dist/mouse.js +84 -0
  39. package/dist/rect.d.ts +27 -0
  40. package/dist/rect.d.ts.map +1 -0
  41. package/dist/rect.js +132 -0
  42. package/dist/scene.d.ts +10 -0
  43. package/dist/scene.d.ts.map +1 -0
  44. package/dist/scene.js +1 -0
  45. package/dist/timer.d.ts +19 -0
  46. package/dist/timer.d.ts.map +1 -0
  47. package/dist/timer.js +86 -0
  48. package/dist/vector2.d.ts +32 -0
  49. package/dist/vector2.d.ts.map +1 -0
  50. package/dist/vector2.js +105 -0
  51. package/package.json +64 -0
@@ -0,0 +1,5 @@
1
+ export declare const GAMEPAD_BUTTON_MAP: Record<string, number>;
2
+ export declare const GAMEPAD_BUTTON_NAMES: Record<number, string>;
3
+ export declare function getButtonName(buttonIndex: number): string;
4
+ export declare function getButtonIndex(buttonName: string): number | undefined;
5
+ //# sourceMappingURL=gamepad-button-map.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gamepad-button-map.d.ts","sourceRoot":"","sources":["../src/gamepad-button-map.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAiCrD,CAAC;AAGF,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAiBvD,CAAC;AAEF,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAErE"}
@@ -0,0 +1,56 @@
1
+ // Button name to index mapping using physical layout
2
+ export const GAMEPAD_BUTTON_MAP = {
3
+ // Face buttons - physical positions (not labels)
4
+ 'ButtonBottom': 0,
5
+ 'ButtonRight': 1,
6
+ 'ButtonLeft': 2,
7
+ 'ButtonTop': 3,
8
+ // Bumpers and triggers
9
+ 'LB': 4,
10
+ 'L1': 4,
11
+ 'RB': 5,
12
+ 'R1': 5,
13
+ 'LT': 6,
14
+ 'L2': 6,
15
+ 'RT': 7,
16
+ 'R2': 7,
17
+ // Menu buttons
18
+ 'Back': 8,
19
+ 'Select': 8,
20
+ 'Start': 9,
21
+ // Stick presses
22
+ 'LS': 10,
23
+ 'L3': 10,
24
+ 'RS': 11,
25
+ 'R3': 11,
26
+ // D-Pad
27
+ 'DPadUp': 12,
28
+ 'DPadDown': 13,
29
+ 'DPadLeft': 14,
30
+ 'DPadRight': 15,
31
+ };
32
+ // Reverse mapping: index to primary name
33
+ export const GAMEPAD_BUTTON_NAMES = {
34
+ 0: 'ButtonBottom',
35
+ 1: 'ButtonRight',
36
+ 2: 'ButtonLeft',
37
+ 3: 'ButtonTop',
38
+ 4: 'LB',
39
+ 5: 'RB',
40
+ 6: 'LT',
41
+ 7: 'RT',
42
+ 8: 'Back',
43
+ 9: 'Start',
44
+ 10: 'LS',
45
+ 11: 'RS',
46
+ 12: 'DPadUp',
47
+ 13: 'DPadDown',
48
+ 14: 'DPadLeft',
49
+ 15: 'DPadRight',
50
+ };
51
+ export function getButtonName(buttonIndex) {
52
+ return GAMEPAD_BUTTON_NAMES[buttonIndex] ?? `Button${buttonIndex}`;
53
+ }
54
+ export function getButtonIndex(buttonName) {
55
+ return GAMEPAD_BUTTON_MAP[buttonName];
56
+ }
@@ -0,0 +1,49 @@
1
+ export interface ControllerMapping {
2
+ guid: string;
3
+ name: string;
4
+ platform: string;
5
+ buttons: Map<string, number>;
6
+ axes: Map<string, number>;
7
+ dpads: Map<string, {
8
+ hat: number;
9
+ value: number;
10
+ }>;
11
+ }
12
+ export declare const SDL_BUTTONS: readonly ["a", "b", "x", "y", "back", "start", "guide", "leftshoulder", "rightshoulder", "lefttrigger", "righttrigger", "leftstick", "rightstick", "dpup", "dpdown", "dpleft", "dpright", "misc1", "misc2", "paddle1", "paddle2", "paddle3", "paddle4", "touchpad"];
13
+ export type SDLButton = (typeof SDL_BUTTONS)[number];
14
+ export declare const SDL_AXES: readonly ["leftx", "lefty", "rightx", "righty"];
15
+ export type SDLAxis = (typeof SDL_AXES)[number];
16
+ export declare class GamepadDatabase {
17
+ private mappings;
18
+ private vendorProductIndex;
19
+ private loaded;
20
+ load(dbContent: string): void;
21
+ private extractVendorProductKey;
22
+ /**
23
+ * Check if the database has been loaded
24
+ */
25
+ isLoaded(): boolean;
26
+ /**
27
+ * Get the number of loaded mappings
28
+ */
29
+ getMappingCount(): number;
30
+ /**
31
+ * Look up a controller mapping by GUID
32
+ */
33
+ getMapping(guid: string): ControllerMapping | undefined;
34
+ getMappingByVendorProduct(vendor: number, product: number): ControllerMapping | undefined;
35
+ /**
36
+ * Check if a controller is in the database
37
+ */
38
+ hasController(guid: string): boolean;
39
+ /**
40
+ * Get all mappings for a specific platform
41
+ */
42
+ getMappingsByPlatform(platform: string): ControllerMapping[];
43
+ /**
44
+ * Parse a single database line
45
+ */
46
+ private parseLine;
47
+ }
48
+ export declare const gamepadDatabase: GamepadDatabase;
49
+ //# sourceMappingURL=gamepad-db.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gamepad-db.d.ts","sourceRoot":"","sources":["../src/gamepad-db.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IAEjB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE7B,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE1B,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpD;AAGD,eAAO,MAAM,WAAW,qQASd,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAGrD,eAAO,MAAM,QAAQ,iDAGX,CAAC;AAEX,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC;AAEhD,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAwC;IACxD,OAAO,CAAC,kBAAkB,CAAwC;IAClE,OAAO,CAAC,MAAM,CAAS;IAEvB,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IA0B7B,OAAO,CAAC,uBAAuB;IAU/B;;OAEG;IACH,QAAQ,IAAI,OAAO;IAInB;;OAEG;IACH,eAAe,IAAI,MAAM;IAIzB;;OAEG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS;IAIvD,yBAAyB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS;IAKzF;;OAEG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIpC;;OAEG;IACH,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,iBAAiB,EAAE;IAa5D;;OAEG;IACH,OAAO,CAAC,SAAS;CAiFlB;AAGD,eAAO,MAAM,eAAe,iBAAwB,CAAC"}
@@ -0,0 +1,192 @@
1
+ // SDL Game Controller Database parser
2
+ // Parses the gamecontrollerdb.txt file format
3
+ // SDL button names that we care about for standard layout
4
+ export const SDL_BUTTONS = [
5
+ 'a', 'b', 'x', 'y',
6
+ 'back', 'start', 'guide',
7
+ 'leftshoulder', 'rightshoulder',
8
+ 'lefttrigger', 'righttrigger',
9
+ 'leftstick', 'rightstick',
10
+ 'dpup', 'dpdown', 'dpleft', 'dpright',
11
+ 'misc1', 'misc2', 'paddle1', 'paddle2', 'paddle3', 'paddle4',
12
+ 'touchpad',
13
+ ];
14
+ // SDL axis names
15
+ export const SDL_AXES = [
16
+ 'leftx', 'lefty',
17
+ 'rightx', 'righty',
18
+ ];
19
+ export class GamepadDatabase {
20
+ constructor() {
21
+ Object.defineProperty(this, "mappings", {
22
+ enumerable: true,
23
+ configurable: true,
24
+ writable: true,
25
+ value: new Map()
26
+ });
27
+ Object.defineProperty(this, "vendorProductIndex", {
28
+ enumerable: true,
29
+ configurable: true,
30
+ writable: true,
31
+ value: new Map()
32
+ });
33
+ Object.defineProperty(this, "loaded", {
34
+ enumerable: true,
35
+ configurable: true,
36
+ writable: true,
37
+ value: false
38
+ });
39
+ }
40
+ load(dbContent) {
41
+ this.mappings.clear();
42
+ this.vendorProductIndex.clear();
43
+ const lines = dbContent.split('\n');
44
+ for (const line of lines) {
45
+ const trimmed = line.trim();
46
+ if (!trimmed || trimmed.startsWith('#')) {
47
+ continue;
48
+ }
49
+ const mapping = this.parseLine(trimmed);
50
+ if (mapping) {
51
+ this.mappings.set(mapping.guid, mapping);
52
+ const vpKey = this.extractVendorProductKey(mapping.guid);
53
+ if (vpKey !== null && !this.vendorProductIndex.has(vpKey)) {
54
+ this.vendorProductIndex.set(vpKey, mapping);
55
+ }
56
+ }
57
+ }
58
+ this.loaded = true;
59
+ }
60
+ extractVendorProductKey(guid) {
61
+ if (guid.length < 20)
62
+ return null;
63
+ const vendorHex = guid.substring(8, 12);
64
+ const productHex = guid.substring(16, 20);
65
+ const vendor = parseInt(vendorHex.substring(2, 4) + vendorHex.substring(0, 2), 16);
66
+ const product = parseInt(productHex.substring(2, 4) + productHex.substring(0, 2), 16);
67
+ if (isNaN(vendor) || isNaN(product))
68
+ return null;
69
+ return 0x10000 * vendor + product;
70
+ }
71
+ /**
72
+ * Check if the database has been loaded
73
+ */
74
+ isLoaded() {
75
+ return this.loaded;
76
+ }
77
+ /**
78
+ * Get the number of loaded mappings
79
+ */
80
+ getMappingCount() {
81
+ return this.mappings.size;
82
+ }
83
+ /**
84
+ * Look up a controller mapping by GUID
85
+ */
86
+ getMapping(guid) {
87
+ return this.mappings.get(guid.toLowerCase());
88
+ }
89
+ getMappingByVendorProduct(vendor, product) {
90
+ const key = 0x10000 * vendor + product;
91
+ return this.vendorProductIndex.get(key);
92
+ }
93
+ /**
94
+ * Check if a controller is in the database
95
+ */
96
+ hasController(guid) {
97
+ return this.mappings.has(guid.toLowerCase());
98
+ }
99
+ /**
100
+ * Get all mappings for a specific platform
101
+ */
102
+ getMappingsByPlatform(platform) {
103
+ const result = [];
104
+ const platformLower = platform.toLowerCase();
105
+ for (const mapping of this.mappings.values()) {
106
+ if (mapping.platform.toLowerCase() === platformLower) {
107
+ result.push(mapping);
108
+ }
109
+ }
110
+ return result;
111
+ }
112
+ /**
113
+ * Parse a single database line
114
+ */
115
+ parseLine(line) {
116
+ // Format: GUID,Name,mapping pairs...,platform:Platform,
117
+ const parts = line.split(',');
118
+ if (parts.length < 3) {
119
+ return null;
120
+ }
121
+ const guid = parts[0].toLowerCase().trim();
122
+ const name = parts[1].trim();
123
+ const buttons = new Map();
124
+ const axes = new Map();
125
+ const dpads = new Map();
126
+ let platform = '';
127
+ // Parse mapping pairs (key:value)
128
+ for (let i = 2; i < parts.length; i++) {
129
+ const part = parts[i].trim();
130
+ if (!part)
131
+ continue;
132
+ // Check for platform specifier
133
+ if (part.startsWith('platform:')) {
134
+ platform = part.substring('platform:'.length).trim();
135
+ continue;
136
+ }
137
+ // Parse key:value pairs
138
+ const colonIndex = part.indexOf(':');
139
+ if (colonIndex === -1)
140
+ continue;
141
+ const key = part.substring(0, colonIndex).trim();
142
+ const value = part.substring(colonIndex + 1).trim();
143
+ if (!key || !value)
144
+ continue;
145
+ // Parse button mapping (b0, b1, etc.)
146
+ if (value.startsWith('b')) {
147
+ const buttonIndex = parseInt(value.substring(1), 10);
148
+ if (!isNaN(buttonIndex)) {
149
+ buttons.set(key, buttonIndex);
150
+ }
151
+ }
152
+ // Parse axis mapping (a0, a1, etc.)
153
+ else if (value.startsWith('a')) {
154
+ const axisIndex = parseInt(value.substring(1), 10);
155
+ if (!isNaN(axisIndex)) {
156
+ axes.set(key, axisIndex);
157
+ }
158
+ }
159
+ // Parse hat mapping (h0.1, h0.4, etc.) - used for D-pad
160
+ else if (value.startsWith('h')) {
161
+ const hatParts = value.substring(1).split('.');
162
+ if (hatParts.length === 2) {
163
+ const hatIndex = parseInt(hatParts[0], 10);
164
+ const hatValue = parseInt(hatParts[1], 10);
165
+ if (!isNaN(hatIndex) && !isNaN(hatValue)) {
166
+ dpads.set(key, { hat: hatIndex, value: hatValue });
167
+ }
168
+ }
169
+ }
170
+ // Parse axis-as-button mappings (+a0, -a0) - some controllers use axes for D-pad
171
+ else if (value.startsWith('+a') || value.startsWith('-a')) {
172
+ const axisIndex = parseInt(value.substring(2), 10);
173
+ const direction = value[0];
174
+ if (!isNaN(axisIndex)) {
175
+ // Store as special button with axis info
176
+ // We'll handle this in the mapping layer
177
+ buttons.set(`${key}:${direction}`, axisIndex);
178
+ }
179
+ }
180
+ }
181
+ return {
182
+ guid,
183
+ name,
184
+ platform,
185
+ buttons,
186
+ axes,
187
+ dpads,
188
+ };
189
+ }
190
+ }
191
+ // Singleton instance
192
+ export const gamepadDatabase = new GamepadDatabase();
@@ -0,0 +1,31 @@
1
+ export interface ButtonMapping {
2
+ toStandard: Map<number, number>;
3
+ fromStandard: Map<number, number>;
4
+ controllerName: string;
5
+ hasMapping: boolean;
6
+ }
7
+ export declare class GamepadMapping {
8
+ private mappings;
9
+ private dbLoaded;
10
+ loadDatabase(): Promise<void>;
11
+ /**
12
+ * Load database from raw text content
13
+ */
14
+ loadDatabaseFromText(content: string): void;
15
+ /**
16
+ * Get or create a button mapping for a specific gamepad
17
+ */
18
+ getMapping(gamepad: Gamepad): ButtonMapping;
19
+ /**
20
+ * Clear all cached mappings
21
+ */
22
+ clear(): void;
23
+ /**
24
+ * Create a new button mapping for a gamepad
25
+ */
26
+ private createMapping;
27
+ private findDatabaseMapping;
28
+ private extractVendorProduct;
29
+ }
30
+ export declare const gamepadMapping: GamepadMapping;
31
+ //# sourceMappingURL=gamepad-mapping.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gamepad-mapping.d.ts","sourceRoot":"","sources":["../src/gamepad-mapping.ts"],"names":[],"mappings":"AA6CA,MAAM,WAAW,aAAa;IAE5B,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEhC,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAElC,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAoC;IACpD,OAAO,CAAC,QAAQ,CAAS;IAEnB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IA+BnC;;OAEG;IACH,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAK3C;;OAEG;IACH,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,aAAa;IAa3C;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,OAAO,CAAC,aAAa;IAuDrB,OAAO,CAAC,mBAAmB;IAU3B,OAAO,CAAC,oBAAoB;CAuB7B;AAGD,eAAO,MAAM,cAAc,gBAAuB,CAAC"}
@@ -0,0 +1,191 @@
1
+ // Gamepad button mapping layer
2
+ // Bridges SDL database mappings with our internal button naming system
3
+ import { gamepadDatabase } from './gamepad-db';
4
+ import { getButtonIndex } from './gamepad-button-map';
5
+ // Map SDL button names to our internal button names
6
+ const SDL_TO_INTERNAL_BUTTON = {
7
+ // Face buttons
8
+ 'a': 'ButtonBottom',
9
+ 'b': 'ButtonRight',
10
+ 'x': 'ButtonLeft',
11
+ 'y': 'ButtonTop',
12
+ // Bumpers and triggers
13
+ 'leftshoulder': 'LB',
14
+ 'rightshoulder': 'RB',
15
+ 'lefttrigger': 'LT',
16
+ 'righttrigger': 'RT',
17
+ // Menu buttons
18
+ 'back': 'Back',
19
+ 'start': 'Start',
20
+ 'guide': 'Guide',
21
+ // Stick presses
22
+ 'leftstick': 'LS',
23
+ 'rightstick': 'RS',
24
+ // D-Pad
25
+ 'dpup': 'DPadUp',
26
+ 'dpdown': 'DPadDown',
27
+ 'dpleft': 'DPadLeft',
28
+ 'dpright': 'DPadRight',
29
+ // Misc buttons
30
+ 'misc1': 'Misc1',
31
+ 'misc2': 'Misc2',
32
+ 'paddle1': 'Paddle1',
33
+ 'paddle2': 'Paddle2',
34
+ 'paddle3': 'Paddle3',
35
+ 'paddle4': 'Paddle4',
36
+ 'touchpad': 'Touchpad',
37
+ };
38
+ export class GamepadMapping {
39
+ constructor() {
40
+ Object.defineProperty(this, "mappings", {
41
+ enumerable: true,
42
+ configurable: true,
43
+ writable: true,
44
+ value: new Map()
45
+ });
46
+ Object.defineProperty(this, "dbLoaded", {
47
+ enumerable: true,
48
+ configurable: true,
49
+ writable: true,
50
+ value: false
51
+ });
52
+ }
53
+ async loadDatabase() {
54
+ if (this.dbLoaded)
55
+ return;
56
+ const sources = ['/like/gamecontrollerdb.txt', './gamecontrollerdb.txt'];
57
+ for (const src of sources) {
58
+ try {
59
+ const res = await fetch(src);
60
+ if (res.ok) {
61
+ gamepadDatabase.load(await res.text());
62
+ this.dbLoaded = true;
63
+ break;
64
+ }
65
+ }
66
+ catch { }
67
+ }
68
+ if (!this.dbLoaded) {
69
+ try {
70
+ // @ts-ignore - Vite handles ?raw imports
71
+ const module = await import('./gamecontrollerdb.txt?raw');
72
+ if (typeof module.default === 'string') {
73
+ gamepadDatabase.load(module.default);
74
+ this.dbLoaded = true;
75
+ }
76
+ }
77
+ catch { }
78
+ }
79
+ if (this.dbLoaded) {
80
+ console.log(`[Gamepad] Loaded ${gamepadDatabase.getMappingCount()} controller mappings`);
81
+ }
82
+ }
83
+ /**
84
+ * Load database from raw text content
85
+ */
86
+ loadDatabaseFromText(content) {
87
+ gamepadDatabase.load(content);
88
+ this.dbLoaded = true;
89
+ }
90
+ /**
91
+ * Get or create a button mapping for a specific gamepad
92
+ */
93
+ getMapping(gamepad) {
94
+ // Use the gamepad's id as a key (this contains the GUID in most browsers)
95
+ const key = `${gamepad.id}_${gamepad.index}`;
96
+ if (this.mappings.has(key)) {
97
+ return this.mappings.get(key);
98
+ }
99
+ const mapping = this.createMapping(gamepad);
100
+ this.mappings.set(key, mapping);
101
+ return mapping;
102
+ }
103
+ /**
104
+ * Clear all cached mappings
105
+ */
106
+ clear() {
107
+ this.mappings.clear();
108
+ }
109
+ /**
110
+ * Create a new button mapping for a gamepad
111
+ */
112
+ createMapping(gamepad) {
113
+ const toStandard = new Map();
114
+ const fromStandard = new Map();
115
+ // If browser provides "standard" mapping, trust it - don't override with DB
116
+ if (gamepad.mapping === 'standard') {
117
+ for (let i = 0; i < gamepad.buttons.length; i++) {
118
+ toStandard.set(i, i);
119
+ fromStandard.set(i, i);
120
+ }
121
+ return {
122
+ toStandard,
123
+ fromStandard,
124
+ controllerName: gamepad.id,
125
+ hasMapping: true,
126
+ };
127
+ }
128
+ // Try to find a mapping in the database
129
+ const dbMapping = this.findDatabaseMapping(gamepad);
130
+ if (dbMapping) {
131
+ for (const [sdlButton, controllerButtonIndex] of dbMapping.buttons) {
132
+ const internalName = SDL_TO_INTERNAL_BUTTON[sdlButton];
133
+ if (internalName) {
134
+ const standardIndex = getButtonIndex(internalName);
135
+ if (standardIndex !== undefined) {
136
+ toStandard.set(controllerButtonIndex, standardIndex);
137
+ fromStandard.set(standardIndex, controllerButtonIndex);
138
+ }
139
+ }
140
+ }
141
+ return {
142
+ toStandard,
143
+ fromStandard,
144
+ controllerName: dbMapping.name,
145
+ hasMapping: true,
146
+ };
147
+ }
148
+ // No database mapping found - use default layout
149
+ for (let i = 0; i < gamepad.buttons.length; i++) {
150
+ toStandard.set(i, i);
151
+ fromStandard.set(i, i);
152
+ }
153
+ return {
154
+ toStandard,
155
+ fromStandard,
156
+ controllerName: gamepad.id,
157
+ hasMapping: false,
158
+ };
159
+ }
160
+ findDatabaseMapping(gamepad) {
161
+ if (!this.dbLoaded)
162
+ return undefined;
163
+ const vp = this.extractVendorProduct(gamepad);
164
+ if (vp) {
165
+ return gamepadDatabase.getMappingByVendorProduct(vp.vendor, vp.product);
166
+ }
167
+ return undefined;
168
+ }
169
+ extractVendorProduct(gamepad) {
170
+ const id = gamepad.id;
171
+ const vendorProductMatch = id.match(/Vendor:\s*([0-9a-fA-F]+)\s+Product:\s*([0-9a-fA-F]+)/i);
172
+ if (vendorProductMatch) {
173
+ const vendor = parseInt(vendorProductMatch[1], 16);
174
+ const product = parseInt(vendorProductMatch[2], 16);
175
+ if (!isNaN(vendor) && !isNaN(product)) {
176
+ return { vendor, product };
177
+ }
178
+ }
179
+ const hexMatch = id.match(/^([0-9a-fA-F]{4})[\s-]+([0-9a-fA-F]{4})/);
180
+ if (hexMatch) {
181
+ const vendor = parseInt(hexMatch[1], 16);
182
+ const product = parseInt(hexMatch[2], 16);
183
+ if (!isNaN(vendor) && !isNaN(product)) {
184
+ return { vendor, product };
185
+ }
186
+ }
187
+ return null;
188
+ }
189
+ }
190
+ // Singleton instance
191
+ export const gamepadMapping = new GamepadMapping();
@@ -0,0 +1,56 @@
1
+ import { getButtonName, getButtonIndex } from './gamepad-button-map';
2
+ import { ButtonMapping } from './gamepad-mapping';
3
+ export { getButtonName, getButtonIndex };
4
+ export interface GamepadButtonEvent {
5
+ gamepadIndex: number;
6
+ buttonIndex: number;
7
+ buttonName: string;
8
+ rawButtonIndex: number;
9
+ }
10
+ export interface StickPosition {
11
+ x: number;
12
+ y: number;
13
+ }
14
+ export declare class Gamepad {
15
+ private buttonTrackers;
16
+ private connectedGamepads;
17
+ private buttonMappings;
18
+ constructor();
19
+ init(): Promise<void>;
20
+ private extractVendorProduct;
21
+ private setupEventListeners;
22
+ update(): {
23
+ pressed: GamepadButtonEvent[];
24
+ released: GamepadButtonEvent[];
25
+ };
26
+ isConnected(gamepadIndex: number): boolean;
27
+ /**
28
+ * Check if a button is currently pressed on a specific gamepad
29
+ * Uses mapped button indices (standard layout)
30
+ */
31
+ isButtonDown(gamepadIndex: number, button: number | string): boolean;
32
+ isButtonDownOnAny(button: number | string): boolean;
33
+ getPressedButtons(gamepadIndex: number): Set<number>;
34
+ getConnectedGamepads(): number[];
35
+ /**
36
+ * Get the raw Gamepad object for a specific index
37
+ */
38
+ getGamepad(gamepadIndex: number): globalThis.Gamepad | undefined;
39
+ /**
40
+ * Get the button mapping for a specific gamepad
41
+ */
42
+ getButtonMapping(gamepadIndex: number): ButtonMapping | undefined;
43
+ /**
44
+ * Check if a gamepad has a known mapping from the database
45
+ */
46
+ hasMapping(gamepadIndex: number): boolean;
47
+ /**
48
+ * Get the controller name for a specific gamepad
49
+ */
50
+ getControllerName(gamepadIndex: number): string | undefined;
51
+ getAxis(gamepadIndex: number, axisIndex: number): number;
52
+ getLeftStick(gamepadIndex: number): StickPosition;
53
+ getRightStick(gamepadIndex: number): StickPosition;
54
+ }
55
+ export declare const gamepad: Gamepad;
56
+ //# sourceMappingURL=gamepad.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gamepad.d.ts","sourceRoot":"","sources":["../src/gamepad.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAErE,OAAO,EAAkB,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,CAAC;AAEzC,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAkBD,qBAAa,OAAO;IAClB,OAAO,CAAC,cAAc,CAAgD;IACtE,OAAO,CAAC,iBAAiB,CAAyC;IAClE,OAAO,CAAC,cAAc,CAAoC;;IAMpD,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3B,OAAO,CAAC,oBAAoB;IAwB5B,OAAO,CAAC,mBAAmB;IA6B3B,MAAM,IAAI;QAAE,OAAO,EAAE,kBAAkB,EAAE,CAAC;QAAC,QAAQ,EAAE,kBAAkB,EAAE,CAAA;KAAE;IA0D3E,WAAW,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO;IAI1C;;;OAGG;IACH,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO;IAOpE,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO;IASnD,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;IAKpD,oBAAoB,IAAI,MAAM,EAAE;IAIhC;;OAEG;IACH,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,UAAU,CAAC,OAAO,GAAG,SAAS;IAIhE;;OAEG;IACH,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAIjE;;OAEG;IACH,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO;IAKzC;;OAEG;IACH,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAK3D,OAAO,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM;IAMxD,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,aAAa;IAMjD,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,aAAa;CAKnD;AAED,eAAO,MAAM,OAAO,SAAgB,CAAC"}