-
-
Notifications
You must be signed in to change notification settings - Fork 75
/
ble-decode.sh
executable file
·1650 lines (1478 loc) · 50.5 KB
/
ble-decode.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#! /bin/bash
: ${bleopt_error_char_abell=}
: ${bleopt_error_char_vbell=1}
: ${bleopt_error_char_discard=}
: ${bleopt_error_kseq_abell=1}
: ${bleopt_error_kseq_vbell=1}
: ${bleopt_error_kseq_discard=1}
: ${bleopt_default_keymap:=emacs}
# **** key names ****
if [ -z "$ble_decode_Erro" ]; then
declare -ir ble_decode_Erro=0x40000000
declare -ir ble_decode_Meta=0x08000000
declare -ir ble_decode_Ctrl=0x04000000
declare -ir ble_decode_Shft=0x02000000
declare -ir ble_decode_Hypr=0x01000000
declare -ir ble_decode_Supr=0x00800000
declare -ir ble_decode_Altr=0x00400000
declare -ir ble_decode_MaskChar=0x001FFFFF
declare -ir ble_decode_MaskFlag=0x7FC00000
fi
if [ "${_ble_bash:-0}" -ge 40000 ]; then
_ble_decode_kbd_ver=4
declare -i _ble_decode_kbd__n=0
declare -A _ble_decode_kbd__k2c
declare -A _ble_decode_kbd__c2k
function .ble-decode-kbd.set-keycode {
local key="$1" code="$2"
: ${_ble_decode_kbd__c2k[$code]:=$key}
_ble_decode_kbd__k2c[$key]=$code
}
function .ble-decode-kbd.get-keycode {
ret="${_ble_decode_kbd__k2c[$1]}"
}
else
_ble_decode_kbd_ver=3
declare -i _ble_decode_kbd__n=0
declare _ble_decode_kbd__k2c_keys=
declare -a _ble_decode_kbd__k2c_vals
declare -a _ble_decode_kbd__c2k
function .ble-decode-kbd.set-keycode {
local key="$1" code="$2"
: ${_ble_decode_kbd__c2k[$code]:=$key}
_ble_decode_kbd__k2c_keys="$_ble_decode_kbd__k2c_keys:$key:"
_ble_decode_kbd__k2c_vals[${#_ble_decode_kbd__k2c_vals[@]}]=$code
}
function .ble-decode-kbd.get-keycode {
local key="$1"
local tmp="${_ble_decode_kbd__k2c_keys%%:$key:*}"
if [ ${#tmp} = ${#_ble_decode_kbd__k2c_keys} ]; then
ret=
else
tmp=(${tmp//:/ })
ret="${_ble_decode_kbd__k2c_vals[${#tmp[@]}]}"
fi
}
fi
if [[ ! $ble_decode_function_key_base ]]; then
declare -ir ble_decode_function_key_base=0x110000
fi
## \param [in] $1 keycode
## \param [out] ret keyname
function .ble-decode-kbd.get-keyname {
local keycode="$1"
ret="${_ble_decode_kbd__c2k[$keycode]}"
if [[ ! $ret ]] && ((keycode<ble_decode_function_key_base)); then
.ble-text.c2s "$keycode"
_ble_decode_kbd__c2k[$keycode]="$ret"
fi
}
## 指定した名前に対応する keycode を取得します。
## 指定した名前の key が登録されていない場合は、
## 新しく kecode を割り当てて返します。
## \param [in] $1 keyname
## \param [out] ret keycode
function .ble-decode-kbd.gen-keycode {
local key="$1"
if ((${#key}==1)); then
.ble-text.s2c "$1"
elif [[ $key && ! ${key//[a-zA-Z_0-9]} ]]; then
.ble-decode-kbd.get-keycode "$key"
if [[ ! $ret ]]; then
((ret=ble_decode_function_key_base+_ble_decode_kbd__n++))
.ble-decode-kbd.set-keycode "$key" "$ret"
fi
else
ret=-1
return 1
fi
}
function .ble-decode-kbd.initialize {
.ble-decode-kbd.set-keycode TAB 9
.ble-decode-kbd.set-keycode RET 13
.ble-decode-kbd.set-keycode NUL 0
.ble-decode-kbd.set-keycode SOH 1
.ble-decode-kbd.set-keycode STX 2
.ble-decode-kbd.set-keycode ETX 3
.ble-decode-kbd.set-keycode EOT 4
.ble-decode-kbd.set-keycode ENQ 5
.ble-decode-kbd.set-keycode ACK 6
.ble-decode-kbd.set-keycode BEL 7
.ble-decode-kbd.set-keycode BS 8
.ble-decode-kbd.set-keycode HT 9 # aka TAB
.ble-decode-kbd.set-keycode LF 10
.ble-decode-kbd.set-keycode VT 11
.ble-decode-kbd.set-keycode FF 12
.ble-decode-kbd.set-keycode CR 13 # aka RET
.ble-decode-kbd.set-keycode SO 14
.ble-decode-kbd.set-keycode SI 15
.ble-decode-kbd.set-keycode DLE 16
.ble-decode-kbd.set-keycode DC1 17
.ble-decode-kbd.set-keycode DC2 18
.ble-decode-kbd.set-keycode DC3 19
.ble-decode-kbd.set-keycode DC4 20
.ble-decode-kbd.set-keycode NAK 21
.ble-decode-kbd.set-keycode SYN 22
.ble-decode-kbd.set-keycode ETB 23
.ble-decode-kbd.set-keycode CAN 24
.ble-decode-kbd.set-keycode EM 25
.ble-decode-kbd.set-keycode SUB 26
.ble-decode-kbd.set-keycode ESC 27
.ble-decode-kbd.set-keycode FS 28
.ble-decode-kbd.set-keycode GS 29
.ble-decode-kbd.set-keycode RS 30
.ble-decode-kbd.set-keycode US 31
.ble-decode-kbd.set-keycode SP 32
.ble-decode-kbd.set-keycode DEL 127
.ble-decode-kbd.set-keycode PAD 128
.ble-decode-kbd.set-keycode HOP 129
.ble-decode-kbd.set-keycode BPH 130
.ble-decode-kbd.set-keycode NBH 131
.ble-decode-kbd.set-keycode IND 132
.ble-decode-kbd.set-keycode NEL 133
.ble-decode-kbd.set-keycode SSA 134
.ble-decode-kbd.set-keycode ESA 135
.ble-decode-kbd.set-keycode HTS 136
.ble-decode-kbd.set-keycode HTJ 137
.ble-decode-kbd.set-keycode VTS 138
.ble-decode-kbd.set-keycode PLD 139
.ble-decode-kbd.set-keycode PLU 140
.ble-decode-kbd.set-keycode RI 141
.ble-decode-kbd.set-keycode SS2 142
.ble-decode-kbd.set-keycode SS3 143
.ble-decode-kbd.set-keycode DCS 144
.ble-decode-kbd.set-keycode PU1 145
.ble-decode-kbd.set-keycode PU2 146
.ble-decode-kbd.set-keycode STS 147
.ble-decode-kbd.set-keycode CCH 148
.ble-decode-kbd.set-keycode MW 149
.ble-decode-kbd.set-keycode SPA 150
.ble-decode-kbd.set-keycode EPA 151
.ble-decode-kbd.set-keycode SOS 152
.ble-decode-kbd.set-keycode SGCI 153
.ble-decode-kbd.set-keycode SCI 154
.ble-decode-kbd.set-keycode CSI 155
.ble-decode-kbd.set-keycode ST 156
.ble-decode-kbd.set-keycode OSC 157
.ble-decode-kbd.set-keycode PM 158
.ble-decode-kbd.set-keycode APC 159
local ret
.ble-decode-kbd.gen-keycode __defchar__
_ble_decode_KCODE_DEFCHAR="$ret"
.ble-decode-kbd.gen-keycode __default__
_ble_decode_KCODE_DEFAULT="$ret"
.ble-decode-kbd.gen-keycode shift
_ble_decode_KCODE_SHIFT="$ret"
.ble-decode-kbd.gen-keycode alter
_ble_decode_KCODE_ALTER="$ret"
.ble-decode-kbd.gen-keycode control
_ble_decode_KCODE_CONTROL="$ret"
.ble-decode-kbd.gen-keycode meta
_ble_decode_KCODE_META="$ret"
.ble-decode-kbd.gen-keycode super
_ble_decode_KCODE_SUPER="$ret"
.ble-decode-kbd.gen-keycode hyper
_ble_decode_KCODE_HYPER="$ret"
}
.ble-decode-kbd.initialize
function ble-decode-kbd {
local keys; ble/string#split keys $' \t\n' "$*"
local key code codes keys
codes=()
for key in "${keys[@]}"; do
code=0
while [[ $key == ?-* ]]; do
case "${key::1}" in
(S) ((code|=ble_decode_Shft)) ;;
(C) ((code|=ble_decode_Ctrl)) ;;
(M) ((code|=ble_decode_Meta)) ;;
(A) ((code|=ble_decode_Altr)) ;;
(s) ((code|=ble_decode_Supr)) ;;
(H) ((code|=ble_decode_Hypr)) ;;
(*) ((code|=ble_decode_Erro)) ;;
esac
key="${key:2}"
done
if [[ $key == ? ]]; then
.ble-text.s2c "$key" 0
((code|=ret))
elif [[ $key && ! ${key//[_0-9a-zA-Z]/} ]]; then
.ble-decode-kbd.get-keycode "$key"
[[ $ret ]] || .ble-decode-kbd.gen-keycode "$key"
((code|=ret))
elif [[ $key == ^? ]]; then
if [[ $key == '^?' ]]; then
((code|=0x7F))
elif [[ $key == '^`' ]]; then
((code|=0x20))
else
.ble-text.s2c "$key" 1
((code|=ret&0x1F))
fi
else
((code|=ble_decode_Erro))
fi
codes[${#codes[@]}]="$code"
done
ret="${codes[*]}"
}
function .ble-decode-unkbd.single-key {
local key="$1"
local f_unknown=
local char="$((key&ble_decode_MaskChar))"
.ble-decode-kbd.get-keyname "$char"
if [[ ! $ret ]]; then
f_unknown=1
ret=__UNKNOWN__
fi
((key&ble_decode_Shft)) && ret="S-$ret"
((key&ble_decode_Meta)) && ret="M-$ret"
((key&ble_decode_Ctrl)) && ret="C-$ret"
((key&ble_decode_Altr)) && ret="A-$ret"
((key&ble_decode_Supr)) && ret="s-$ret"
((key&ble_decode_Hypr)) && ret="H-$ret"
[[ ! $f_unknown ]]
}
function ble-decode-unkbd {
local -a kbd
local kc
for kc in $*; do
.ble-decode-unkbd.single-key "$kc"
kbd[${#kbd[@]}]="$ret"
done
ret="${kbd[*]}"
}
# **** ble-decode-byte ****
# function ble-decode-byte {
# while [ $# -gt 0 ]; do
# "ble-decode-byte+$bleopt_input_encoding" "$1"
# shift
# done
# .ble-edit/exec:exec
# }
# function ble-decode-char {
# .ble-decode-char "$1"
# .ble-edit/exec:exec
# }
# function ble-decode-key {
# .ble-decode-key "$1"
# .ble-edit/exec:exec
# }
## 関数 .ble-decode-byte bytes...
## バイト値を整数で受け取って、現在の文字符号化方式に従ってデコードをします。
## デコードした結果得られた文字は .ble-decode-char を呼び出す事によって処理します。
function .ble-decode-byte {
while (($#)); do
"ble-decode-byte+$bleopt_input_encoding" "$1"
shift
done
}
# **** ble-decode-char/csi ****
_ble_decode_csi_mode=0
_ble_decode_csi_args=
_ble_decode_csimap_tilde=()
_ble_decode_csimap_alpha=()
function .ble-decode-char/csi/print {
local num ret
for num in "${!_ble_decode_csimap_tilde[@]}"; do
ble-decode-unkbd "${_ble_decode_csimap_tilde[num]}"
echo "ble-bind --csi '$num~' $ret"
done
for num in "${!_ble_decode_csimap_alpha[@]}"; do
local s; .ble-text.c2s "$num"; s="$ret"
ble-decode-unkbd "${_ble_decode_csimap_alpha[num]}"
echo "ble-bind --csi '$s' $ret"
done
}
function .ble-decode-char/csi/clear {
_ble_decode_csi_mode=0
}
function .ble-decode-char/csi/modify-kcode {
local mod="$(($1-1))"
if ((mod>=0)); then
((mod&0x01&&(kcode|=ble_decode_Shft),
mod&0x02&&(kcode|=ble_decode_Altr),
mod&0x04&&(kcode|=ble_decode_Ctrl),
mod&0x08&&(kcode|=ble_decode_Supr),
mod&0x10&&(kcode|=ble_decode_Hypr)))
fi
}
function .ble-decode-char/csi/decode {
local char="$1" rex kcode
if ((char==126)); then
if rex='^27;([1-9][0-9]*);?([1-9][0-9]*)$' && [[ $_ble_decode_csi_args =~ $rex ]]; then
# xterm "CSI 2 7 ; <mod> ; <char> ~" sequences
local kcode="$((BASH_REMATCH[2]&ble_decode_MaskChar))"
.ble-decode-char/csi/modify-kcode "${BASH_REMATCH[1]}"
csistat="$kcode"
return
fi
if rex='^([1-9][0-9]*)(;([1-9][0-9]*))?$' && [[ $_ble_decode_csi_args =~ $rex ]]; then
# "CSI <kcode> ; <mod> ~" sequences
kcode="${_ble_decode_csimap_tilde[BASH_REMATCH[1]]}"
if [[ $kcode ]]; then
.ble-decode-char/csi/modify-kcode "${BASH_REMATCH[3]}"
csistat="$kcode"
return
fi
fi
elif ((char==94||char==64)); then
if rex='^[1-9][0-9]*$' && [[ $_ble_decode_csi_args =~ $rex ]]; then
# rxvt "CSI <kcode> ^", "CSI <kcode> @" sequences
kcode="${_ble_decode_csimap_tilde[BASH_REMATCH[1]]}"
if [[ $kcode ]]; then
((kcode|=ble_decode_Ctrl,
char==64&&(kcode|=ble_decode_Shft)))
.ble-decode-char/csi/modify-kcode "${BASH_REMATCH[3]}"
csistat="$kcode"
return
fi
fi
fi
# pc-style "CSI 1; <mod> A" sequences
kcode="${_ble_decode_csimap_alpha[char]}"
if [[ $kcode ]]; then
if rex='^(1?|1;([1-9][0-9]*))$' && [[ $_ble_decode_csi_args =~ $rex ]]; then
.ble-decode-char/csi/modify-kcode "${BASH_REMATCH[2]}"
csistat="$kcode"
return
fi
fi
}
## 関数 .ble-decode-char/csi/consume char
## @param[in] char
## @var[out] csistat
function .ble-decode-char/csi/consume {
# 一番頻度の高い物
csistat=
((_ble_decode_csi_mode==0&&$1!=27)) && return 1
local char="$1"
case "$_ble_decode_csi_mode" in
(0)
_ble_decode_csi_mode=1
csistat=_ ;;
(1)
if ((char!=91)); then
_ble_decode_csi_mode=0
return 1
else
_ble_decode_csi_mode=2
_ble_decode_csi_args=
csistat=_
fi ;;
(2)
if ((32<=char&&char<64)); then
local ret; .ble-text.c2s "$char"
_ble_decode_csi_args="$_ble_decode_csi_args$ret"
csistat=_
elif ((64<=char&&char<127)); then
_ble_decode_csi_mode=0
.ble-decode-char/csi/decode "$char"
else
_ble_decode_csi_mode=0
fi ;;
esac
}
# **** ble-decode-char ****
declare _ble_decode_char__hook=
## 配列 _ble_decode_cmap_${_ble_decode_char__seq}[char]
## 文字列からキーへの写像を保持する。
## 各要素は文字の列 ($_ble_decode_char__seq $char) に対する定義を保持する。
## 各要素は以下の形式の何れかである。
## kcode+ 文字の列がキー kcode に一意に対応する事を表す。
## _ 文字の列が何らかのキーを表す文字列の prefix になっている事を表す。
## kcode_ 文字の列がキー kcode に対応すると同時に、
## 他のキーの文字列の prefix になっている事を表す。
_ble_decode_cmap_=()
# _ble_decode_char__seq が設定されている時は、
# 必ず _ble_decode_char2_reach も設定されている様にする。
_ble_decode_char2_seq=
_ble_decode_char2_reach=
_ble_decode_char2_modifier=
_ble_decode_char2_modkcode=
function .ble-decode-char {
local char="$1"
# decode error character
if ((char&ble_decode_Erro)); then
((char&=~ble_decode_Erro))
[[ $bleopt_error_char_vbell ]] && .ble-term.visible-bell "received a misencoded char $(builtin printf '\\u%04x' $char)"
[[ $bleopt_error_char_abell ]] && .ble-term.audible-bell
[[ $bleopt_error_char_discard ]] && return
# ((char&ble_decode_Erro)) : 最適化(過去 sequence は全部吐く)?
fi
# hook for quoted-insert, etc
if [[ $_ble_decode_char__hook ]]; then
local hook="$_ble_decode_char__hook"
_ble_decode_char__hook=
$hook "$char"
return 0
fi
local ent
.ble-decode-char/getent
if [[ ! $ent ]]; then
# シーケンスが登録されていない時
if [[ $_ble_decode_char2_reach ]]; then
local reach rest
reach=($_ble_decode_char2_reach)
rest="${_ble_decode_char2_seq:reach[1]}"
rest=(${rest//_/ } $char)
_ble_decode_char2_reach=
_ble_decode_char2_seq=
.ble-decode-char/csi/clear
.ble-decode-char/send-modified-key "${reach[0]}"
for char in "${rest[@]}"; do
.ble-decode-char "$char"
done
else
.ble-decode-char/send-modified-key "$char"
fi
elif [[ $ent == *_ ]]; then
# /\d*_/ (_ は続き (1つ以上の有効なシーケンス) がある事を示す)
_ble_decode_char2_seq="${_ble_decode_char2_seq}_$char"
if [[ ${ent%_} ]]; then
_ble_decode_char2_reach="${ent%_} ${#_ble_decode_char2_seq}"
elif [[ ! $_ble_decode_char2_reach ]]; then
# 1文字目
_ble_decode_char2_reach="$char ${#_ble_decode_char2_seq}"
fi
else
# /\d+/ (続きのシーケンスはなく ent で確定である事を示す)
_ble_decode_char2_seq=
_ble_decode_char2_reach=
.ble-decode-char/csi/clear
.ble-decode-char/send-modified-key "$ent"
fi
return 0
}
## @var[in] _ble_decode_char2_seq
## @var[in] char
function .ble-decode-char/getent {
builtin eval "ent=\"\${_ble_decode_cmap_$_ble_decode_char2_seq[$char]}\""
# CSI sequence
# ent= の時 → (CSI の結果)
# ent=_ の時 → (CSI の結果) + _
# ent=num の時 → num のまま (CSI の結果に拘わらず確定)
# ent=num_ の時 → num_ のまま
local csistat=
.ble-decode-char/csi/consume "$char"
if [[ $csistat && ! ${ent%_} ]]; then
if [[ ! $ent ]]; then
ent="$csistat"
else
ent="${csistat%_}_"
fi
fi
# ble-assert '[[ $ent =~ ^[0-9]*_?$ ]]'
}
function .ble-decode-char/process-modifier {
local mflag1="$1" mflag="$_ble_decode_char2_modifier"
if ((mflag1&mflag)); then
# 既に同じ修飾がある場合は通常と同じ処理をする。
# 例えば ESC ESC は3番目に来る文字に Meta 修飾をするのではなく、
# 2番目の ESC (C-[ に翻訳される) に対して
# 更に Meta 修飾をして C-M-[ を出力する。
return 1
else
# ※以下では kcode 内に既に mflag
# と重複する修飾がある場合は考慮していない。
# 重複があったという情報はここで消える。
((_ble_decode_char2_modkcode=kcode|mflag,
_ble_decode_char2_modifier=mflag1|mflag))
return 0
fi
}
## 関数 .ble-decode-char/send-modified-key kcode
## 指定されたキーを修飾して .ble-decode-key に渡します。
## kcode = 0..31 は C-@ C-a ... C-z C-[ C-\ C-] C-^ C-_ に変換されます。
## ESC は次に来る文字を meta 修飾します。
## @param[in] kcode
## 処理対象のキーコードを指定します。
function .ble-decode-char/send-modified-key {
local kcode="$1"
if ((0<=kcode&&kcode<32)); then
((kcode|=(kcode==0||kcode>26?64:96)|ble_decode_Ctrl))
fi
if (($1==27)); then
.ble-decode-char/process-modifier "$ble_decode_Meta" && return
elif ((_ble_decode_KCODE_SHIFT<=$1&&$1<=_ble_decode_KCODE_HYPER)); then
case "$1" in
($_ble_decode_KCODE_SHIFT)
.ble-decode-char/process-modifier "$ble_decode_Shft" && return ;;
($_ble_decode_KCODE_CONTROL)
.ble-decode-char/process-modifier "$ble_decode_Ctrl" && return ;;
($_ble_decode_KCODE_ALTER)
.ble-decode-char/process-modifier "$ble_decode_Altr" && return ;;
($_ble_decode_KCODE_META)
.ble-decode-char/process-modifier "$ble_decode_Meta" && return ;;
($_ble_decode_KCODE_SUPER)
.ble-decode-char/process-modifier "$ble_decode_Supr" && return ;;
($_ble_decode_KCODE_HYPER)
.ble-decode-char/process-modifier "$ble_decode_Hypr" && return ;;
esac
fi
if [[ $_ble_decode_char2_modifier ]]; then
local mflag="$_ble_decode_char2_modifier"
local mcode="$_ble_decode_char2_modkcode"
_ble_decode_char2_modifier=
_ble_decode_char2_modkcode=
if ((kcode&mflag)); then
.ble-decode-key "$mcode"
else
((kcode|=mflag))
fi
fi
.ble-decode-key "$kcode"
}
function .ble-decode-char.bind {
local -a seq=($1)
local kc="$2"
local i iN=${#seq[@]} char tseq=
for ((i=0;i<iN;i++)); do
local char="${seq[i]}"
builtin eval "local okc=\"\${_ble_decode_cmap_$tseq[$char]}\""
if ((i+1==iN)); then
if [[ ${okc//[0-9]/} == _ ]]; then
builtin eval "_ble_decode_cmap_$tseq[$char]=\"${kc}_\""
else
builtin eval "_ble_decode_cmap_$tseq[$char]=\"${kc}\""
fi
else
if [[ ! $okc ]]; then
builtin eval "_ble_decode_cmap_$tseq[$char]=_"
else
builtin eval "_ble_decode_cmap_$tseq[$char]=\"${okc%_}_\""
fi
tseq="${tseq}_$char"
fi
done
}
function .ble-decode-char.unbind {
local -a seq=($1)
local char="${seq[$((iN-1))]}"
local tseq=
local i iN=${#seq}
for ((i=0;i<iN-1;i++)); do
tseq="${tseq}_${seq[$i]}"
done
local isfirst=1 ent=
while
builtin eval "ent=\"\${_ble_decode_cmap_$tseq[$char]}\""
if [[ $isfirst ]]; then
# 数字を消す
isfirst=
if [[ $ent == *_ ]]; then
# ent = 1234_ (両方在る時は片方消して終わり)
builtin eval _ble_decode_cmap_$tseq[$char]=_
break
fi
else
# _ を消す
if [[ $ent != _ ]]; then
# ent = 1234_ (両方在る時は片方消して終わり)
builtin eval _ble_decode_cmap_$tseq[$char]=${ent%_}
break
fi
fi
unset "_ble_decode_cmap_$tseq[$char]"
builtin eval "((\${#_ble_decode_cmap_$tseq[@]}!=0))" && break
[[ $tseq ]]
do
char="${tseq##*_}"
tseq="${tseq%_*}"
done
}
function .ble-decode-char.dump {
local tseq="$1" nseq ccode
nseq=("${@:2}")
builtin eval "local -a ccodes=(\${!_ble_decode_cmap_$tseq[@]})"
for ccode in "${ccodes[@]}"; do
local ret; ble-decode-unkbd "$ccode"
local cnames
cnames=("${nseq[@]}" "$ret")
builtin eval "local ent=\${_ble_decode_cmap_$tseq[$ccode]}"
if [[ ${ent%_} ]]; then
local kcode="${ent%_}" ret
ble-decode-unkbd "$kcode"; local key="$ret"
builtin echo "ble-bind -k '${cnames[*]}' '$key'"
fi
if [[ ${ent//[0-9]/} == _ ]]; then
.ble-decode-char.dump "${tseq}_$ccode" "${cnames[@]}"
fi
done
}
# **** ble-decode-key ****
## 配列 _ble_decode_${keymap}_kmap_${_ble_decode_key__seq}[key]
## 各 keymap は (キーシーケンス, コマンド) の集合と等価です。
## この配列は keymap の内容を以下の形式で格納します。
##
## @param[in] keymap
## 対象の keymap の名称を指定します。
##
## @param[in] _ble_decode_key__seq
## @param[in] key
## _ble_decode_key__seq key の組合せでキーシーケンスを表します。
##
## @value
## 以下の形式の何れかです。
## - "_"
## - "_:command"
## - "1:command"
##
## 始めの文字が "_" の場合はキーシーケンスに続きがある事を表します。
## つまり、このキーシーケンスを prefix とするより長いキーシーケンスが登録されている事を表します。
## command が指定されている場合には、より長いシーケンスでの一致に全て失敗した時点で
## command が実行されます。シーケンスを受け取った段階では実行されません。
##
## 初めの文字が "1" の場合はキーシーケンスが確定的である事を表します。
## つまり、このキーシーケンスを prefix とするより長いシーケンスが登録されてなく、
## このシーケンスを受け取った段階で command を実行する事が確定する事を表します。
##
## 変数 _ble_decode_kmaps := ( ':' kmap ':' )+
## 存在している kmap の名前の一覧を保持します。
## 既定の kmap (名前無し) は含まれません。
_ble_decode_kmaps=
function .ble-decode/keymap/register {
local kmap="$1"
if [[ $kmap && $_ble_decode_kmaps != *":$kmap:"* ]]; then
_ble_decode_kmaps="$_ble_decode_kmaps:$kmap:"
fi
}
function .ble-decode/keymap/dump {
local kmap="$1" arrays
builtin eval "arrays=(\"\${!_ble_decode_${kmap}_kmap_@}\")"
builtin echo ".ble-decode/keymap/register $kmap"
ble/util/declare-print-definitions "${arrays[@]}"
}
## 関数 kmap ; .ble-decode-key.bind keycodes command
function .ble-decode-key.bind {
local dicthead="_ble_decode_${kmap}_kmap_"
local -a seq=($1)
local cmd="$2"
.ble-decode/keymap/register "$kmap"
local i iN="${#seq[@]}" key tseq=
for ((i=0;i<iN;i++)); do
local key="${seq[i]}"
builtin eval "local ocmd=\"\${$dicthead$tseq[$key]}\""
if ((i+1==iN)); then
if [[ ${ocmd::1} == _ ]]; then
builtin eval "$dicthead$tseq[$key]=\"_:\$cmd\""
else
builtin eval "$dicthead$tseq[$key]=\"1:\$cmd\""
fi
else
if [[ ! $ocmd ]]; then
builtin eval "$dicthead$tseq[$key]=_"
elif [[ ${ocmd::1} == 1 ]]; then
builtin eval "$dicthead$tseq[$key]=\"_:\${ocmd#?:}\""
fi
tseq="${tseq}_$key"
fi
done
}
function .ble-decode-key.unbind {
local dicthead=_ble_decode_${kmap}_kmap_
local -a seq=($1)
local i iN=${#seq}
local key=${seq[iN-1]}
local tseq=
for ((i=0;i<iN-1;i++)); do
tseq="${tseq}_${seq[$i]}"
done
local isfirst=1 ent=
while
builtin eval "ent=\"\${$dicthead$tseq[$key]}\""
if [[ $isfirst ]]; then
# command を消す
isfirst=
if [[ ${ent::1} == _ ]]; then
# ent = _ または _:command の時は、単に command を消して終わる。
# (未だ bind が残っているので、登録は削除せず break)。
builtin eval $dicthead$tseq[$key]=_
break
fi
else
# prefix の ent は _ か _:command のどちらかの筈。
if [[ $ent != _ ]]; then
# _:command の場合には 1:command に書き換える。
# (1:command の bind が残っているので登録は削除せず break)。
builtin eval $dicthead$tseq[$key]="1:${ent#?:}"
break
fi
fi
unset "$dicthead$tseq[$key]"
builtin eval "((\${#$dicthead$tseq[@]}!=0))" && break
[[ $tseq ]]
do
key="${tseq##*_}"
tseq="${tseq%_*}"
done
}
function .ble-decode-key.dump {
# 引数の無い場合: 全ての kmap を dump
local kmap
if (($#==0)); then
for kmap in ${_ble_decode_kmaps//:/ }; do
echo "# keymap $kmap"
.ble-decode-key.dump "$kmap"
done
return
fi
local kmap="$1" tseq="$2" nseq="$3"
local dicthead=_ble_decode_${kmap}_kmap_
local kmapopt=
[[ $kmap ]] && kmapopt=" -m '$kmap'"
local kcode kcodes
builtin eval "kcodes=(\${!$dicthead$tseq[@]})"
for kcode in "${kcodes[@]}"; do
local ret; ble-decode-unkbd "$kcode"
local knames=$nseq${nseq:+ }$ret
builtin eval "local ent=\${$dicthead$tseq[$kcode]}"
if [[ ${ent:2} ]]; then
local cmd="${ent:2}" q=\' Q="'\''"
case "$cmd" in
# ble-edit+insert-string *)
# echo "ble-bind -sf '${knames//$q/$Q}' '${cmd#ble-edit+insert-string }'" ;;
(ble-edit+*)
echo "ble-bind$kmapopt -f '${knames//$q/$Q}' '${cmd#ble-edit+}'" ;;
('.ble-edit.bind.command '*)
echo "ble-bind$kmapopt -cf '${knames//$q/$Q}' '${cmd#.ble-edit.bind.command }'" ;;
(*)
echo "ble-bind$kmapopt -xf '${knames//$q/$Q}' '${cmd}'" ;;
esac
fi
if [[ ${ent::1} == _ ]]; then
.ble-decode-key.dump "$kmap" "${tseq}_$kcode" "$knames"
fi
done
}
## 現在選択されている keymap
declare _ble_decode_key__kmap
##
declare -a _ble_decode_keymap_stack=()
## 関数 .ble-decode/keymap/push kmap
function .ble-decode/keymap/push {
ble/util/array-push _ble_decode_keymap_stack "$_ble_decode_key__kmap"
_ble_decode_key__kmap="$1"
}
## 関数 .ble-decode/keymap/pop
function .ble-decode/keymap/pop {
local count="${#_ble_decode_keymap_stack[@]}"
local last="$((count-1))"
_ble_decode_key__kmap="${_ble_decode_keymap_stack[last]}"
unset '_ble_decode_keymap_stack[last]'
}
## 今迄に入力された未処理のキーの列を保持します
declare _ble_decode_key__seq= # /(_\d+)*/
declare _ble_decode_key__hook=
## 関数 .ble-decode-key key
## キー入力の処理を行います。登録されたキーシーケンスに一致した場合、
## 関連付けられたコマンドを実行します。
## 登録されたキーシーケンスの前方部分に一致する場合、即座に処理は行わず
## 入力されたキーの列を _ble_decode_key__seq に記録します。
##
## @var[in] key
## 入力されたキー
##
function .ble-decode-key {
local key="$1"
if [[ $_ble_decode_key__hook ]]; then
local hook="$_ble_decode_key__hook"
_ble_decode_key__hook=
$hook "$key"
return 0
fi
local dicthead=_ble_decode_${_ble_decode_key__kmap:-$bleopt_default_keymap}_kmap_
builtin eval "local ent=\"\${$dicthead$_ble_decode_key__seq[$key]}\""
if [ "${ent%%:*}" = 1 ]; then
# /1:command/ (続きのシーケンスはなく ent で確定である事を示す)
local command="${ent:2}"
.ble-decode-key/invoke-command || _ble_decode_key__seq=
elif [ "${ent%%:*}" = _ ]; then
# /_(:command)?/ (続き (1つ以上の有効なシーケンス) がある事を示す)
_ble_decode_key__seq="${_ble_decode_key__seq}_$key"
else
# 遡って適用 (部分一致、または、既定動作)
.ble-decode-key/invoke-partial-match "$key" && return
# エラーの表示
local kcseq="${_ble_decode_key__seq}_$key" ret
ble-decode-unkbd "${kcseq//_/ }"
local kbd="$ret"
[[ $bleopt_error_kseq_vbell ]] && .ble-term.visible-bell "unbound keyseq: $kbd"
[[ $bleopt_error_kseq_abell ]] && .ble-term.audible-bell
# 残っている文字の処理
if [[ $_ble_decode_key__seq ]]; then
if [[ $bleopt_error_kseq_discard ]]; then
_ble_decode_key__seq=
else
local -a keys
keys=(${_ble_decode_key__seq//_/ } $key)
local i iN
_ble_decode_key__seq=
for ((i=1,iN=${#keys[*]};i<iN;i++)); do
# 2文字目以降を処理
.ble-decode-key "${keys[i]}"
done
fi
fi
fi
return 0
}
## 関数 .ble-decode-key/invoke-partial-match fail
## これまでのキー入力に対する部分一致を試みます。
## 登録されている部分一致がない場合には単体のキーに対して既定の動作を呼び出します。
## 既定の動作も登録されていない場合には関数は失敗します。
## @var[in,out] _ble_decode_key__seq
## @var[in] next
## _ble_decode_key__seq は既に入力された未処理のキー列を指定します。
## next には今回入力されたキーの列を指定します。
## この関数は _ble_decode_key__seq next からなるキー列に対する部分一致を試みます。
##
## この関数は以下の様に動作します。
## 1 先ず、_ble_decode_key__seq に対して部分一致がないか確認し、部分一致する
## binding があればそれを実行します。
## - _ble_decode_key__seq + key の全体に対する一致は試みない事に注意して下
## さい。全体一致については既にチェックして失敗しているという前提です。
## 何故なら部分一致を試みるのは常に最長一致が失敗した時だけだからです。
## 2 _ble_decode_key__seq に対する部分一致が存在しない場合には、
## ch = _ble_decode_key__seq + key の最初のキーについて登録されている既定の
## 動作を実行します。ch はつまり、_ble_decode_key__seq が空でない時はその先
## 頭で、空の場合は key になります。
## 3 一致が存在して処理が実行された場合には、その後一旦 _ble_decode_key__seq
## がクリアされ、一致しなかった残りの部分に対して再度 .ble-decode-key を呼
## び出して再解釈が行われます。
## 1, 2 のいずれでも一致が見付からなかった場合には、_ble_decode_key__seq を
## 呼出時の状態に戻し関数は失敗します。つまり、この場合 _ble_decode_key__seq
## は、呼出元からは変化していない様に見えます。
##
function .ble-decode-key/invoke-partial-match {
local dicthead=_ble_decode_${_ble_decode_key__kmap:-$bleopt_default_keymap}_kmap_
local next="$1"
if [[ $_ble_decode_key__seq ]]; then
local last="${_ble_decode_key__seq##*_}"
_ble_decode_key__seq="${_ble_decode_key__seq%_*}"
builtin eval "local ent=\"\${$dicthead$_ble_decode_key__seq[$last]}\""
if [[ $ent == '_:'* ]]; then
local command="${ent:2}"
.ble-decode-key/invoke-command || _ble_decode_key__seq=
.ble-decode-key "$next"
return 0
else # ent = _
if .ble-decode-key/invoke-partial-match "$last"; then
.ble-decode-key "$next"
return 0
else
# 元に戻す
_ble_decode_key__seq="${_ble_decode_key__seq}_$last"
return 1
fi
fi
else
# ここでは指定した単体のキーに対する既定の処理を実行する
# $next 単体でも設定がない場合はここに来る。
# 通常の文字などは全てここに流れてくる事になる。
# 既定の文字ハンドラ
local key="$1"
if (((key&ble_decode_MaskFlag)==0&&32<=key&&key<ble_decode_function_key_base)); then
builtin eval "local command=\"\${${dicthead}[$_ble_decode_KCODE_DEFCHAR]:2}\""
.ble-decode-key/invoke-command && return 0
fi
# 既定のキーハンドラ
builtin eval "local command=\"\${${dicthead}[$_ble_decode_KCODE_DEFAULT]:2}\""
.ble-decode-key/invoke-command && return 0
return 1
fi
}
## 関数 .ble-decode-key/invoke-command
## コマンドが有効な場合に、指定したコマンドを適切な環境で実行します。
## @var[in] command
## 起動するコマンドを指定します。空の場合コマンドは実行されません。
## @var[in] _ble_decode_key__seq
## @var[in] key
## _ble_decode_key__seq は前回までに受け取ったキーの列です。
## key は今回新しく受け取ったキーの列です。
## _ble_decode_key__seq と key の組合せで現在入力されたキーシーケンスになります。
## コマンドを実行した場合 _ble_decode_key__seq はクリアされます。
## コマンドを実行しなかった場合
## @return
## コマンドが実行された場合に 0 を返します。それ以外の場合は 1 です。
##