开发过程优化·自定义鼠标右键菜单

为了改善日常工作中的开发体验,我希望在某个项目目录下点击鼠标右键的快捷菜单,让程序自动为该项目引入一个内部的工具库文件并挂载到项目中。

        实现该功能需要组装一些零碎的电脑应用知识,下面徐徐渐进依次说明:

        1、在右键菜单中添加一级菜单

        1)运行“regedit”打开注册表编辑器;

        2)找到“HKEY_CLASSES_ROOT\Directory\Background\shell(针对文件夹空白处右键菜单)”,在左侧树shell下新建一个子项(例如:front_tools),并设置该子项右侧的默认值(该值是右键菜单中显示的文案,缺省则会使用子项的左侧树名称);

        3)在上述子项(front_tools)下新建一个子项“command”,在其右侧的默认值中设置想要调用的程序(例如:此处设置nodejs程序,若要执行JS脚本,可在程序后跟上脚本的绝对路径)。

1

        虽然上述方法可以实现添加菜单,但实际工作中,我们更需要的其实是个二级菜单,就像图中的“新建”菜单,里面可以包含很多子菜单。

        2、在右键菜单中添加二级菜单

        1)添加二级菜单数据

        在注册表编辑器中找到“HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\CommandStore\shell”,新建子项(例如:importCosUtil),并在其右侧默认数据中设置该二级菜单对应的中文文案(例如:引入腾讯云公共函数)。然后再在importCosUtil下新建子项command,并在其右侧设置要调用的应用程序(图例中我创建了两个二级菜单);

        2)创建一级菜单并与二级菜单建立关联

        在“HKEY_CLASSES_ROOT\Directory\Background\shell”下创建子项(例如:前端便捷工具),并在其右侧新建“字符串值”SubCommands,该字符串值对应的数据设置为想要关联的二级菜单的名称(例如:“importCosUtil;importOssUtil;”);

        此时,在文件夹中点击鼠标右键,即可看到自定义的菜单了。

        需要注意的是:一级菜单(即示例中的“前端便捷工具”)右侧的默认数据不要做修改,应保持显示“(数据未设置)”,否则当点击鼠标右键时,二级菜单无法显示。

2

        3、编写脚本来添加右键菜单

        之前两节都是手动操作注册表,比较繁琐,我们需要编写一个安装脚本,双击运行脚本后自动添加右键菜单。因为注册表的部分内容与业务相关,所以我们结合整体方案思路来说明:

        1)使用批处理进行一键安装

        设置一个名为install.bat的批处理文件,用来一键安装程序,安装过程中会构建注册表脚本来实现添加右键菜单的操作;

        install.bat代码:

node install.js

        install.js代码:

const path = require('path');

const Registry = require('winreg');

let nodePath = path.join(process.env.NVM_SYMLINK, 'node.exe');

let copyPath = path.join(__dirname, 'commands', 'copy.js');

const methodToPromise = function (host, method) {

  return new Promise((resolve, reject) => {

if (!host || !method) {reject('宿主名和方法名不能为空')}

    host[method](function (err) {

      if (err) {reject(err)}

      else {resolve(...arguments)}

    });

  })

}

