@@ -1706,19 +1706,46 @@ function getFolderCover( uri ) {
1706
1706
*/
1707
1707
function keyboardControls ( event ) {
1708
1708
1709
- if ( event . code == 'F1' && ! event . altKey && ! event . ctrlKey ) {
1709
+ // ignore system shortcuts (with alt, ctrl or win key)
1710
+ if ( event . altKey || event . ctrlKey || event . metaKey )
1711
+ return ;
1712
+
1713
+ const isShiftKey = event . shiftKey ;
1714
+
1715
+ // F1 - help
1716
+ if ( event . code == 'F1' && ! isShiftKey ) {
1710
1717
location . href = '#help' ;
1711
1718
event . preventDefault ( ) ;
1712
1719
return ;
1713
1720
}
1714
1721
1715
- if ( event . target . tagName != 'BODY' || event . altKey || event . ctrlKey )
1722
+ // ignore all other keys when focus is not on body (e.g. input fields)
1723
+ if ( event . target . tagName != 'BODY' )
1716
1724
return ;
1717
1725
1718
- const isShiftKey = event . shiftKey ;
1726
+ // avoid automatic repetition if it's not an arrow key
1727
+ if ( event . repeat && ! event . code . startsWith ( 'Arrow' ) )
1728
+ return ;
1719
1729
1720
- // keys handled on 'keydown' allow automatic repetition
1721
- if ( event . type == 'keydown' ) {
1730
+ // handle numeric keys (load / save user presets)
1731
+ if ( event . code . match ( / ^ ( D i g i t | N u m p a d ) [ 0 - 9 ] $ / ) ) {
1732
+ const index = event . code . slice ( - 1 ) - 1 ;
1733
+ if ( index == - 1 ) { // '0' pressed
1734
+ // ignore if Shift pressed as it could be a user mistake
1735
+ if ( ! isShiftKey ) {
1736
+ randomizeSettings ( true ) ;
1737
+ setProperty ( elRandomMode , false ) ; // restart randomize timer (if active)
1738
+ }
1739
+ }
1740
+ else if ( isShiftKey ) {
1741
+ const settings = getCurrentSettings ( ) ;
1742
+ settings . randomMode = 0 ; // when saving via keyboard shortcut, turn off Randomize
1743
+ saveUserPreset ( index , settings ) ;
1744
+ }
1745
+ else
1746
+ loadPreset ( index ) ;
1747
+ }
1748
+ else {
1722
1749
switch ( event . code ) {
1723
1750
case 'ArrowUp' : // volume up
1724
1751
if ( isShiftKey )
@@ -1752,154 +1779,128 @@ function keyboardControls( event ) {
1752
1779
else
1753
1780
scheduleFastSearch ( 'k' ) ;
1754
1781
break ;
1782
+ case 'Delete' : // delete selected songs from the playlist
1783
+ case 'Backspace' : // for Mac
1784
+ playlist . querySelectorAll ( '.selected' ) . forEach ( e => {
1785
+ revokeBlobURL ( e ) ;
1786
+ e . remove ( ) ;
1787
+ } ) ;
1788
+ const current = getIndex ( playlist . querySelector ( '.current' ) ) ;
1789
+ if ( current !== undefined )
1790
+ playlistPos = current ; // update playlistPos if current song hasn't been deleted
1791
+ else if ( playlistPos > queueLength ( ) - 1 )
1792
+ playlistPos = queueLength ( ) - 1 ;
1793
+ else
1794
+ playlistPos -- ;
1795
+ if ( queueLength ( ) )
1796
+ loadNextSong ( ) ;
1797
+ else {
1798
+ clearAudioElement ( nextAudio ) ;
1799
+ if ( ! isPlaying ( ) )
1800
+ clearAudioElement ( ) ;
1801
+ }
1802
+ storePlayQueue ( true ) ;
1803
+ break ;
1804
+ case 'Space' : // play / pause
1805
+ setCanvasMsg ( isPlaying ( ) ? 'Pause' : 'Play' , 1 ) ;
1806
+ playPause ( ) ;
1807
+ break ;
1808
+ case 'ArrowLeft' : // previous song
1809
+ case 'KeyJ' :
1810
+ if ( ! finishFastSearch ( ) && ! isShiftKey ) {
1811
+ setCanvasMsg ( 'Previous track' , 1 ) ;
1812
+ skipTrack ( true ) ;
1813
+ }
1814
+ break ;
1815
+ case 'KeyG' : // gradient
1816
+ cycleElement ( elGradient , isShiftKey ) ;
1817
+ setCanvasMsg ( getSelectedGradients ( ) ) ;
1818
+ break ;
1819
+ case 'ArrowRight' : // next song
1820
+ case 'KeyK' :
1821
+ if ( ! finishFastSearch ( ) && ! isShiftKey ) {
1822
+ setCanvasMsg ( 'Next track' , 1 ) ;
1823
+ skipTrack ( ) ;
1824
+ }
1825
+ break ;
1826
+ case 'KeyA' : // cycle thru Randomize options
1827
+ cycleElement ( elRandomMode , isShiftKey ) ;
1828
+ setCanvasMsg ( 'Randomize: ' + getText ( elRandomMode ) ) ;
1829
+ setProperty ( elRandomMode ) ;
1830
+ break ;
1831
+ case 'KeyB' : // background or image fit (shift)
1832
+ cycleElement ( isShiftKey ? elBgImageFit : elBackground ) ;
1833
+ const bgOption = elBackground . value [ 0 ] ;
1834
+ setCanvasMsg ( 'Background: ' + getText ( elBackground ) + ( bgOption > 1 && bgOption < 7 ? ` (${ getText ( elBgImageFit ) } )` : '' ) ) ;
1835
+ break ;
1836
+ case 'KeyC' : // radial
1837
+ elRadial . click ( ) ;
1838
+ setCanvasMsg ( 'Radial ' + onOff ( elRadial ) ) ;
1839
+ break ;
1840
+ case 'KeyD' : // display information
1841
+ toggleInfo ( ) ;
1842
+ break ;
1843
+ case 'KeyE' : // shuffle queue
1844
+ if ( queueLength ( ) > 0 ) {
1845
+ shufflePlayQueue ( ) ;
1846
+ setCanvasMsg ( 'Shuffle' ) ;
1847
+ }
1848
+ break ;
1849
+ case 'KeyF' : // toggle fullscreen
1850
+ fullscreen ( ) ;
1851
+ break ;
1852
+ case 'KeyH' : // toggle fps display
1853
+ elFPS . click ( ) ;
1854
+ break ;
1855
+ case 'KeyI' : // toggle info display on track change
1856
+ elShowSong . click ( ) ;
1857
+ setCanvasMsg ( 'Song info display ' + onOff ( elShowSong ) ) ;
1858
+ break ;
1859
+ case 'KeyL' : // toggle LED display effect
1860
+ elLedDisplay . click ( ) ;
1861
+ setCanvasMsg ( 'LED effect ' + onOff ( elLedDisplay ) ) ;
1862
+ break ;
1863
+ case 'KeyM' : // visualization mode
1864
+ case 'KeyV' :
1865
+ cycleElement ( elMode , isShiftKey ) ;
1866
+ setCanvasMsg ( 'Mode: ' + getText ( elMode ) ) ;
1867
+ break ;
1868
+ case 'KeyN' : // increase or reduce sensitivity
1869
+ cycleElement ( elSensitivity , isShiftKey ) ;
1870
+ setCanvasMsg ( getText ( elSensitivity ) . toUpperCase ( ) + ' sensitivity' ) ;
1871
+ break ;
1872
+ case 'KeyO' : // toggle resolution
1873
+ elLoRes . click ( ) ;
1874
+ setCanvasMsg ( ( isSwitchOn ( elLoRes ) ? 'LOW' : 'HIGH' ) + ' Resolution' ) ;
1875
+ break ;
1876
+ case 'KeyP' : // toggle peaks display
1877
+ elShowPeaks . click ( ) ;
1878
+ setCanvasMsg ( 'Peaks ' + onOff ( elShowPeaks ) ) ;
1879
+ break ;
1880
+ case 'KeyR' : // toggle playlist repeat
1881
+ elRepeat . click ( ) ;
1882
+ setCanvasMsg ( 'Queue repeat ' + onOff ( elRepeat ) ) ;
1883
+ break ;
1884
+ case 'KeyS' : // toggle X and Y axis scales
1885
+ setCanvasMsg ( 'Scale: ' + [ 'None' , 'Frequency (Hz)' , 'Level (dB)' , 'Both' ] [ cycleScale ( isShiftKey ) ] ) ;
1886
+ break ;
1887
+ case 'KeyT' : // toggle text shadow
1888
+ elNoShadow . click ( ) ;
1889
+ setCanvasMsg ( ( isSwitchOn ( elNoShadow ) ? 'Flat' : 'Shadowed' ) + ' text mode' ) ;
1890
+ break ;
1891
+ case 'KeyU' : // toggle lumi bars
1892
+ elLumiBars . click ( ) ;
1893
+ setCanvasMsg ( 'Luminance bars ' + onOff ( elLumiBars ) ) ;
1894
+ break ;
1895
+ case 'KeyX' :
1896
+ cycleElement ( elReflex , isShiftKey ) ;
1897
+ setCanvasMsg ( 'Reflex: ' + getText ( elReflex ) ) ;
1898
+ break ;
1755
1899
default :
1756
1900
// no key match - quit and keep default behavior
1757
1901
return ;
1758
- }
1759
- }
1760
- else {
1761
- if ( event . code . match ( / ^ ( D i g i t | N u m p a d ) [ 0 - 9 ] $ / ) ) {
1762
- const index = event . code . slice ( - 1 ) - 1 ;
1763
- if ( index == - 1 ) { // '0' pressed
1764
- // ignore if Shift pressed as it could be a user mistake
1765
- if ( ! isShiftKey ) {
1766
- randomizeSettings ( true ) ;
1767
- setProperty ( elRandomMode , false ) ; // restart randomize timer (if active)
1768
- }
1769
- }
1770
- else if ( isShiftKey ) {
1771
- const settings = getCurrentSettings ( ) ;
1772
- settings . randomMode = 0 ; // when saving via keyboard shortcut, turn off Randomize
1773
- saveUserPreset ( index , settings ) ;
1774
- }
1775
- else
1776
- loadPreset ( index ) ;
1777
- }
1778
- else {
1779
- switch ( event . code ) {
1780
- case 'Delete' : // delete selected songs from the playlist
1781
- case 'Backspace' : // for Mac
1782
- playlist . querySelectorAll ( '.selected' ) . forEach ( e => {
1783
- revokeBlobURL ( e ) ;
1784
- e . remove ( ) ;
1785
- } ) ;
1786
- const current = getIndex ( playlist . querySelector ( '.current' ) ) ;
1787
- if ( current !== undefined )
1788
- playlistPos = current ; // update playlistPos if current song hasn't been deleted
1789
- else if ( playlistPos > queueLength ( ) - 1 )
1790
- playlistPos = queueLength ( ) - 1 ;
1791
- else
1792
- playlistPos -- ;
1793
- if ( queueLength ( ) )
1794
- loadNextSong ( ) ;
1795
- else {
1796
- clearAudioElement ( nextAudio ) ;
1797
- if ( ! isPlaying ( ) )
1798
- clearAudioElement ( ) ;
1799
- }
1800
- storePlayQueue ( true ) ;
1801
- break ;
1802
- case 'Space' : // play / pause
1803
- setCanvasMsg ( isPlaying ( ) ? 'Pause' : 'Play' , 1 ) ;
1804
- playPause ( ) ;
1805
- break ;
1806
- case 'ArrowLeft' : // previous song
1807
- case 'KeyJ' :
1808
- if ( ! finishFastSearch ( ) && ! isShiftKey ) {
1809
- setCanvasMsg ( 'Previous track' , 1 ) ;
1810
- skipTrack ( true ) ;
1811
- }
1812
- break ;
1813
- case 'KeyG' : // gradient
1814
- cycleElement ( elGradient , isShiftKey ) ;
1815
- setCanvasMsg ( getSelectedGradients ( ) ) ;
1816
- break ;
1817
- case 'ArrowRight' : // next song
1818
- case 'KeyK' :
1819
- if ( ! finishFastSearch ( ) && ! isShiftKey ) {
1820
- setCanvasMsg ( 'Next track' , 1 ) ;
1821
- skipTrack ( ) ;
1822
- }
1823
- break ;
1824
- case 'KeyA' : // cycle thru Randomize options
1825
- cycleElement ( elRandomMode , isShiftKey ) ;
1826
- setCanvasMsg ( 'Randomize: ' + getText ( elRandomMode ) ) ;
1827
- setProperty ( elRandomMode ) ;
1828
- break ;
1829
- case 'KeyB' : // background or image fit (shift)
1830
- cycleElement ( isShiftKey ? elBgImageFit : elBackground ) ;
1831
- const bgOption = elBackground . value [ 0 ] ;
1832
- setCanvasMsg ( 'Background: ' + getText ( elBackground ) + ( bgOption > 1 && bgOption < 7 ? ` (${ getText ( elBgImageFit ) } )` : '' ) ) ;
1833
- break ;
1834
- case 'KeyC' : // radial
1835
- elRadial . click ( ) ;
1836
- setCanvasMsg ( 'Radial ' + onOff ( elRadial ) ) ;
1837
- break ;
1838
- case 'KeyD' : // display information
1839
- toggleInfo ( ) ;
1840
- break ;
1841
- case 'KeyE' : // shuffle queue
1842
- if ( queueLength ( ) > 0 ) {
1843
- shufflePlayQueue ( ) ;
1844
- setCanvasMsg ( 'Shuffle' ) ;
1845
- }
1846
- break ;
1847
- case 'KeyF' : // toggle fullscreen
1848
- fullscreen ( ) ;
1849
- break ;
1850
- case 'KeyH' : // toggle fps display
1851
- elFPS . click ( ) ;
1852
- break ;
1853
- case 'KeyI' : // toggle info display on track change
1854
- elShowSong . click ( ) ;
1855
- setCanvasMsg ( 'Song info display ' + onOff ( elShowSong ) ) ;
1856
- break ;
1857
- case 'KeyL' : // toggle LED display effect
1858
- elLedDisplay . click ( ) ;
1859
- setCanvasMsg ( 'LED effect ' + onOff ( elLedDisplay ) ) ;
1860
- break ;
1861
- case 'KeyM' : // visualization mode
1862
- case 'KeyV' :
1863
- cycleElement ( elMode , isShiftKey ) ;
1864
- setCanvasMsg ( 'Mode: ' + getText ( elMode ) ) ;
1865
- break ;
1866
- case 'KeyN' : // increase or reduce sensitivity
1867
- cycleElement ( elSensitivity , isShiftKey ) ;
1868
- setCanvasMsg ( getText ( elSensitivity ) . toUpperCase ( ) + ' sensitivity' ) ;
1869
- break ;
1870
- case 'KeyO' : // toggle resolution
1871
- elLoRes . click ( ) ;
1872
- setCanvasMsg ( ( isSwitchOn ( elLoRes ) ? 'LOW' : 'HIGH' ) + ' Resolution' ) ;
1873
- break ;
1874
- case 'KeyP' : // toggle peaks display
1875
- elShowPeaks . click ( ) ;
1876
- setCanvasMsg ( 'Peaks ' + onOff ( elShowPeaks ) ) ;
1877
- break ;
1878
- case 'KeyR' : // toggle playlist repeat
1879
- elRepeat . click ( ) ;
1880
- setCanvasMsg ( 'Queue repeat ' + onOff ( elRepeat ) ) ;
1881
- break ;
1882
- case 'KeyS' : // toggle X and Y axis scales
1883
- setCanvasMsg ( 'Scale: ' + [ 'None' , 'Frequency (Hz)' , 'Level (dB)' , 'Both' ] [ cycleScale ( isShiftKey ) ] ) ;
1884
- break ;
1885
- case 'KeyT' : // toggle text shadow
1886
- elNoShadow . click ( ) ;
1887
- setCanvasMsg ( ( isSwitchOn ( elNoShadow ) ? 'Flat' : 'Shadowed' ) + ' text mode' ) ;
1888
- break ;
1889
- case 'KeyU' : // toggle lumi bars
1890
- elLumiBars . click ( ) ;
1891
- setCanvasMsg ( 'Luminance bars ' + onOff ( elLumiBars ) ) ;
1892
- break ;
1893
- case 'KeyX' :
1894
- cycleElement ( elReflex , isShiftKey ) ;
1895
- setCanvasMsg ( 'Reflex: ' + getText ( elReflex ) ) ;
1896
- break ;
1897
- default :
1898
- // no key match - quit and keep default behavior
1899
- return ;
1900
- } // switch
1901
- }
1902
- } // else if ( event.type == 'keydown' )
1902
+ } // switch
1903
+ } // else
1903
1904
1904
1905
event . preventDefault ( ) ;
1905
1906
}
@@ -5152,9 +5153,8 @@ function updateRangeValue( el ) {
5152
5153
setUIEventListeners ( ) ;
5153
5154
} ) ;
5154
5155
5155
- // Add events listeners for keyboard controls
5156
+ // Add event listener for keyboard shortcuts
5156
5157
window . addEventListener ( 'keydown' , keyboardControls ) ;
5157
- window . addEventListener ( 'keyup' , keyboardControls ) ;
5158
5158
5159
5159
// notie options
5160
5160
notie . setOptions ( {
0 commit comments