Fix copy paste outside of screen (#143)

This commit is contained in:
Will Scullin 2022-07-16 20:50:15 -07:00 committed by GitHub
parent c0ff1e8129
commit 087dbd3602
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 93 additions and 39 deletions

View File

@ -46,7 +46,7 @@
</div>
<div id="display">
<div class="overscan">
<canvas id="screen" width="592" height="416"></canvas>
<canvas id="screen" width="592" height="416" tabindex="-1"></canvas>
</div>
</div>
<div class="inset">
@ -265,7 +265,7 @@
</button>
</header>
<main class="modal__content" id="printer-modal-content">
<div class="paper"></div>
<div class="paper" tabindex="-1"></div>
</main>
<footer class="modal__footer">
<a id="raw_printer_output" class="button">Download Raw Output</a>

View File

@ -46,7 +46,7 @@
</div>
<div id="display">
<div class="overscan">
<canvas id="screen" width="592" height="416"></canvas>
<canvas id="screen" width="592" height="416" tabindex="-1"></canvas>
</div>
</div>
<div class="inset">
@ -270,7 +270,7 @@
</button>
</header>
<main class="modal__content" id="printer-modal-content">
<div class="paper"></div>
<div class="paper" tabindex="-1"></div>
</main>
<footer class="modal__footer">
<a id="raw_printer_output" class="button">Download Raw Output</a>

View File

@ -9,6 +9,7 @@ img {
#badge {
cursor: pointer;
user-select: none;
}
#subtitle {
@ -18,6 +19,7 @@ img {
font-family: "Adobe Garamond Pro",Garamond,Times;
font-size: 13px;
font-weight: normal;
user-select: none;
}
.motter {
@ -135,6 +137,7 @@ body {
overflow: hidden;
white-space: nowrap;
flex-grow: 1;
user-select: none;
}
.code {
@ -180,6 +183,7 @@ th {
color: #0f0;
border: 2px inset #888;
border-radius: 4px;
user-select: none;
}
canvas {
@ -308,6 +312,7 @@ canvas {
padding: 5px 11px;
border: 1px outset #66594E;
border-radius: 3px;
user-select: none;
}
.modal__title {
@ -338,28 +343,34 @@ canvas {
.modal__footer {
text-align: right;
user-select: none;
}
button {
button,
a.button {
background: #44372C;
color: #fff;
padding: 2px 8px;
border: 1px outset #66594E;
border-radius: 3px;
font-size: 15px;
text-decoration: none;
}
button:hover {
button:hover,
a.button:hover {
background-color: #55473D;
border: 1px outset #66594E;
}
button:active {
button:active,
a.button:active {
background-color: #22150A;
border: 1px outset #44372C;
}
button:focus {
button:focus,
a.button:hover {
outline: none;
}

View File

@ -47,7 +47,7 @@ export interface Apple2Props {
*/
export const Apple2 = (props: Apple2Props) => {
const { e, enhanced, sectors } = props;
const screen = useRef<HTMLCanvasElement>(null);
const screenRef = useRef<HTMLCanvasElement>(null);
const [apple2, setApple2] = useState<Apple2Impl>();
const [error, setError] = useState<unknown>();
const [ready, setReady] = useState(false);
@ -60,6 +60,12 @@ export const Apple2 = (props: Apple2Props) => {
const rom = apple2?.getROM();
const doPaste = useCallback((event: Event) => {
if (
(document.activeElement !== screenRef.current) &&
(document.activeElement !== document.body)
) {
return;
}
if (io) {
const paste = (event.clipboardData || window.clipboardData)?.getData('text');
if (paste) {
@ -70,6 +76,12 @@ export const Apple2 = (props: Apple2Props) => {
}, [io]);
const doCopy = useCallback((event: Event) => {
if (
(document.activeElement !== screenRef.current) &&
(document.activeElement !== document.body)
) {
return;
}
if (vm) {
event.clipboardData?.setData('text/plain', vm.getText());
}
@ -77,9 +89,9 @@ export const Apple2 = (props: Apple2Props) => {
}, [vm]);
useEffect(() => {
if (screen.current) {
if (screenRef.current) {
const options = {
canvas: screen.current,
canvas: screenRef.current,
tick: () => { /* do nothing */ },
...props,
};
@ -111,12 +123,20 @@ export const Apple2 = (props: Apple2Props) => {
}, [props, drivesReady]);
useEffect(() => {
const { current } = screenRef;
window.addEventListener('paste', doPaste);
window.addEventListener('copy', doCopy);
current?.addEventListener('paste', doPaste);
current?.addEventListener('copy', doCopy);
return () => {
window.removeEventListener('paste', doPaste);
window.removeEventListener('copy', doCopy);
current?.removeEventListener('paste', doPaste);
current?.removeEventListener('copy', doCopy);
};
}, [doCopy, doPaste]);
@ -124,23 +144,16 @@ export const Apple2 = (props: Apple2Props) => {
setShowDebug((on) => !on);
}, []);
const removeFocus = useCallback(() => {
if (document?.activeElement instanceof HTMLElement) {
document.activeElement.blur();
}
}, []);
return (
<div className={styles.container}>
<div
className={cs(styles.outer, { apple2e: e, [styles.ready]: ready })}
onClick={removeFocus}
>
<Screen screen={screen} />
<Screen screenRef={screenRef} />
{!e ? <LanguageCard cpu={cpu} io={io} rom={rom} slot={0} /> : null}
<Slinky io={io} slot={2} />
{!e ? <Videoterm io={io} slot={3} /> : null}
<Mouse cpu={cpu} screen={screen} io={io} slot={4} />
<Mouse cpu={cpu} screenRef={screenRef} io={io} slot={4} />
<ThunderClock io={io} slot={5} />
<Inset>
<Drives cpu={cpu} io={io} sectors={sectors} enhanced={enhanced} ready={drivesReady} />

View File

@ -11,7 +11,7 @@ import { useEffect } from 'preact/hooks';
export interface MouseProps {
cpu: CPU6502 | undefined;
io: Apple2IO | undefined;
screen: RefObject<HTMLCanvasElement>;
screenRef: RefObject<HTMLCanvasElement>;
slot: slot;
}
@ -24,14 +24,14 @@ export interface MouseProps {
* @param slot Slot to register card in
* @returns Mouse component
*/
export const Mouse = ({ cpu, screen, io, slot }: MouseProps) => {
export const Mouse = ({ cpu, screenRef, io, slot }: MouseProps) => {
useEffect(() => {
if (cpu && io && screen.current) {
const mouseUI = new MouseUI(screen.current);
if (cpu && io && screenRef.current) {
const mouseUI = new MouseUI(screenRef.current);
const mouse = new MouseCard(cpu, mouseUI);
io.setSlot(slot, mouse);
}
}, [cpu, io, screen, slot]);
}, [cpu, io, screenRef, slot]);
return null;
};

View File

@ -80,7 +80,7 @@ export const Printer = ({ io, slot }: PrinterProps) => {
<>
<Modal isOpen={isOpen} onClose={onClose} title="Printer">
<ModalContent>
<pre className={styles.printer}>
<pre className={styles.printer} tabIndex={-1} >
{content}
</pre>
</ModalContent>

View File

@ -6,7 +6,7 @@ import styles from './css/Screen.module.css';
* Screen properties
*/
export interface ScreenProps {
screen: Ref<HTMLCanvasElement>;
screenRef: Ref<HTMLCanvasElement>;
}
/**
@ -16,7 +16,7 @@ export interface ScreenProps {
* @param screen Canvas element reference
* @returns
*/
export const Screen = ({ screen }: ScreenProps) => {
export const Screen = ({ screenRef }: ScreenProps) => {
return (
<div className={styles.display}>
<div className={styles.overscan}>
@ -24,7 +24,7 @@ export const Screen = ({ screen }: ScreenProps) => {
className={styles.screen}
width="592"
height="416"
ref={screen}
ref={screenRef}
/>
</div>
</div>

View File

@ -26,6 +26,7 @@
overflow: hidden;
white-space: nowrap;
flex-grow: 1;
user-select: none;
}
@media only screen and (min-resolution: 1.25dppx) {

View File

@ -11,4 +11,5 @@
color: #0f0;
border: 2px inset #888;
border-radius: 4px;
user-select: none;
}

View File

@ -16,6 +16,7 @@
display: flex;
justify-content: center;
align-items: center;
user-select: none;
}
.reset:hover {

View File

@ -26,6 +26,7 @@
overflow: hidden;
white-space: nowrap;
flex-grow: 1;
user-select: none;
}
@media only screen and (min-resolution: 1.25dppx) {

View File

@ -19,6 +19,7 @@
.badge {
cursor: pointer;
user-select: none;
}
.subtitle {
@ -28,4 +29,5 @@
font-family: "Adobe Garamond Pro", Garamond, Times, serif;
font-size: 13px;
font-weight: normal;
user-select: none;
}

View File

@ -47,7 +47,7 @@ const Variable = ({ variable }: { variable: ApplesoftVariable }) => {
<tr>
<td>{name}{TYPE_SYMBOL[type]}{arrayStr}</td>
<td>{TYPE_NAME[type]}{isArray ? ' Array' : ''}</td>
<td>{isArray ? formatArray(value) : value}</td>
<td><pre tabIndex={-1}>{isArray ? formatArray(value) : value}</pre></td>
</tr>
);
};
@ -103,7 +103,7 @@ export const Applesoft = ({ apple2 }: ApplesoftProps) => {
return (
<div className={styles.column}>
<span className={debuggerStyles.subHeading}>Listing</span>
<pre className={styles.listing}>{listing}</pre>
<pre className={styles.listing} tabIndex={-1}>{listing}</pre>
<span className={debuggerStyles.subHeading}>Variables</span>
<div className={styles.variables}>
<table>

View File

@ -156,21 +156,21 @@ export const CPU = ({ apple2 }: CPUProps) => {
<div className={debuggerStyles.row}>
<div className={debuggerStyles.column}>
<span className={debuggerStyles.subHeading}>Registers</span>
<pre>
<pre tabIndex={-1}>
{registers}
</pre>
<span className={debuggerStyles.subHeading}>Trace</span>
<pre className={styles.trace}>
<pre className={styles.trace} tabIndex={-1}>
{trace}
</pre>
<span className={debuggerStyles.subHeading}>ZP</span>
<pre className={styles.zeroPage}>
<pre className={styles.zeroPage} tabIndex={-1}>
{zeroPage}
</pre>
</div>
<div className={debuggerStyles.column}>
<span className={debuggerStyles.subHeading}>Stack</span>
<pre className={styles.stack}>
<pre className={styles.stack} tabIndex={-1}>
{stack}
</pre>
</div>
@ -185,7 +185,7 @@ export const CPU = ({ apple2 }: CPUProps) => {
className={cs({ [styles.invalid]: !memoryPageValid })}
/>
{memoryPageValid ? null : ERROR_ICON}
<pre className={styles.zp}>
<pre className={styles.zp} tabIndex={-1}>
{memory}
</pre>
</div>

View File

@ -908,15 +908,39 @@ function onLoaded(
* Input Handling
*/
window.addEventListener('paste', (event: Event) => {
const screenElement = document.querySelector('#screen')!;
const doPaste = (event: Event) => {
const paste = (event.clipboardData || window.clipboardData)!.getData('text');
io.setKeyBuffer(paste);
event.preventDefault();
};
const doCopy = (event: Event) => {
event.clipboardData!.setData('text/plain', vm.getText());
event.preventDefault();
};
window.addEventListener('paste', (event: Event) => {
if (document.activeElement && document.activeElement !== document.body) {
return;
}
doPaste(event);
});
window.addEventListener('copy', (event: Event) => {
event.clipboardData!.setData('text/plain', vm.getText());
event.preventDefault();
if (document.activeElement && document.activeElement !== document.body) {
return;
}
doCopy(event);
});
screenElement.addEventListener('copy', (event: Event) => {
doCopy(event);
});
screenElement.addEventListener('paste', (event: Event) => {
doPaste(event);
});
if (navigator.standalone) {