let ret = (async function () {

  let regKey = new Registry({

    hive: Registry.HKCR,

key: '\\Directory\\Background\\shell\\前端便捷工具'

  });

  await methodToPromise(regKey, 'create');

// create方法创建的“(默认)”值不是“(数值未设置)”,需要用clear清空。

  await methodToPromise(regKey, 'clear');

  regKey.set('SubCommands', 'REG_SZ', 'importCosUtil;importOssUtil;', function (err) {

    if (err) {console.log(err)}

  });

  let regKey1 = new Registry({

    hive: Registry.HKLM,

    key: '\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CommandStore\\shell\\importCosUtil'

  });

  let regKey2 = new Registry({

    hive: Registry.HKLM,

    key: '\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CommandStore\\shell\\importOssUtil'

  });

  let regKey3 = new Registry({

    hive: Registry.HKLM,

    key: '\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CommandStore\\shell\\importCosUtil\\command'

  });

  let regKey4 = new Registry({

    hive: Registry.HKLM,

    key: '\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CommandStore\\shell\\importOssUtil\\command'

  });

  // let regVal3 = "\"\\\"C:\\Users\\Administrator\\AppData\\Roaming\\nvm\\v10.4.1\\node.exe\\\" \\\"E:\\public\\commands\\copy.js\\\" cosUtil.js \\\"%V\\\"\"";

  let regVal3 = `\"\\\"${nodePath}\\\" \\\"${copyPath}\\\" cosUtil.js \\\"%V\\\"\"`;

  let regVal4 = `\"\\\"${nodePath}\\\" \\\"${copyPath}\\\" ossUtil.js \\\"%V\\\"\"`;

  await methodToPromise(regKey1, 'create');

  await methodToPromise(regKey2, 'create');

  await methodToPromise(regKey3, 'create');

  await methodToPromise(regKey4, 'create');

regKey1.set(Registry.DEFAULT_VALUE, 'REG_SZ', '引入腾讯云公共函数', function (err) {console.log(err)});

regKey2.set(Registry.DEFAULT_VALUE, 'REG_SZ', '引入阿里云公共函数', function (err) {console.log(err)});

  regKey3.set(Registry.DEFAULT_VALUE, 'REG_SZ', regVal3, function (err) {console.log(err)});

  regKey4.set(Registry.DEFAULT_VALUE, 'REG_SZ', regVal4, function (err) {console.log(err)});

})();

        上述代码中,我是通过“winreg”这个依赖包来操作注册表的,因为操作注册表需要管理员权限,所以要以管理员身份运行批处理。

        其中一个难点在regVal3和regVal4的内容上,需要多层字符转义。其最终写入注册表的内容是:

"C:\Users\Administrator\AppData\Roaming\nvm\v10.4.1\node.exe" "e:\public\commands\copy.js" cosUtil.js "%V"

        2)编写点击右键菜单时的响应脚本

        当点击右键菜单时,系统会执行注册表command项中设置的命令,此处以“引入腾讯云公共函数”为例,command内容为

"C:\Users\Administrator\AppData\Roaming\nvm\v10.4.1\node.exe" "E:\public\commands\copy.js" cosUtil.js "%V"

        意即点击菜单后会执行copy.js这个本地脚本(将某个公共函数库拷贝到当前文件夹中)。

        copy.js代码:

const fs = require('fs');

const path = require('path');

const toolsNode = require('../libs/tools-node');

//获取传递给脚本的参数(排除前两个默认参数)

const args = process.argv.slice(2);

let from = path.join(__dirname, '../resources/', args[0]);

let to = path.join(args[1], args[0]);

if (fs.existsSync(from) && fs.existsSync(args[1])) {

  toolsNode.copyFile(from, to);

}

        完成上述代码后,直接以管理员身份运行install.bat便可以自动添加右键菜单了。

        4、结语

        上文示例中我只是把指定文件拷贝到当前目录,更多便捷操作可以自行编写相应脚本实现。本项目的目录结构设计如图所示:

4

        5、附注

        上文中只用到了“文件夹空白处的右击菜单”,其它场景相关的注册表路径如下:

        1)只在文件右键菜单中添加菜单,相关的注册表路径为“HKEY_CLASSES_ROOT\*\shell”;

        2)只在桌面右击菜单中显示,路径为“HKEY_CLASSES_ROOT\DesktopBackground\Shell”;

        3)在桌面和文件夹空白处右击菜单都显示,路径为“HKEY_CLASSES_ROOT\Directory\Background\shell”;

        4)在选中文件夹的右击菜单中显示,路径为“HKEY_CLASSES_ROOT\Directory\shell”;

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 在Windows系统中,只要对着桌面或是文件(夹)单击右键,就会弹出一个快捷菜单,里面有对该文件(夹)的一些常用操...
    readilen阅读 2,455评论 0 1
  • 大家都知道电脑刚刚装完系统,其运行速度十分顺畅,而当运行过几个月之后,在操作时可能会经常出现一些卡顿的情况。其原因...
    huhu咪阅读 69,530评论 0 1
  • 定制功能强大的 Windows Terminal 右键菜单 由于最近我的电脑上的 Windows 10 变的不太稳...
    swordsm阅读 10,396评论 1 9
  • 右键菜单消失一般是因为系统盘更换了,导致注册表没了。我个人是因为安装了双系统,系统1有gitbash,系统2没有,...
    Modulante阅读 4,122评论 0 1
  • 对于喜欢捣鼓自己电脑的人来说,当然是要让自己的电脑和别人的与众不同了,比如,一个独特漂亮的桌面右键菜单就非常的需要...
    f675b1a02698阅读 1,632评论 0 0