diff --git a/htdocs/css/shortcuts.css b/htdocs/css/shortcuts.css
index b5772fd7..f597ad08 100644
--- a/htdocs/css/shortcuts.css
+++ b/htdocs/css/shortcuts.css
@@ -3,9 +3,9 @@
#ks-overlay {
position: fixed;
- top: 5vh;
+ top: 1vh;
left: calc((100vw - 800px) / 2);
- max-height: 90vh;
+ max-height: 95vh;
width: 800px;
color: white;
background-color: #000;
@@ -22,7 +22,7 @@
.ks-title {
font-weight: bold;
font-size: 1.5rem;
- margin-top: 1rem;
+ margin-top: 0.8rem;
}
.ks-subtitle {
diff --git a/htdocs/lib/Shortcuts.js b/htdocs/lib/Shortcuts.js
index 161df854..6a5787a1 100644
--- a/htdocs/lib/Shortcuts.js
+++ b/htdocs/lib/Shortcuts.js
@@ -33,7 +33,7 @@ Shortcuts.init = function(target) {
change tuning step
-
${this.keycap('[')}|${this.keycap(']')}
+
${this.keycap('{')}|${this.keycap('}')}
change volume
@@ -44,6 +44,19 @@ Shortcuts.init = function(target) {
${this.keycap('Space')}
+
+
toggle noise reduction
+
${this.keycap('N')}
+
+
+
adjust bandpass offset
+
${this.keycap('Shift')}+${this.keycap('ArrowLeft')}|${this.keycap('ArrowRight')}
+
+
+
adjust bandpass width
+
${this.keycap('Shift')}+${this.keycap('ArrowUp')}|${this.keycap('ArrowDown')}
+
+
auto-set squelch
${this.keycap('A')}
@@ -62,17 +75,17 @@ Shortcuts.init = function(target) {
${this.keycap('S')}
-
adjust bandpass offset
-
${this.keycap('Shift')}+${this.keycap('ArrowLeft')}|${this.keycap('ArrowRight')}
+
tune by squelch
+
${this.keycap('[')}|${this.keycap(']')}
-
adjust bandpass width
-
${this.keycap('Shift')}+${this.keycap('ArrowUp')}|${this.keycap('ArrowDown')}
+
side-step current profile
+
${this.keycap('PageDown')}|${this.keycap('PageUp')}
-
toggle noise reduction
-
${this.keycap('N')}
+
show this help panel
+
${this.keycap('?')}
adjust waterfall min level
@@ -230,13 +243,35 @@ Shortcuts.handleKey = function(event) {
break;
case 'pagedown':
+ // PageDown: Shift central frequency down (if allowed)
jumpBySteps(-1);
break;
case 'pageup':
+ // PageUp: Shift central frequency up (if allowed)
jumpBySteps(1);
break;
+ case '[':
+ // [: Tune to a previous signal, by squelch
+ tuneBySquelch(-1);
+ break;
+
+ case ']':
+ // ]: Tune to a next signal, by squelch
+ tuneBySquelch(1);
+ break;
+
+ case '{':
+ // {: Decrease tuning step
+ this.moveSelector('#openwebrx-tuning-step-listbox', -1);
+ break;
+
+ case '}':
+ // }: Increase tuning step
+ this.moveSelector('#openwebrx-tuning-step-listbox', 1);
+ break;
+
case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9': case '0':
// [CTRL+]0-9: Select modulation
@@ -247,16 +282,6 @@ Shortcuts.handleKey = function(event) {
if (n < $modes.length) $modes[n].click();
break;
- case '[': case '{':
- // [: Decrease tuning step
- this.moveSelector('#openwebrx-tuning-step-listbox', -1);
- break;
-
- case ']': case '}':
- // ]: Increase tuning step
- this.moveSelector('#openwebrx-tuning-step-listbox', 1);
- break;
-
case 'a':
// A: Set squelch automatically
$('.openwebrx-squelch-auto').click();
@@ -351,6 +376,7 @@ Shortcuts.handleKey = function(event) {
break;
case '/': case '?':
+ // ?: Show keyboard shortcuts help
Shortcuts.overlay.slideToggle(100);
break;
diff --git a/htdocs/openwebrx.js b/htdocs/openwebrx.js
index 6406dff3..db57e894 100644
--- a/htdocs/openwebrx.js
+++ b/htdocs/openwebrx.js
@@ -39,7 +39,7 @@ var bandplan = null;
var scanner = null;
var bookmarks = null;
var audioEngine = null;
-
+var waterfall_last = null;
function zoomInOneStep() {
zoom_set(zoom_level + 1);
@@ -66,6 +66,32 @@ function tuneBySteps(steps) {
}
}
+function tuneBySquelch(dir) {
+ // Must have a copy of the last received waterfall
+ if (waterfall_last == null) return;
+
+ // Get current squelch threshold from the slider
+ // (why do we need to subtract ~13dB here to make FFT match the S-meter?)
+ var $slider = $('#openwebrx-panel-receiver .openwebrx-squelch-slider');
+ var squelch = $slider.val() - 13.0;
+
+ // Start from the current offset within the waterfall
+ var demodulator = $('#openwebrx-panel-receiver').demodulatorPanel().getDemodulator();
+ var f = demodulator.get_offset_frequency();
+
+ // Scan up or down the waterfall
+ dir = tuning_step * (dir>=0? 1 : -1);
+ for(f += dir ; ; f += dir) {
+ var i = Math.round(waterfall_last.length * (f / bandwidth + 0.5));
+ if (i < 0 || i >= waterfall_last.length) {
+ break;
+ } else if (waterfall_last[i] >= squelch) {
+ demodulator.set_offset_frequency(f);
+ break;
+ }
+ }
+}
+
function jumpBySteps(steps) {
steps = Math.round(steps);
if (steps != 0) {
@@ -1105,6 +1131,8 @@ function on_ws_recv(evt) {
spectrum.update(waterfall_f32);
// Feed scanner with data
scanner.update(waterfall_f32);
+ // Save waterfall for squelch-based tuning
+ waterfall_last = waterfall_f32;
break;
case 2:
// audio data