mirror of
https://github.com/pybricks/pybricks-code.git
synced 2026-09-14 18:46:17 +00:00
terminal: add audio/visual feedback when no user program
Characters typed into the terminal are only sent to the hub when a user program is running. This provides audio and visual feedback to indicate to the user that keystrokes have no effect when the user program is not running.
This commit is contained in:
committed by
David Lechner
parent
808e6c0e85
commit
64b6251c1a
@@ -4,6 +4,9 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
- Added audio and visual feedback when typing into terminal while user program is not running.
|
||||
|
||||
## [2.0.1] - 2022-12-21
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2020-2022 The Pybricks Authors
|
||||
|
||||
import 'xterm/css/xterm.css';
|
||||
import './terminal.scss';
|
||||
import { Menu, MenuDivider, MenuItem, ResizeSensor } from '@blueprintjs/core';
|
||||
import { ContextMenu2, ContextMenu2ContentProps } from '@blueprintjs/popover2';
|
||||
import React, { useContext, useEffect, useMemo, useRef } from 'react';
|
||||
@@ -13,7 +15,12 @@ import { TerminalContext } from './TerminalContext';
|
||||
import { receiveData } from './actions';
|
||||
import { useI18n } from './i18n';
|
||||
|
||||
import 'xterm/css/xterm.css';
|
||||
// Source: https://freesound.org/people/altemark/sounds/45759/
|
||||
// This sound is released under the Creative Commons Attribution 3.0 Unported
|
||||
// (CC BY 3.0) license. It was created by 'altemark'. No modifications have been
|
||||
// made, apart from the conversion to base64.
|
||||
const BELL_SOUND =
|
||||
'data:audio/mp3;base64,SUQzBAAAAAAAI1RTU0UAAAAPAAADTGF2ZjU4LjMyLjEwNAAAAAAAAAAAAAAA//tQxAADB8AhSmxhIIEVCSiJrDCQBTcu3UrAIwUdkRgQbFAZC1CQEwTJ9mjRvBA4UOLD8nKVOWfh+UlK3z/177OXrfOdKl7pyn3Xf//WreyTRUoAWgBgkOAGbZHBgG1OF6zM82DWbZaUmMBptgQhGjsyYqc9ae9XFz280948NMBWInljyzsNRFLPWdnZGWrddDsjK1unuSrVN9jJsK8KuQtQCtMBjCEtImISdNKJOopIpBFpNSMbIHCSRpRR5iakjTiyzLhchUUBwCgyKiweBv/7UsQbg8isVNoMPMjAAAA0gAAABEVFGmgqK////9bP/6XCykxBTUUzLjEwMKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq';
|
||||
|
||||
function handleKeyEvent(event: KeyboardEvent): boolean {
|
||||
if (
|
||||
@@ -186,12 +193,46 @@ const Terminal: React.FC = (_props) => {
|
||||
return () => removeEventListener('pb-terminal-focus', listener);
|
||||
}, [xterm]);
|
||||
|
||||
// audio and visual notification of bell
|
||||
|
||||
const bellRef = useRef<HTMLAudioElement>(null);
|
||||
const bellOverlayRef = useRef<HTMLDivElement>(null);
|
||||
const bellTimeoutRef = useRef<ReturnType<typeof setTimeout>>();
|
||||
|
||||
useEffect(() => {
|
||||
const audioElement = bellRef.current;
|
||||
const overlayElement = bellOverlayRef.current;
|
||||
|
||||
if (process.env.NODE_ENV === 'test' || !audioElement || !overlayElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
const subscription = xterm.onBell(() => {
|
||||
if (bellTimeoutRef.current) {
|
||||
clearTimeout(bellTimeoutRef.current);
|
||||
}
|
||||
|
||||
audioElement.play();
|
||||
overlayElement.classList.add('pb-bell');
|
||||
|
||||
bellTimeoutRef.current = setTimeout(() => {
|
||||
overlayElement.classList.remove('pb-bell');
|
||||
}, 150);
|
||||
});
|
||||
|
||||
return () => subscription.dispose();
|
||||
}, [xterm, bellRef, bellOverlayRef, bellTimeoutRef]);
|
||||
|
||||
return (
|
||||
<ContextMenu2
|
||||
className="h-100"
|
||||
content={contextMenu}
|
||||
popoverProps={{ onClosed: () => xterm.focus() }}
|
||||
>
|
||||
<audio hidden preload="auto" ref={bellRef}>
|
||||
<source src={BELL_SOUND} />
|
||||
</audio>
|
||||
<div className="pb-terminal-bell-overlay" ref={bellOverlayRef} />
|
||||
<ResizeSensor onResize={(): void => fitAddon.fit()}>
|
||||
<div ref={terminalRef} className="h-100" />
|
||||
</ResizeSensor>
|
||||
|
||||
@@ -79,6 +79,8 @@ function* receiveTerminalData(): Generator {
|
||||
// it should be fine as long a the logic for the state doesn't change.
|
||||
if (!isUserProgramRunning) {
|
||||
// if no user program is running, input goes to /dev/null
|
||||
// print the BEL character (^G) to notify the user that the input was ignored
|
||||
yield* put(sendData('\x07'));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2022 The Pybricks Authors
|
||||
|
||||
@use '@blueprintjs/core/lib/scss/variables' as bp;
|
||||
|
||||
.pb-terminal-bell-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: bp.$pt-z-index-content - 1;
|
||||
pointer-events: none;
|
||||
|
||||
&.pb-bell {
|
||||
background-color: adjust-color(bp.$pt-intent-danger, $alpha: -0.5);
|
||||
transition: linear 100ms;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user