mirror of https://github.com/nealey/vail.git
Freetext repeater entry (fixes #17)
This commit is contained in:
parent
42b3eb1621
commit
82d0787ef8
|
@ -44,7 +44,7 @@
|
||||||
<a class="mdl-navigation__link" href="?repeater=21-99+WPM">21-99 WPM</a>
|
<a class="mdl-navigation__link" href="?repeater=21-99+WPM">21-99 WPM</a>
|
||||||
</nav>
|
</nav>
|
||||||
<hr>
|
<hr>
|
||||||
<nav class="mdl-navigation">
|
<nav class="mdl-navigation">
|
||||||
<a class="mdl-navigation__link" href="https://morse.withgoogle.com/learn/">Learn Morse Code</a>
|
<a class="mdl-navigation__link" href="https://morse.withgoogle.com/learn/">Learn Morse Code</a>
|
||||||
<a class="mdl-navigation__link" href="https://github.com/nealey/vail-adapter">Use a physical key</a>
|
<a class="mdl-navigation__link" href="https://github.com/nealey/vail-adapter">Use a physical key</a>
|
||||||
</nav>
|
</nav>
|
||||||
|
@ -58,15 +58,23 @@
|
||||||
<main class="mdl-layout__content">
|
<main class="mdl-layout__content">
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="mdl-card mdl-shadow--4dp input-methods">
|
<div class="mdl-card mdl-shadow--4dp input-methods">
|
||||||
|
<div id="recv">
|
||||||
|
<!-- This div appears as a little light that turns on when someone's sending -->
|
||||||
|
<i class="material-icons" id="muted">volume_off</i>
|
||||||
|
</div>
|
||||||
<div class="mdl-card__title">
|
<div class="mdl-card__title">
|
||||||
<h2 class="mdl-card__title-text">
|
<h2 class="mdl-card__title-text">
|
||||||
<span id="repeater"></span>
|
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
|
||||||
Repeater
|
<input class="mdl-textfield__input" type="text" id="repeater" list="repeater-list">
|
||||||
|
<datalist id="repeater-list">
|
||||||
|
<option>General Chaos</option>
|
||||||
|
<option>1-15 WPM</option>
|
||||||
|
<option>16-20 WPM</option>
|
||||||
|
<option>21+ WPM</option>
|
||||||
|
</datalist>
|
||||||
|
<label class="mdl-textfield__label" for="repeater">Repeater</label>
|
||||||
|
</div>
|
||||||
</h2>
|
</h2>
|
||||||
<div id="recv">
|
|
||||||
<!-- This div appears as a little light that turns on when someone's sending -->
|
|
||||||
<i class="material-icons" id="muted">volume_off</i>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="mdl-tabs mdl-js-tabs mdl-js-ripple-effect">
|
<div class="mdl-tabs mdl-js-tabs mdl-js-ripple-effect">
|
||||||
<div class="mdl-tabs__tab-bar">
|
<div class="mdl-tabs__tab-bar">
|
||||||
|
@ -91,7 +99,6 @@
|
||||||
<kbd>c</kbd>
|
<kbd>c</kbd>
|
||||||
<kbd>,</kbd>
|
<kbd>,</kbd>
|
||||||
<kbd>Enter</kbd>
|
<kbd>Enter</kbd>
|
||||||
<kbd>⇧ Shift</kbd>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -354,7 +361,7 @@
|
||||||
value="100">
|
value="100">
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Recieve delay:
|
Receive delay:
|
||||||
<output id="rx-delay-value"></output>ms
|
<output id="rx-delay-value"></output>ms
|
||||||
<input
|
<input
|
||||||
id="rx-delay"
|
id="rx-delay"
|
||||||
|
@ -406,139 +413,123 @@
|
||||||
|
|
||||||
<div class="mdl-card mdl-shadow--4dp">
|
<div class="mdl-card mdl-shadow--4dp">
|
||||||
<div class="mdl-card__title">
|
<div class="mdl-card__title">
|
||||||
<h2 class="mdl-card__title-text">Vail</h2>
|
<h2 class="mdl-card__title-text">Documentation</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="mdl-card__supporting-text">
|
<div class="mdl-tabs mdl-js-tabs mdl-js-ripple-effect">
|
||||||
<p>
|
<div class="mdl-tabs__tab-bar">
|
||||||
This is a CW repeater,
|
<a href="#doc-about" class="mdl-tabs__tab is-active">About</a>
|
||||||
named after Alfred Vail,
|
<a href="#doc-faq" class="mdl-tabs__tab">FAQ</a>
|
||||||
who may or may not have invented what's called "Morse code",
|
<a href="#doc-geek" class="mdl-tabs__tab">Geek Stuff</a>
|
||||||
but clearly had some role in it.
|
</div>
|
||||||
</p>
|
<div class="mdl-tabs__panel mdl-card__supporting-text long is-active" id="doc-about">
|
||||||
|
<p>
|
||||||
|
This is a CW repeater,
|
||||||
|
named after Alfred Vail,
|
||||||
|
who may or may not have invented what's called "Morse code",
|
||||||
|
but clearly had some role in it.
|
||||||
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Just like a radio repeater,
|
Just like a radio repeater,
|
||||||
anybody can connect and start transmitting stuff,
|
anybody can connect and start transmitting stuff,
|
||||||
and this will broadcast it to everyone connected.
|
and this will broadcast it to everyone connected.
|
||||||
</p>
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<h3 class="mdl-card__title-text">Why Does This Exist?</h3>
|
<div class="mdl-tabs__panel mdl-card__supporting-text long" id="doc-faq">
|
||||||
|
<h3 class="mdl-card__title-text">Why Does This Exist?</h3>
|
||||||
|
<p>
|
||||||
|
I needed a place to practice CW with actual human beings,
|
||||||
|
and I wanted it to be as close as possible to what I'd experience on a radio.
|
||||||
|
I also didn't have a lot of money to spend on equipment, but I did have a computer, phone, and gamepad.
|
||||||
|
Nothing else like this exists on the Internet, as far as I can tell.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3 class="mdl-card__title-text">Why do I hear a low tone?</h3>
|
||||||
|
<p>
|
||||||
|
This is the "drop tone", and will be accompanied by an error.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
This means the packet arrived so late, it can't be played in time.
|
||||||
|
In technical terms: the timestamp of the packet plus the receive delay
|
||||||
|
is less than the current time.
|
||||||
|
It can't be scheduled to play, because we can't go back in time.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
This could be happening for three reasons:
|
||||||
|
</p>
|
||||||
|
<ol>
|
||||||
|
<li>You (the person hearing the drop tone) need a larger receive delay</li>
|
||||||
|
<li>The receiving computer's clock is in the future (running fast)</li>
|
||||||
|
<li>The sending computer's clock is in the past (running slow)</li>
|
||||||
|
</ol>
|
||||||
|
<p>
|
||||||
|
Make sure your clock is synced with an Internet time server.
|
||||||
|
Accurate time is very important to how Vail works.
|
||||||
|
</p>
|
||||||
|
|
||||||
<p>
|
<h3 class="mdl-card__title-text">How can I help?</h3>
|
||||||
I need a place to practice CW with actual human beings,
|
<ul>
|
||||||
and I want it to be as close as possible to what I'd experience on a radio.
|
<li>Improve the <a href="https://github.com/nealey/vail/">source code</a></li>
|
||||||
Also, I don't want to make people buy a bunch of radio hardware.
|
<li>Email me and let me know you're using it</li>
|
||||||
Nothing else like this exists on the Internet, as far as I can tell.
|
<li>Vail costs me 50¢ a year to run: you could buy me a cup of coffee every 5 years or so to offset the expense</li>
|
||||||
</p>
|
</ul>
|
||||||
|
|
||||||
|
<h3 class="mdl-card__title-text">Who made this?</h3>
|
||||||
|
<p>
|
||||||
|
<a href="mailto:neale@woozle.org">Neale Pickett</a> kd7oqi
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="mdl-tabs__panel mdl-card__supporting-text long" id="doc-geek">
|
||||||
|
<p>
|
||||||
|
The Internet isn't exactly like radio waves:
|
||||||
|
it still goes at near the speed of light,
|
||||||
|
but there are multiple hops between endpoints,
|
||||||
|
which buffer up transmissions, and multiplex them onto a single uplink connection.
|
||||||
|
These repeaters (routers)
|
||||||
|
are also allowed to just drop things if they need to.
|
||||||
|
It's the responsibility of the communicating parties
|
||||||
|
to work out whether something needs to be retransmitted.
|
||||||
|
Because of this,
|
||||||
|
there's no telling how long it will take for a transmission to get to a destination.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Each Vail transmission (packet) consists of:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>timestamp (milliseconds since 1 Jan 1970, 00:00:00 in Reykjavík)</li>
|
||||||
|
<li>transmission duration (milliseconds)</li>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
The repeater does nothing but broadcast everything it gets
|
||||||
|
to every connected Vail client,
|
||||||
|
including the one that sent the packet.
|
||||||
|
When your client gets back the exact same thing it sent,
|
||||||
|
it compares the current time to the time in the packet.
|
||||||
|
This is the <i>round-trip time</i>:
|
||||||
|
the time it takes for a packet to get from your computer to the repeater and back.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
When the client gets a packet it didn't send,
|
||||||
|
it adds the <i>receive delay</i> to the timestamp,
|
||||||
|
and schedules to play the tones and silences in the packet
|
||||||
|
at that time.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
By adding the maximum round-trip time to the <i>longest recent transmission</i>
|
||||||
|
(the length of a dah, hopefully),
|
||||||
|
your client can make a guess about how much time needs to be added to a received timestamp,
|
||||||
|
in order to have it play back in the future at the time it comes in.
|
||||||
|
This is just a guess.
|
||||||
|
If you're communicating with somebody with a higher round-trip time than you have,
|
||||||
|
you'll need to raise your receive delay to account for it.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mdl-card mdl-shadow--4dp">
|
|
||||||
<div class="mdl-card__title">
|
|
||||||
<h2 class="mdl-card__title-text">How It Works</h2>
|
|
||||||
</div>
|
|
||||||
<div class="mdl-card__supporting-text">
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The Internet isn't exactly like radio waves:
|
|
||||||
it still goes at near the speed of light,
|
|
||||||
but there are multiple hops between endpoints,
|
|
||||||
which buffer up transmissions, and multiplex them onto a single uplink connection.
|
|
||||||
These repeaters (routers)
|
|
||||||
are also allowed to just drop things if they need to.
|
|
||||||
It's the responsibility of the communicating parties
|
|
||||||
to work out whether something needs to be retransmitted.
|
|
||||||
Because of this,
|
|
||||||
there's no telling how long it will take for a transmission to get to a destination.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Each Vail transmission (packet) consists of:
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>timestamp (milliseconds since 1 Jan 1970, 00:00:00 in Reykjavík)</li>
|
|
||||||
<li>transmission duration (milliseconds)</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The repeater does nothing but broadcast everything it gets
|
|
||||||
to every connected Vail client,
|
|
||||||
including the one that sent the packet.
|
|
||||||
When your client gets back the exact same thing it sent,
|
|
||||||
it compares the current time to the time in the packet.
|
|
||||||
This is the <i>round-trip time</i>:
|
|
||||||
the time it takes for a packet to get from your computer to the repeater and back.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
When the client gets a packet it didn't send,
|
|
||||||
it adds the <i>receive delay</i> to the timestamp,
|
|
||||||
and schedules to play the tones and silences in the packet
|
|
||||||
at that time.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
By adding the maximum round-trip time to the <i>longest recent transmission</i>
|
|
||||||
(the length of a dah, hopefully),
|
|
||||||
your client can make a guess about how much time needs to be added to a received timestamp,
|
|
||||||
in order to have it play back in the future at the time it comes in.
|
|
||||||
This is just a guess.
|
|
||||||
If you're communicating with somebody with a higher round-trip time than you have,
|
|
||||||
you'll need to raise your receive delay to account for it.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mdl-card mdl-shadow--4dp">
|
|
||||||
<div class="mdl-card__title">
|
|
||||||
<h2 class="mdl-card__title-text">Why do I hear a low tone?</h2>
|
|
||||||
</div>
|
|
||||||
<div class="mdl-card__supporting-text">
|
|
||||||
<p>
|
|
||||||
This is the "drop tone", and will be accompanied by an error.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
This means the packet arrived so late, it can't be played in time.
|
|
||||||
In technical terms: the timestamp of the packet plus the receive delay
|
|
||||||
is less than the current time.
|
|
||||||
It can't be scheduled to play, because we can't go back in time.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
This could be happening for three reasons:
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<ol>
|
|
||||||
<li>You (the person hearing the drop tone) need a larger receive delay</li>
|
|
||||||
<li>The receiving computer's clock is in the future (running fast)</li>
|
|
||||||
<li>The sending computer's clock is in the past (running slow)</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Make sure your clock is synced with an Internet time server.
|
|
||||||
Accurate time is very important to how Vail works.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mdl-card mdl-shadow--4dp">
|
|
||||||
<div class="mdl-card__title">
|
|
||||||
<h2 class="mdl-card__title-text">How can I help?</h2>
|
|
||||||
</div>
|
|
||||||
<div class="mdl-card__supporting-text">
|
|
||||||
<ul>
|
|
||||||
<li>Improve the <a href="https://github.com/nealey/vail/">source code</a></li>
|
|
||||||
<li>Email me and let me know you're using it</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<a href="mailto:neale@woozle.org">Neale Pickett</a> kd7oqi
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
28
static/sw.js
28
static/sw.js
|
@ -1,13 +1,25 @@
|
||||||
// jshint asi:true
|
cacheName = "v1"
|
||||||
|
|
||||||
self.addEventListener("install", install)
|
self.addEventListener("install", e => install(e))
|
||||||
function install(event) {
|
function install(event) {
|
||||||
console.log(event)
|
event.waitUntil(
|
||||||
event.waitUntil(Promise.resolve(true))
|
caches.open(cacheName)
|
||||||
|
.then(cache => {
|
||||||
|
return cache.addAll(
|
||||||
|
[
|
||||||
|
"/",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
})
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.addEventListener("fetch", fetcher)
|
self.addEventListener("fetch", e => cacheFetch(e))
|
||||||
function fetcher(event) {
|
function cacheFetch(event) {
|
||||||
event.respondWith(fetch(event.request))
|
event.respondWith(
|
||||||
|
fetch(event.request)
|
||||||
|
.catch(() => {
|
||||||
|
return caches.match(event.request)
|
||||||
|
})
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -94,18 +94,14 @@ img {
|
||||||
max-height: inherit;
|
max-height: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
#repeater {
|
|
||||||
font-style: italic;
|
|
||||||
margin-right: 0.3em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#recv {
|
#recv {
|
||||||
width: 3em;
|
width: 2em;
|
||||||
height: 2em;
|
height: 1em;
|
||||||
line-height: 2em;
|
line-height: 1em;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
top: 0.5em;
|
||||||
right: 1em;
|
right: 1em;
|
||||||
border-radius: 30%;
|
border-radius: 0.3em;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@ import * as Morse from "./morse.mjs"
|
||||||
import {getFortune} from "./fortunes.mjs"
|
import {getFortune} from "./fortunes.mjs"
|
||||||
import { toast } from "./morse.mjs"
|
import { toast } from "./morse.mjs"
|
||||||
|
|
||||||
|
const DefaultRepeater = "General Chaos"
|
||||||
|
|
||||||
class Vail {
|
class Vail {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.sent = []
|
this.sent = []
|
||||||
|
@ -12,8 +14,6 @@ class Vail {
|
||||||
this.beginTxTime = null // Time when we began transmitting
|
this.beginTxTime = null // Time when we began transmitting
|
||||||
this.debug = localStorage.debug
|
this.debug = localStorage.debug
|
||||||
|
|
||||||
this.openSocket()
|
|
||||||
|
|
||||||
// Listen to HTML buttons
|
// Listen to HTML buttons
|
||||||
for (let e of document.querySelectorAll("button.key")) {
|
for (let e of document.querySelectorAll("button.key")) {
|
||||||
e.addEventListener("contextmenu", e => { e.preventDefault(); return false })
|
e.addEventListener("contextmenu", e => { e.preventDefault(); return false })
|
||||||
|
@ -33,8 +33,7 @@ class Vail {
|
||||||
// Make helpers
|
// Make helpers
|
||||||
this.buzzer = new Morse.Buzzer()
|
this.buzzer = new Morse.Buzzer()
|
||||||
this.iambic = new Morse.Iambic(() => this.beginTx(), () => this.endTx())
|
this.iambic = new Morse.Iambic(() => this.beginTx(), () => this.endTx())
|
||||||
this.fortuneBuzzer = new Morse.Buzzer({highFreq: 440})
|
this.fortuneIambic = new Morse.Iambic(() => this.buzzer.Buzz(), () => this.buzzer.Silence())
|
||||||
this.fortuneIambic = new Morse.Iambic(() => this.fortuneBuzzer.Buzz(true), () => this.fortuneBuzzer.Silence(true))
|
|
||||||
|
|
||||||
// Listen for slider values
|
// Listen for slider values
|
||||||
this.inputInit("#iambic-duration", e => {
|
this.inputInit("#iambic-duration", e => {
|
||||||
|
@ -48,9 +47,21 @@ class Vail {
|
||||||
this.fortuneIambic.SetPauseMultiplier(e.target.value)
|
this.fortuneIambic.SetPauseMultiplier(e.target.value)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Show what repeater we're on
|
// Redirect old URLs
|
||||||
let repeater = (new URL(location)).searchParams.get("repeater") || "General Chaos"
|
if (window.location.search) {
|
||||||
document.querySelector("#repeater").textContent = repeater
|
let me = new URL(location)
|
||||||
|
let repeater = me.searchParams.get("repeater")
|
||||||
|
me.search = ""
|
||||||
|
me.hash = repeater
|
||||||
|
window.location = me
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill in the name of our repeater
|
||||||
|
let repeater = decodeURI(window.location.hash.split("#")[1] || "General Chaos")
|
||||||
|
let repeaterElement = document.querySelector("#repeater")
|
||||||
|
repeaterElement.addEventListener("change", e => this.setRepeater(e.target.value.trim()))
|
||||||
|
repeaterElement.value = unescape(repeater)
|
||||||
|
repeaterElement.dispatchEvent(new Event("change"))
|
||||||
|
|
||||||
// Request MIDI access
|
// Request MIDI access
|
||||||
if (navigator.requestMIDIAccess) {
|
if (navigator.requestMIDIAccess) {
|
||||||
|
@ -62,13 +73,24 @@ class Vail {
|
||||||
window.addEventListener("gamepadconnected", e => this.gamepadConnected(e))
|
window.addEventListener("gamepadconnected", e => this.gamepadConnected(e))
|
||||||
}
|
}
|
||||||
|
|
||||||
openSocket() {
|
setRepeater(name) {
|
||||||
// Set up WebSocket
|
this.repeaterName = name
|
||||||
|
|
||||||
|
// Set window URL
|
||||||
|
let hash = name
|
||||||
|
if (name == DefaultRepeater) {
|
||||||
|
hash = ""
|
||||||
|
}
|
||||||
|
if (hash != window.location.hash) {
|
||||||
|
window.location.hash = hash
|
||||||
|
}
|
||||||
|
|
||||||
let wsUrl = new URL("chat", window.location)
|
let wsUrl = new URL("chat", window.location)
|
||||||
wsUrl.protocol = wsUrl.protocol.replace("http", "ws")
|
wsUrl.protocol = wsUrl.protocol.replace("http", "ws")
|
||||||
|
wsUrl.searchParams.set("repeater", name)
|
||||||
this.socket = new WebSocket(wsUrl)
|
this.socket = new WebSocket(wsUrl)
|
||||||
this.socket.addEventListener("message", e => this.wsMessage(e))
|
this.socket.addEventListener("message", e => this.wsMessage(e))
|
||||||
this.socket.addEventListener("close", e => this.openSocket())
|
this.socket.addEventListener("close", () => this.setRepeater(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
inputInit(selector, func) {
|
inputInit(selector, func) {
|
||||||
|
@ -273,6 +295,10 @@ class Vail {
|
||||||
}
|
}
|
||||||
|
|
||||||
keyboard(event) {
|
keyboard(event) {
|
||||||
|
if (["INPUT"].includes(document.activeElement.tagName)) {
|
||||||
|
// Ignore everything if the user is entering text somewhere
|
||||||
|
return
|
||||||
|
}
|
||||||
if (event.repeat) {
|
if (event.repeat) {
|
||||||
// Ignore key repeats generated by the OS, we do this ourselves
|
// Ignore key repeats generated by the OS, we do this ourselves
|
||||||
return
|
return
|
||||||
|
@ -282,7 +308,6 @@ class Vail {
|
||||||
|
|
||||||
if ((event.code == "KeyX") ||
|
if ((event.code == "KeyX") ||
|
||||||
(event.code == "Period") ||
|
(event.code == "Period") ||
|
||||||
(event.code == "ControlLeft") ||
|
|
||||||
(event.code == "BracketLeft") ||
|
(event.code == "BracketLeft") ||
|
||||||
(event.key == "[")) {
|
(event.key == "[")) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
@ -290,7 +315,6 @@ class Vail {
|
||||||
}
|
}
|
||||||
if ((event.code == "KeyZ") ||
|
if ((event.code == "KeyZ") ||
|
||||||
(event.code == "Slash") ||
|
(event.code == "Slash") ||
|
||||||
(event.code == "ControlRight") ||
|
|
||||||
(event.code == "BracketRight") ||
|
(event.code == "BracketRight") ||
|
||||||
(event.key == "]")) {
|
(event.key == "]")) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|
Loading…
Reference in New Issue