Bilibili-Evolved 快捷键扩展「无动作」插件:用空动作屏蔽 B 站原生快捷键
【免费下载链接】Bilibili-Evolved强大的哔哩哔哩增强脚本项目地址: https://gitcode.com/gh_mirrors/bi/Bilibili-Evolved
导读
「无动作」(快捷键扩展 - 无动作)是 Bilibili-Evolved 仓库中一个短小精悍的插件:它在脚本的快捷键动作列表里注册一个名为"无动作"的占位动作,把任意按键绑定到这个动作上,就能阻止该按键原有的快捷键行为,从而屏蔽 B 站页面自带快捷键(如投币的C、全屏的W等)。读完本文你将掌握:这个插件如何安装启用、它"阻止原生快捷键"的底层实现原理(prevent标志与事件拦截逻辑)、以及如何配合"快捷键扩展"组件实现"自定义按键 + 屏蔽原生按键"的完整方案。
插件定位:一个动作、两行注册
该插件的文档只有一句话:
在快捷键的动作列表里添加一个 "无动作", 将按键绑定到这个上面就可以阻止原有的快捷键行为.
它位于仓库的 registry/lib/plugins/utils/keymap-empty-action.ts/index.md,对应实现为同目录下的 index.ts。整个插件通过 Bilibili-Evolved 的插件数据槽(addData)完成注册,核心代码非常精简:
export const plugin: PluginMetadata = { name: 'keymap.actions.empty', displayName: '快捷键扩展 - 无动作', setup: ({ addData }) => { addData('keymap.actions', (actions: Record<string, KeyBindingAction>) => { actions.empty = { displayName: '无动作', prevent: true, run: none, } }) addData('keymap.presets', (presetBase: Record<string, string>) => { presetBase.empty = '' }) }, }从源码结构看,它做了两件事:
- 通过
keymap.actions数据槽向动作列表注册empty动作,显示名为"无动作"; - 通过
keymap.presets数据槽在presetBase(默认按键表)中为它登记空字符串按键,即默认不绑定任何键,完全由用户自行指定。
安装与启用方式
这是一个标准的用户插件(PluginMetadata),在 Bilibili-Evolved 中安装启用即可:
- 打开脚本的设置面板,进入「用户插件」页面(或通过在线插件仓库搜索"无动作");
- 启用「快捷键扩展 - 无动作」插件后,打开「快捷键扩展」组件的设置(快捷键列表),即可在动作列表中看到新增的"无动作"一行;
- 在其"自定义按键"栏填入想要屏蔽的原生快捷键,失去焦点时自动保存(见 help.md 对自定义按键文本框的描述)。
前置条件:该插件只提供"无动作"这个动作本身,其生效依赖「快捷键扩展」组件(keymap,见 registry/lib/components/utils/keymap/index.ts)的快捷键分发机制,因此需要同时启用「快捷键扩展」组件才能看到并配置该动作。
工作原理:prevent: true+ 空运行函数
理解这个插件如何"阻止原有的快捷键行为",关键在于KeyBindingAction接口中的prevent可选字段,以及run: none这个空实现。
在 registry/lib/components/utils/keymap/bindings.ts 中定义了动作接口:
export interface KeyBindingAction { displayName: string run: (context: KeyBindingActionContext) => unknown prevent?: boolean /** 默认打字时忽略快捷键, 将此属性设置为 false 可以在打字时允许触发快捷键 */ ignoreTyping?: boolean /** 默认聚焦在可聚焦元素时不忽略快捷键, 将此属性设置为 true 可以在聚焦时禁止触发快捷键 */ ignoreFocus?: boolean }而 bindings.ts 在按键命中后的分发逻辑为:
const actionResult = binding.action.run({ ... }) const actionSuccess = !lodash.isNil(actionResult) if (binding.action.prevent ?? actionSuccess) { e.stopImmediatePropagation() e.preventDefault() }也就是说:普通动作只有在run返回非null/undefined(表示动作执行成功)时才会阻止事件继续传播;而"无动作"插件把prevent显式设为true,并让run执行none(一个来自@/core/utils的空操作函数,可在 src/core/utils 中确认其无操作实现)。于是无论该动作是否"做"了什么,只要按键匹配命中,就会无条件执行:
e.stopImmediatePropagation()—— 中断事件冒泡链,阻止页面其他监听器(包括 B 站原生快捷键监听)收到这次按键;e.preventDefault()—— 阻止浏览器对该按键的默认行为。
这一组合正是"屏蔽原生快捷键"的完整机制:绑定"无动作"的按键被脚本在捕获阶段消费掉,B 站原有的快捷键逻辑自然不会再触发。
为什么需要它:脚本快捷键与 B 站原生快捷键互不影响
「快捷键扩展」组件修改某动作的按键,并不会覆盖 B 站自带的快捷键——两者是独立的监听体系。官方帮助文档 help.md 对此有明确说明:
b 站自带有一些快捷键, 修改本组件提供的相同动作快捷键不会影响 b 站自带的快捷键, 如果希望屏蔽掉 b 站自带的快捷键, 可以安装
快捷键扩展 - 无动作插件, 并将无动作绑定到希望屏蔽的快捷键上. 例如希望用C键投币且不希望自带的W键触发投币, 则应该在组件里配置投币为c, 无动作为w.
这意味着:"无动作"插件的典型应用场景是按键冲突治理——当用户希望把某个按键改作他用(如用C投币),但 B 站原生仍用该键(如W全屏)时,把原生按键绑定到"无动作"即可彻底消除冲突,而不是去修改 B 站自身的快捷键。
实战示例:屏蔽 B 站自带的W全屏键
以官方文档给出的投币场景为例,完整操作如下:
- 启用「快捷键扩展」组件与「快捷键扩展 - 无动作」插件;
- 打开快捷键设置(可在脚本设置面板或启动栏中搜索"快捷键扩展设置"进入,见 index.ts 中通过
launchBar.actions注册的打开入口); - 在"投币"动作的自定义按键栏填入
c; - 在"无动作"动作的自定义按键栏填入
w; - 之后按下
C触发脚本的投币动作,按下W则被"无动作"消费,B 站自带的全屏/投币等行为不再发生。
底层数据流:动作与按键如何合并生效
要深入理解该插件在整个快捷键体系中的位置,需要了解「快捷键扩展」组件的数据组织方式:
- 动作注册:内置动作在 registry/lib/components/utils/keymap/actions.ts 中定义(全屏、宽屏、音量、跳转、投币、收藏、点赞、弹幕开关、进度跳转等),最终通过
registerAndGetData('keymap.actions', builtInActions)汇总所有插件注册的动作(见 actions.ts)。 - 按键注册:
presetBase记录每个动作的默认按键(如fullscreen: 'f'、like: 'l'、sendComment: 'ctrl enter'),builtInPresets提供 Default / YouTube / HTML5Player / PotPlayer 等预设,见 presets.ts。 - 最终合并:组件在 index.ts 中按优先级合并按键——
{ ...presetBase, ...preset, ...customKeyBindings },即默认按键 < 预设按键 < 自定义按键,合并结果解析为KeyBinding[]后交给loadKeyBindings挂载全局keydown监听(含 Shadow DOM 监听,见 bindings.ts)。
「无动作」插件正是通过这两个数据槽(keymap.actions与keymap.presets)无缝接入上述体系的:presetBase.empty = ''保证它在默认情况下不占用任何按键,用户只需在设置界面为它指定要屏蔽的键即可。
扩展性提示:插件如何新增"动作"
「无动作」插件本身也是"如何扩展快捷键体系"的一个绝佳范例。任何插件都可以仿照它,通过keymap.actions添加新动作、通过keymap.presets添加默认按键。官方文档 help.md 给出的自定义动作模板如下:
addData('keymap.actions', (actions: Record<string, KeyBindingAction>) => { actions.watchlater = { displayName: '稍后再看', run: context => { const { clickElement } = context return clickElement('...选择器...', context) }, } }) addData('keymap.presets', (presetBase: Record<string, string>) => { presetBase.watchlater = 'shift w' })动作的run返回值约定为:true表示完成动作并应阻止其他事件;返回空值表示当前场景不适用、应继续执行原有事件(help.md)。相比之下,「无动作」通过prevent: true+run: none让动作"不做事但必拦截",这正是它与其他动作在语义上的本质区别。
小结
- 「无动作」插件以最少的代码(仅注册一个动作与一个空按键)实现了"屏蔽 B 站原生快捷键"的能力;
- 其核心是
KeyBindingAction.prevent字段配合空运行函数,在快捷键分发处触发stopImmediatePropagation与preventDefault; - 使用时需同时启用「快捷键扩展」组件,并在设置界面为"无动作"指定欲屏蔽的按键;
- 该插件同时是理解 Bilibili-Evolved 插件数据槽(
keymap.actions/keymap.presets)扩展机制的最佳入门示例。
【免费下载链接】Bilibili-Evolved强大的哔哩哔哩增强脚本项目地址: https://gitcode.com/gh_mirrors/bi/Bilibili-Evolved
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考