Skip to content

Commit 7d3c51e

Browse files
committed
Rollover Test implemented
1 parent 607ae97 commit 7d3c51e

File tree

3 files changed

+291
-4
lines changed

3 files changed

+291
-4
lines changed

src/App.tsx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const MainContent = styled.main`
2828

2929
const App: React.FC = () => {
3030
const [keyHistory, setKeyHistory] = useState<string[]>([]);
31+
const [activeTab, setActiveTab] = useState('keyTest');
3132

3233
const handleKeyPress = useCallback((key: string) => {
3334
setKeyHistory(prev => [...prev, key]);
@@ -37,14 +38,24 @@ const App: React.FC = () => {
3738
setKeyHistory([]);
3839
}, []);
3940

41+
const handleTabChange = useCallback((tabId: string) => {
42+
setActiveTab(tabId);
43+
// Clear key history when switching tabs
44+
setKeyHistory([]);
45+
}, []);
46+
4047
return (
4148
<ThemeProvider theme={theme}>
4249
<AppWrapper>
4350
<Navbar />
4451
<MainContent>
4552
<Header />
46-
<TestContainer onKeyPress={handleKeyPress} onReset={handleReset} />
47-
<KeyHistory keys={keyHistory} />
53+
<TestContainer
54+
onKeyPress={handleKeyPress}
55+
onReset={handleReset}
56+
onTabChange={handleTabChange}
57+
/>
58+
{activeTab === 'keyTest' && <KeyHistory keys={keyHistory} />}
4859
</MainContent>
4960
<Footer />
5061
</AppWrapper>
Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
import React, { useState, useEffect } from 'react';
2+
import styled from 'styled-components';
3+
import { motion, AnimatePresence } from 'framer-motion';
4+
5+
const RolloverContainer = styled.div`
6+
display: flex;
7+
flex-direction: column;
8+
align-items: center;
9+
width: 100%;
10+
max-width: 800px;
11+
margin: 0 auto;
12+
gap: 2rem;
13+
`;
14+
15+
const KeyCountDisplay = styled.div`
16+
font-size: 2.5rem;
17+
font-weight: bold;
18+
color: ${props => props.theme.colors.primary};
19+
text-align: center;
20+
margin-bottom: 1rem;
21+
22+
span {
23+
font-size: 1.2rem;
24+
color: ${props => props.theme.colors.text};
25+
margin-left: 0.5rem;
26+
}
27+
`;
28+
29+
const KeysContainer = styled.div`
30+
background-color: ${props => props.theme.colors.background};
31+
border: 1px solid ${props => props.theme.colors.primary};
32+
border-radius: 8px;
33+
padding: 1rem;
34+
width: 100%;
35+
height: 60px;
36+
display: flex;
37+
align-items: center;
38+
justify-content: flex-start;
39+
overflow-x: auto;
40+
position: relative;
41+
42+
&:before {
43+
content: '';
44+
position: absolute;
45+
top: 0;
46+
left: 0;
47+
right: 0;
48+
bottom: 0;
49+
box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.1);
50+
pointer-events: none;
51+
border-radius: 8px;
52+
}
53+
54+
/* Hide scrollbar for Chrome, Safari and Opera */
55+
&::-webkit-scrollbar {
56+
display: none;
57+
}
58+
59+
/* Hide scrollbar for IE, Edge and Firefox */
60+
-ms-overflow-style: none;
61+
scrollbar-width: none;
62+
`;
63+
64+
const KeyDisplay = styled(motion.div)`
65+
color: ${props => props.theme.colors.text};
66+
background: ${props => props.theme.colors.primary}20;
67+
border: 1px solid ${props => props.theme.colors.primary};
68+
border-radius: 4px;
69+
padding: 0.5rem 1rem;
70+
margin: 0 0.25rem;
71+
min-width: 40px;
72+
text-align: center;
73+
font-family: monospace;
74+
flex-shrink: 0;
75+
`;
76+
77+
const PlaceholderText = styled.div`
78+
color: ${props => props.theme.colors.text}80;
79+
font-style: italic;
80+
text-align: center;
81+
width: 100%;
82+
user-select: none;
83+
`;
84+
85+
const InstructionText = styled.p`
86+
color: ${props => props.theme.colors.text};
87+
text-align: center;
88+
max-width: 600px;
89+
margin: 0 auto;
90+
line-height: 1.5;
91+
`;
92+
93+
interface RolloverTestProps {
94+
onKeyDown?: (key: string) => void;
95+
onKeyUp?: (key: string) => void;
96+
onReset?: () => void;
97+
}
98+
99+
const RolloverTest: React.FC<RolloverTestProps> = ({ onKeyDown, onKeyUp, onReset }) => {
100+
const [pressedKeys, setPressedKeys] = useState<Set<string>>(new Set());
101+
102+
// Format key name for display
103+
const formatKeyName = (key: string): string => {
104+
switch (key) {
105+
case 'ArrowLeft':
106+
case 'Left':
107+
return '←';
108+
case 'ArrowRight':
109+
case 'Right':
110+
return '→';
111+
case 'ArrowUp':
112+
case 'Up':
113+
return '↑';
114+
case 'ArrowDown':
115+
case 'Down':
116+
return '↓';
117+
case 'L-Shift':
118+
return 'L-Shift';
119+
case 'R-Shift':
120+
return 'R-Shift';
121+
case 'L-Ctrl':
122+
return 'L-Ctrl';
123+
case 'R-Ctrl':
124+
return 'R-Ctrl';
125+
case 'L-Alt':
126+
return 'L-Alt';
127+
case 'R-Alt':
128+
return 'R-Alt';
129+
case 'Control':
130+
return 'Ctrl';
131+
case 'Meta':
132+
return 'Win';
133+
default:
134+
return key;
135+
}
136+
};
137+
138+
// Effect to handle reset
139+
useEffect(() => {
140+
// Function to clear pressed keys
141+
const clearPressedKeys = () => {
142+
setPressedKeys(new Set());
143+
};
144+
145+
// Listen for the custom reset event from TestContainer
146+
window.addEventListener('rollover-test-reset', clearPressedKeys);
147+
148+
// Cleanup
149+
return () => {
150+
window.removeEventListener('rollover-test-reset', clearPressedKeys);
151+
};
152+
}, []);
153+
154+
// Add event listeners for key down and key up
155+
useEffect(() => {
156+
const handleKeyDown = (e: KeyboardEvent) => {
157+
e.preventDefault();
158+
159+
let keyName = e.key;
160+
161+
// Handle special keys
162+
if (e.key === ' ') keyName = 'Space';
163+
if (e.key === 'Control' && e.location === 1) keyName = 'L-Ctrl';
164+
if (e.key === 'Control' && e.location === 2) keyName = 'R-Ctrl';
165+
if (e.key === 'Shift' && e.location === 1) keyName = 'L-Shift';
166+
if (e.key === 'Shift' && e.location === 2) keyName = 'R-Shift';
167+
if (e.key === 'Alt' && e.location === 1) keyName = 'L-Alt';
168+
if (e.key === 'Alt' && e.location === 2) keyName = 'R-Alt';
169+
170+
setPressedKeys(prev => {
171+
const newSet = new Set(prev);
172+
newSet.add(keyName);
173+
return newSet;
174+
});
175+
176+
if (onKeyDown) {
177+
onKeyDown(keyName);
178+
}
179+
};
180+
181+
const handleKeyUp = (e: KeyboardEvent) => {
182+
e.preventDefault();
183+
184+
let keyName = e.key;
185+
186+
// Handle special keys (same as in keydown)
187+
if (e.key === ' ') keyName = 'Space';
188+
if (e.key === 'Control' && e.location === 1) keyName = 'L-Ctrl';
189+
if (e.key === 'Control' && e.location === 2) keyName = 'R-Ctrl';
190+
if (e.key === 'Shift' && e.location === 1) keyName = 'L-Shift';
191+
if (e.key === 'Shift' && e.location === 2) keyName = 'R-Shift';
192+
if (e.key === 'Alt' && e.location === 1) keyName = 'L-Alt';
193+
if (e.key === 'Alt' && e.location === 2) keyName = 'R-Alt';
194+
195+
setPressedKeys(prev => {
196+
const newSet = new Set(prev);
197+
newSet.delete(keyName);
198+
return newSet;
199+
});
200+
201+
if (onKeyUp) {
202+
onKeyUp(keyName);
203+
}
204+
};
205+
206+
// Add event listeners
207+
window.addEventListener('keydown', handleKeyDown);
208+
window.addEventListener('keyup', handleKeyUp);
209+
210+
// Clean up
211+
return () => {
212+
window.removeEventListener('keydown', handleKeyDown);
213+
window.removeEventListener('keyup', handleKeyUp);
214+
};
215+
}, [onKeyDown, onKeyUp]);
216+
217+
// Convert Set to Array for rendering
218+
const pressedKeysArray = Array.from(pressedKeys);
219+
220+
return (
221+
<RolloverContainer>
222+
<KeyCountDisplay>
223+
{pressedKeys.size} <span>keys pressed simultaneously</span>
224+
</KeyCountDisplay>
225+
226+
<InstructionText>
227+
Press multiple keys at once to test your keyboard's rollover capability.
228+
Most modern keyboards support at least 6-key rollover, while gaming keyboards
229+
often support N-key rollover (unlimited simultaneous keypresses).
230+
</InstructionText>
231+
232+
<KeysContainer>
233+
<AnimatePresence mode="sync">
234+
{pressedKeysArray.length === 0 ? (
235+
<PlaceholderText>
236+
Rollover Test - Press and hold multiple keys to see how many can be recognized simultaneously
237+
</PlaceholderText>
238+
) : (
239+
pressedKeysArray.map((key) => (
240+
<KeyDisplay
241+
key={key}
242+
initial={{ opacity: 0, scale: 0.8 }}
243+
animate={{ opacity: 1, scale: 1 }}
244+
exit={{ opacity: 0, scale: 0.8 }}
245+
transition={{
246+
duration: 0.1,
247+
type: "spring",
248+
stiffness: 500,
249+
damping: 30
250+
}}
251+
>
252+
{formatKeyName(key)}
253+
</KeyDisplay>
254+
))
255+
)}
256+
</AnimatePresence>
257+
</KeysContainer>
258+
</RolloverContainer>
259+
);
260+
};
261+
262+
export default RolloverTest;

src/components/TestContainer/TestContainer.tsx

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ import styled from 'styled-components';
33
import { motion, AnimatePresence } from 'framer-motion';
44
import { KeyboardSelector, KeyboardType } from '../Keyboards';
55
import { KeyboardLayoutType } from '../Keyboards/keyboardTypes';
6+
import RolloverTest from '../RolloverTest/RolloverTest';
67

78
interface TestContainerProps {
89
onKeyPress?: (key: string) => void;
910
onReset?: () => void;
11+
onTabChange?: (tabId: string) => void;
1012
}
1113

1214
const Container = styled.div`
@@ -143,7 +145,7 @@ interface TabData {
143145
onClick: () => void;
144146
}
145147

