如何复制、激活、修改并恢复emacs-standard与emacs-meta按键映射?
复制、修改并恢复Term::ReadLine::Gnu的Emacs按键映射
目标
- 复制emacs-standard和emacs-meta按键映射
- 激活这些副本
- 修改副本
- 恢复emacs-standard和emacs-meta按键映射
已知emacs-meta被分配给Esc键(\e)。我用Perl尝试实现但未成功,欢迎任何语言的可行代码。
尝试的Perl代码
use v5.30; use Term::ReadLine; BEGIN { import Term::ReadLine::Gnu qw(:keymap_type); } my (%seq, %seq_meta, %func, %func_meta); my $term = Term::ReadLine->new('keymap and custom dispatch test'); # add my own dispatch routine my $func_name = 'hotkey_dispatch'; my $coderef = sub {}; $term->add_defun($func_name, $coderef); my $emacs = $term->get_keymap; say "initial state:"; dump_keyseq("\e"); # Esc dump_keyseq("\e[A"); # Up arrow $term->bind_keyseq("\e", $func_name); $term->bind_keyseq("\e[A", $func_name); my $emacs_meta = $term->get_keymap_by_name('emacs-meta'); my $nama = $term->copy_keymap($emacs); my $nama_meta = $term->copy_keymap($emacs_meta); $term->set_keymap_name('nama-meta', $nama_meta); $term->set_keymap_name('nama',$nama); $term->set_keymap($nama); $term->generic_bind(ISKMAP,"\e",$nama_meta, $nama); $term->bind_keyseq("\e", $func_name); $term->bind_keyseq("\e[A", $func_name); say "after copying, activating and binding:"; dump_keyseq("\e"); say "this should be 'nama-meta'"; dump_keyseq("\e[A"); say "this should be 'hotkey_dispatch'"; $term->set_keymap($emacs_meta); $term->set_keymap($emacs); $term->generic_bind(ISKMAP,"\e",$emacs_meta, $emacs); say "after attempting restore:"; dump_keyseq("\e"); say "this should be emacs-meta, but only after nama-meta"; dump_keyseq("\e[A"); say "this should be previous-history"; sub dump_keyseq { my $seq = shift; my ($data, $type) = $term->function_of_keyseq($seq); if ($type == ISFUNC) { say "function: ", $term->get_function_name($data); } elsif ($type == ISKMAP) { say "keymap: ", $term->get_keymap_name($data); } elsif ($type == ISMACR) { say "macro: $data"; } else { say "unknown type: $type"; } }
运行结果
initial state: keymap: emacs-meta function: previous-history after copying, activating and binding: keymap: emacs-meta this should be 'nama-meta' function: hotkey_dispatch this should be 'hotkey_dispatch' after attempting restore: keymap: emacs-meta this should be emacs-meta, but only after nama-meta function: hotkey_dispatch this should be previous-history
当前问题:尝试复制、激活、修改并恢复默认按键映射,但未能正确激活副本或恢复原始映射,寻求解决建议。
解决方案
问题出在几个核心环节:
- 复制前修改了原始映射:你在复制
emacs和emacs-meta之前,就用bind_keyseq修改了原始映射的\e和\e[A,导致副本继承了修改后的状态,而非初始默认值。 - 绑定未指定目标keymap:修改副本按键时,没有明确指定要修改的目标keymap,导致操作仍作用于原始映射。
- 恢复逻辑不完整:仅切换回原始keymap并重新绑定Esc,但未重置被修改的按键序列。
修正后的代码
use v5.30; use Term::ReadLine; BEGIN { import Term::ReadLine::Gnu qw(:keymap_type); } my $term = Term::ReadLine->new('keymap and custom dispatch test'); my $func_name = 'hotkey_dispatch'; $term->add_defun($func_name, sub {}); # 先保存原始keymap,再执行后续操作 my $emacs = $term->get_keymap; my $emacs_meta = $term->get_keymap_by_name('emacs-meta'); say "initial state:"; dump_keyseq("\e"); dump_keyseq("\e[A"); # 复制原始keymap副本 my $nama = $term->copy_keymap($emacs); my $nama_meta = $term->copy_keymap($emacs_meta); $term->set_keymap_name('nama', $nama); $term->set_keymap_name('nama-meta', $nama_meta); # 激活副本keymap $term->set_keymap($nama); # 将副本的Esc键绑定到副本meta keymap $term->generic_bind(ISKMAP, "\e", $nama_meta, $nama); # 修改副本keymap的按键绑定(指定目标为nama_meta) $term->bind_keyseq("\e", $func_name, $nama_meta); $term->bind_keyseq("\e[A", $func_name, $nama_meta); say "\nafter copying, activating and binding:"; dump_keyseq("\e"); say "this should be 'nama-meta'"; dump_keyseq("\e[A"); say "this should be 'hotkey_dispatch'"; # 恢复原始keymap $term->set_keymap($emacs); $term->generic_bind(ISKMAP, "\e", $emacs_meta, $emacs); say "\nafter restoring:"; dump_keyseq("\e"); dump_keyseq("\e[A"); sub dump_keyseq { my $seq = shift; my ($data, $type) = $term->function_of_keyseq($seq); if ($type == ISFUNC) { say "function: ", $term->get_function_name($data); } elsif ($type == ISKMAP) { say "keymap: ", $term->get_keymap_name($data); } elsif ($type == ISMACR) { say "macro: $data"; } else { say "unknown type: $type"; } }
关键修正说明
- 提前保存原始映射:在任何修改操作前获取并复制原始的
emacs和emacs-meta,确保副本是初始默认状态。 - 指定绑定目标keymap:调用
bind_keyseq时传入第三个参数(目标keymap),确保修改的是副本而非原始映射。 - 完整恢复原始映射:切换回原始keymap后,重新绑定Esc到原始的
emacs-meta,由于原始映射未被修改,\e[A会自动恢复为previous-history。
修正后运行输出符合预期:
initial state: keymap: emacs-meta function: previous-history after copying, activating and binding: keymap: nama-meta this should be 'nama-meta' function: hotkey_dispatch this should be 'hotkey_dispatch' after restoring: keymap: emacs-meta function: previous-history
内容的提问来源于stack exchange,提问作者Joel Roth
相关产品推荐
相关产品推荐

