1
1
import * as keyFromAccelerator from 'keyboardevent-from-electron-accelerator' ;
2
- import { App , MarkdownView , Plugin , PluginSettingTab , Setting , TFile } from 'obsidian' ;
2
+ import { Notice , App , MarkdownView , Plugin , PluginSettingTab , Setting , TFile } from 'obsidian' ;
3
3
4
4
declare const CodeMirror : any ;
5
5
6
6
interface Settings {
7
7
vimrcFileName : string ,
8
8
displayChord : boolean ,
9
- displayVimMode : boolean
9
+ displayVimMode : boolean ,
10
+ fixedNormalModeLayout : boolean ,
11
+ capturedKeyboardMap : Record < string , string >
10
12
}
11
13
12
14
const DEFAULT_SETTINGS : Settings = {
13
15
vimrcFileName : ".obsidian.vimrc" ,
14
16
displayChord : false ,
15
- displayVimMode : false
17
+ displayVimMode : false ,
18
+ fixedNormalModeLayout : false ,
19
+ capturedKeyboardMap : { }
16
20
}
17
21
18
22
const enum vimStatus {
@@ -45,6 +49,26 @@ export default class VimrcPlugin extends Plugin {
45
49
private currentVimStatus : vimStatus = vimStatus . normal ;
46
50
private customVimKeybinds : { [ name : string ] : boolean } = { } ;
47
51
private currentSelection : CodeMirror . Range = null ;
52
+ private isInsertMode : boolean = false ;
53
+
54
+ async captureKeyboardLayout ( ) {
55
+ // This is experimental API and it might break at some point:
56
+ // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardLayoutMap
57
+ let keyMap : Record < string , string > = { } ;
58
+ let layout = await ( navigator as any ) . keyboard . getLayoutMap ( ) ;
59
+ let doneIterating = new Promise ( ( resolve , reject ) => {
60
+ let counted = 0 ;
61
+ layout . forEach ( ( value : any , index : any ) => {
62
+ keyMap [ index ] = value ;
63
+ counted += 1 ;
64
+ if ( counted === layout . size )
65
+ resolve ( ) ;
66
+ } ) ;
67
+ } ) ;
68
+ await doneIterating ;
69
+ new Notice ( 'Keyboard layout captured' ) ;
70
+ return keyMap ;
71
+ }
48
72
49
73
async onload ( ) {
50
74
console . log ( 'loading Vimrc plugin' ) ;
@@ -59,11 +83,6 @@ export default class VimrcPlugin extends Plugin {
59
83
catch ( error => { console . log ( 'Error loading vimrc file' , VIMRC_FILE_NAME , 'from the vault root' , error ) } ) ;
60
84
} ) ) ;
61
85
62
- // window.onkeydown = (ev: KeyboardEvent) => {
63
- // console.log('key = ', ev.key, 'code = ', ev.code);
64
- // ev.stopPropagation();
65
- // return false;
66
- // };
67
86
this . registerDomEvent ( document , 'click' , ( ) => {
68
87
this . captureYankBuffer ( ) ;
69
88
} ) ;
@@ -105,6 +124,11 @@ export default class VimrcPlugin extends Plugin {
105
124
this . defineSendKeys ( CodeMirror . Vim ) ;
106
125
this . defineObCommand ( CodeMirror . Vim ) ;
107
126
this . defineSurround ( CodeMirror . Vim ) ;
127
+ this . defineFixedLayout ( ) ;
128
+
129
+ CodeMirror . on ( cmEditor , "vim-mode-change" , ( modeObj : any ) => {
130
+ this . isInsertMode = modeObj . mode === 'insert' ;
131
+ } ) ;
108
132
109
133
// Record the position of selections
110
134
CodeMirror . on ( cmEditor , "cursorActivity" , async ( cm : any ) => {
@@ -390,6 +414,21 @@ export default class VimrcPlugin extends Plugin {
390
414
} ) ;
391
415
}
392
416
}
417
+
418
+ defineFixedLayout ( ) {
419
+ let cmEditor = this . getEditor ( this . getActiveView ( ) ) ;
420
+ cmEditor . on ( 'keydown' , ( instance : CodeMirror . Editor , ev : KeyboardEvent ) => {
421
+ if ( this . settings . fixedNormalModeLayout ) {
422
+ const keyMap = this . settings . capturedKeyboardMap ;
423
+ if ( ! this . isInsertMode && ! ev . shiftKey &&
424
+ ev . code in keyMap && ev . key != keyMap [ ev . code ] ) {
425
+ CodeMirror . Vim . handleKey ( instance , keyMap [ ev . code ] , 'mapping' ) ;
426
+ ev . preventDefault ( ) ;
427
+ return false ;
428
+ }
429
+ }
430
+ } ) ;
431
+ }
393
432
}
394
433
395
434
class SettingsTab extends PluginSettingTab {
@@ -412,10 +451,9 @@ class SettingsTab extends PluginSettingTab {
412
451
. setDesc ( 'Relative to vault directory (requires restart)' )
413
452
. addText ( ( text ) => {
414
453
text . setPlaceholder ( DEFAULT_SETTINGS . vimrcFileName ) ;
415
- if ( this . plugin . settings . vimrcFileName !== DEFAULT_SETTINGS . vimrcFileName )
416
- text . setValue ( this . plugin . settings . vimrcFileName )
454
+ text . setValue ( this . plugin . settings . vimrcFileName || DEFAULT_SETTINGS . vimrcFileName ) ;
417
455
text . onChange ( value => {
418
- this . plugin . settings . vimrcFileName = value || DEFAULT_SETTINGS . vimrcFileName ;
456
+ this . plugin . settings . vimrcFileName = value ;
419
457
this . plugin . saveSettings ( ) ;
420
458
} )
421
459
} ) ;
@@ -424,10 +462,9 @@ class SettingsTab extends PluginSettingTab {
424
462
. setName ( 'Vim chord display' )
425
463
. setDesc ( 'Displays the current chord until completion. Ex: "<Space> f-" (requires restart)' )
426
464
. addToggle ( ( toggle ) => {
427
- if ( this . plugin . settings . displayChord !== DEFAULT_SETTINGS . displayChord )
428
- toggle . setValue ( this . plugin . settings . displayChord )
465
+ toggle . setValue ( this . plugin . settings . displayChord || DEFAULT_SETTINGS . displayChord ) ;
429
466
toggle . onChange ( value => {
430
- this . plugin . settings . displayChord = value || DEFAULT_SETTINGS . displayChord ;
467
+ this . plugin . settings . displayChord = value ;
431
468
this . plugin . saveSettings ( ) ;
432
469
} )
433
470
} ) ;
@@ -436,12 +473,31 @@ class SettingsTab extends PluginSettingTab {
436
473
. setName ( 'Vim mode display' )
437
474
. setDesc ( 'Displays the current vim mode (requires restart)' )
438
475
. addToggle ( ( toggle ) => {
439
- if ( this . plugin . settings . displayVimMode !== DEFAULT_SETTINGS . displayVimMode )
440
- toggle . setValue ( this . plugin . settings . displayVimMode )
476
+ toggle . setValue ( this . plugin . settings . displayVimMode || DEFAULT_SETTINGS . displayVimMode ) ;
441
477
toggle . onChange ( value => {
442
- this . plugin . settings . displayVimMode = value || DEFAULT_SETTINGS . displayVimMode ;
478
+ this . plugin . settings . displayVimMode = value ;
443
479
this . plugin . saveSettings ( ) ;
444
480
} )
445
481
} ) ;
482
+
483
+ new Setting ( containerEl )
484
+ . setName ( 'Use a fixed keyboard layout for Normal mode' )
485
+ . setDesc ( 'Define a keyboard layout to always use when in Normal mode, regardless of the input language (experimental).' )
486
+ . addButton ( async ( button ) => {
487
+ button . setButtonText ( 'Capture current layout' ) ;
488
+ button . onClick ( async ( ) => {
489
+ this . plugin . settings . capturedKeyboardMap = await this . plugin . captureKeyboardLayout ( ) ;
490
+ this . plugin . saveSettings ( ) ;
491
+ } ) ;
492
+ } )
493
+ . addToggle ( ( toggle ) => {
494
+ toggle . setValue ( this . plugin . settings . fixedNormalModeLayout || DEFAULT_SETTINGS . fixedNormalModeLayout ) ;
495
+ toggle . onChange ( async value => {
496
+ this . plugin . settings . fixedNormalModeLayout = value ;
497
+ if ( value && Object . keys ( this . plugin . settings . capturedKeyboardMap ) . length === 0 )
498
+ this . plugin . settings . capturedKeyboardMap = await this . plugin . captureKeyboardLayout ( ) ;
499
+ this . plugin . saveSettings ( ) ;
500
+ } ) ;
501
+ } )
446
502
}
447
503
}
0 commit comments