146-
const TestContainer: React.FC<TestContainerProps> = ({ onKeyPress, onReset }) => {
148+
const TestContainer: React.FC<TestContainerProps> = ({ onKeyPress, onReset, onTabChange }) => {
147149
const [activeTab, setActiveTab] = useState('keyTest');
148150
const [direction, setDirection] = useState(0);
149151
const [currentLayout, setCurrentLayout] = useState<KeyboardType>('75%');
@@ -157,6 +159,11 @@ const TestContainer: React.FC<TestContainerProps> = ({ onKeyPress, onReset }) =>
157159
setDirection(newIndex > currentIndex ? 1 : -1);
158160

159161
setActiveTab(tabId);
162+
163+
// Call the onTabChange callback if provided
164+
if (onTabChange) {
165+
onTabChange(tabId);
166+
}
160167
};
161168

162169
const handleLayoutChange = (layout: KeyboardType) => {
@@ -176,6 +183,9 @@ const TestContainer: React.FC<TestContainerProps> = ({ onKeyPress, onReset }) =>
176183
onReset();
177184
}
178185

186+
// Dispatch a custom event for the RolloverTest component
187+
window.dispatchEvent(new CustomEvent('rollover-test-reset'));
188+
179189
setKeyboardKey(prevKey => prevKey + 1);
180190
};
181191

@@ -190,7 +200,11 @@ const TestContainer: React.FC<TestContainerProps> = ({ onKeyPress, onReset }) =>
190200
keyboardType={currentType}
191201
/>;
192202
case 'rolloverTest':
193-
return <div>Rollover Test Content</div>;
203+
return <RolloverTest
204+
onKeyDown={onKeyPress}
205+
onKeyUp={() => {}}
206+
onReset={onReset}
207+
/>;
194208
case 'typingTest':
195209
return <div>Typing Test Content</div>;
196210
case 'layout':

0 commit comments

Comments
 (0)