-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfix_useGamepad_final.cjs
More file actions
149 lines (124 loc) · 4.35 KB
/
fix_useGamepad_final.cjs
File metadata and controls
149 lines (124 loc) · 4.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
const fs = require('fs');
const content = `import { useEffect, useRef } from 'react';
// Configuration for Key Mappings
const MAPPINGS = {
// Player 1 (Usually Index 0)
P1: {
AXES: {
UP: 'ArrowUp',
DOWN: 'ArrowDown',
LEFT: 'ArrowLeft',
RIGHT: 'ArrowRight',
},
BUTTONS: {
0: 'ControlLeft', // Attack
1: 'AltLeft', // Jump
2: 'Space', // Action 3
3: 'ShiftLeft', // Action 4
4: 'KeyZ', // Action 5
5: 'KeyX', // Action 6
8: 'Digit5', // Coin
9: 'Digit1', // Start
} as Record<number, string>
},
// Player 2 (Usually Index 2 - skipping Ghost Index 1)
P2: {
AXES: {
UP: 'KeyR',
DOWN: 'KeyF',
LEFT: 'KeyD',
RIGHT: 'KeyG',
},
BUTTONS: {
0: 'KeyA',
1: 'KeyS',
2: 'KeyQ',
3: 'KeyW',
4: 'KeyE',
5: 'KeyT',
8: 'Digit6', // Coin P2
9: 'Digit2', // Start P2
} as Record<number, string>
}
};
type KeyState = { [key: string]: boolean };
export function useGamepad() {
const requestRef = useRef<number | undefined>(undefined);
const keyState = useRef<KeyState>({});
useEffect(() => {
// Helper to dispatch keyboard events
const triggerKey = (code: string, type: 'keydown' | 'keyup') => {
// Avoid repeating keyup events if already up, or keydown if already down
if (type === 'keydown' && keyState.current[code]) return;
if (type === 'keyup' && !keyState.current[code]) return;
keyState.current[code] = type === 'keydown';
const event = new KeyboardEvent(type, {
code: code,
key: code, // Simplification
bubbles: true,
cancelable: true,
});
window.dispatchEvent(event);
};
const updateLoop = () => {
const gamepads = navigator.getGamepads();
// Filter out nulls and potential ghost devices (0 buttons)
// We treat the first valid device as P1, second as P2
const validGamepads = Array.from(gamepads).filter(gp => gp && gp.buttons.length > 0);
validGamepads.forEach((gp, listIndex) => {
// Determine if this is P1 or P2 based on the filtered list order
// List Index 0 -> P1
// List Index 1 -> P2
let mapping = null;
if (listIndex === 0) mapping = MAPPINGS.P1;
if (listIndex === 1) mapping = MAPPINGS.P2;
if (!mapping || !gp) return;
// 1. Handle Axes (Sticks)
// Threshold for stick activation
const THRESHOLD = 0.5;
// Left/Right (Axis 0)
if (gp.axes[0] < -THRESHOLD) triggerKey(mapping.AXES.LEFT, 'keydown');
else triggerKey(mapping.AXES.LEFT, 'keyup');
if (gp.axes[0] > THRESHOLD) triggerKey(mapping.AXES.RIGHT, 'keydown');
else triggerKey(mapping.AXES.RIGHT, 'keyup');
// Up/Down (Axis 1)
if (gp.axes[1] < -THRESHOLD) triggerKey(mapping.AXES.UP, 'keydown');
else triggerKey(mapping.AXES.UP, 'keyup');
if (gp.axes[1] > THRESHOLD) triggerKey(mapping.AXES.DOWN, 'keydown');
else triggerKey(mapping.AXES.DOWN, 'keyup');
// 2. Handle Buttons
gp.buttons.forEach((btn, idx) => {
const keyCode = mapping!.BUTTONS[idx];
if (keyCode) {
triggerKey(keyCode, btn.pressed ? 'keydown' : 'keyup');
}
});
});
requestRef.current = requestAnimationFrame(updateLoop);
};
const onConnected = (e: GamepadEvent) => {
console.log("Gamepad connected:", e.gamepad.id);
// Ensure loop is running
if (!requestRef.current) {
requestRef.current = requestAnimationFrame(updateLoop);
}
};
const onDisconnected = (e: GamepadEvent) => {
console.log("Gamepad disconnected:", e.gamepad.id);
};
window.addEventListener("gamepadconnected", onConnected);
window.addEventListener("gamepaddisconnected", onDisconnected);
// Start polling immediately in case devices are already plugged in
requestRef.current = requestAnimationFrame(updateLoop);
return () => {
window.removeEventListener("gamepadconnected", onConnected);
window.removeEventListener("gamepaddisconnected", onDisconnected);
if (requestRef.current) {
cancelAnimationFrame(requestRef.current);
requestRef.current = undefined;
}
};
}, []);
}
`;
fs.writeFileSync('src/hooks/useGamepad.ts', content);