#nodejs #windows #nw # #系统,根据窗体“标题名”闪烁窗体的任务栏图标来请求用户注意

bin+lib request-window-attention

在 Windows 系统,根据窗体“标题名”闪烁窗体的任务栏图标来请求用户注意

7 个版本

0.1.6 2023年12月11日
0.1.5 2023年12月9日
0.1.4 2023年8月27日

GUI 中排名 212

MIT 许可证

37KB
489

request-window-attention

功能

根据 Windows 操作系统的 Native GUI 窗体标题名,寻址窗体句柄,闪烁窗体在桌面任务栏内的占位图标,以吸引计算机操作员的注意力。

窗体标题名

从这里看,

图片

动机

自从 nwjs 40+ 以后,闪烁电脑桌面任务栏图标的 js api 接口 win.requestAttention() 对 Windows 操作系统丧失了兼容性(和错误 Unchecked runtime.lastError: The context from which the function was called did not have an associated app window.)。哎!应用面最广的操作系统又一次不受待见可苦了我们这些做应用程序开发的码农了。

缺陷工单如预期般被提交。甲方爸爸可不管这是操作系统被嫌弃、容器自身缺陷、还是应用程序被躺枪的问题。反正,缺陷你得给我解决了。所以,只能想点儿“歪招”,绕过 nwjs 容器,从更底层的 WIN32 COM ABI 闪烁应用程序的桌面任务栏图标。

用法

任务栏图标的闪烁功能被以三种形式封装,以适应不同的调用端场景:

  1. dll动态链接库 —— 允许调用端以增量更新的方式集成此功能模块
  2. rlib / lib静态链接库 —— 只为方便的懒人使用。只要项目工期预算充足,花半天时间重编译都不叫事。正好,还有光鲜堂皇的理由摸鱼。
  3. nodejs C addons模块 —— 前端开发者看这里。伪装成 Commonjs Module 的 C 插件是给你们的专属。
  4. nwjs C addons模块 —— 前端兄弟们注意了:“nwjs 与 nodejs 的 C addons 并不通用”。它们的 C addons 头文件有差异。所以,交叉使用会链接失败的。

额外说明

  1. 虽然工程编译也会输出机器码的【可执行文件】,但它仅用于测试,不接受任何命令行参数。
  2. 【链接库】输出格式将附加 C++ 头文件,以描述链接库接口格式。
    1. 文件位置 target-win-x64<profile>\request-window-attention.h
  3. nodejs C addons输出格式也将附加 .d.ts 类型说明文件,以向调用端提供基本的代码提示和参数作用解释。
    1. 文件位置 dist\nodejs\v16.4.0\win-x64\request-window-attention.d.ts

由于文件篇幅不长,我将 C++ 头文件和 .d.ts 类型说明文件的内容直接贴在这里

#include <cstdarg>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <ostream>
#include <new>
struct GitEdition {
  const char *branch;
  const char *tag;
  const char *latest_commit_id;
  const char *pkg_name;
  const char *pkg_version;
  const char *bundle_time;
};
extern "C" {
    /// 结束闪烁,但窗口任务栏还会继续高亮,直到窗体获得用户操作的焦点
    /// @param winTitle 被闪烁窗体“标题名”
    void stopFlashByTitleC(const char *win_title);
    /// /// 开始闪烁。
    /// (1)在 stopFlashJs() 接口被调用后,闪烁会停止但高亮会继续。
    /// (2)在窗体获得了焦点之后,闪烁与高亮才都会结束。
    /// @param winTitle 被闪烁窗体“标题名”
    /// @param blinkCount  闪烁次数。超过闪烁次数之后,任务栏会一直保持高亮状态。
    /// @param blinkRate   相邻闪烁的间隔时间(单位:毫秒)
    void startFlashByTitleC(const char *win_title,
                            unsigned int count,
                            unsigned int blink_rate);
    /// 结束闪烁,但窗口任务栏还会继续高亮,直到窗体获得用户操作的焦点
    /// @param process_id 被闪烁窗体的进程ID或nwjs的进程PID
    void stopFlashByPpidC(unsigned int process_id) ;
    /// /// 开始闪烁。
    /// (1)在 stopFlashJs() 接口被调用后,闪烁会停止但高亮会继续。
    /// (2)在窗体获得了焦点之后,闪烁与高亮才都会结束。
    /// @param process_id  被闪烁窗体的进程ID或nwjs的进程PID
    /// @param blinkCount  闪烁次数。超过闪烁次数之后,任务栏会一直保持高亮状态。
    /// @param blinkRate   相邻闪烁的间隔时间(单位:毫秒)
    void startFlashByPpidC(unsigned int process_id,
                           unsigned int count,
                           unsigned int blink_rate);
    /// 模块版本信息
    GitEdition *getEditionC();
} // extern "C"

/**
 * 模块版本信息
 */
export interface GitEdition {
    branch: string;
    tag: string;
    latestCommitId: string;
    pkgName: string;
    pkgVersion: string;
    bundleDateTime: string;
}
/**
 * 请对【日志·输出】回调函数,务必做好`try-catch`异常捕获,因为来自`js`端的
 * 异常目前会级联地引发`c-addon`程序崩溃。结果不可控!
 */
export interface Logger {
    (text: string): void;
}
/**
 * 挂载全域【日志·输出】回调函数。通过指定回调函数,可将此`c-addon`内部日志
 * 中继转发到`js`应用层。
 *
 * 重复挂载新的【日志·输出】回调函数不需要手工卸载之前的【日志】回调函数,因为
 * 被采用的`RAII`设计模式可确保`napi_function`是析构的。
 * @param log
 */
export function setLogger(log: Logger);
/**
 * 手工卸载当前的【日志·输出】回调函数,以防止内存泄漏。
 *
 * 注:重复卸载操作不会导致程序崩溃。
 */
export function unsetLogger();
/**
 * 开始闪烁。
 * 1. 在 stopFlashJs() 接口被调用后,闪烁会停止但高亮会继续。
 * 2. 在窗体获得了焦点之后,闪烁与高亮才都会结束。
 * @param winTitle 被闪烁窗体“标题名”
 * @param blinkCount  闪烁次数。超过闪烁次数之后,任务栏会一直保持高亮状态。
 * @param blinkRate   相邻闪烁的间隔时间(单位:毫秒)
 */
export function startFlashByTitleJs(winTitle: string, blinkCount: number, blinkRate: number);
/**
 * 结束闪烁,但窗口任务栏还会继续高亮,直到窗体获得用户操作的焦点
 * @param winTitle 被闪烁窗体“标题名”
 * @param log     【可选】日志回调函数
 */
export function stopFlashByTitleJs(winTitle: string);
/**
 * 开始闪烁。
 * 1. 在 stopFlashJs() 接口被调用后,闪烁会停止但高亮会继续。
 * 2. 在窗体获得了焦点之后,闪烁与高亮才都会结束。
 * @param ppid  被闪烁窗体的进程ID或nwjs的进程PID
 * @param blinkCount  闪烁次数。超过闪烁次数之后,任务栏会一直保持高亮状态。
 * @param blinkRate   相邻闪烁的间隔时间(单位:毫秒)
 */
export function startFlashByPpidJs(ppid: number, blinkCount: number, blinkRate: number);
/**
 * 结束闪烁,但窗口任务栏还会继续高亮,直到窗体获得用户操作的焦点
 * @param ppid  被闪烁窗体的进程ID或nwjs的进程PID
 */
export function stopFlashByPpidJs(ppid: number);
/**
 * 模块版本信息
 * @returns GitEdition
 */
export function getEdition(): GitEdition;

nwjs 调用端示例

在 nodejs 10/12/16 win64 运行时环境下自测

// 以`Commonjs Module`的形式,导入 C addons 插件
const attention = require('./dist/nodejs/win-x64/request-window-attention.node');
(async () => {
    // 读取与输出`c-addon`的版本信息
    console.info('版本信息', attention.getEdition());
    // 挂载全局【日志·输出】回调函数钩子。
    attention.setLogger(text => {
        console.log('[attention]', text);
    });
    // 根据【主窗体】名,通知操作系统,开始闪烁桌面任务栏图标
    attention.startFlashByTitleJs('有道云笔记', 10, 500);
    await new Promise(resolve => setTimeout(resolve, 500));
    // 根据【主窗体】名,通知操作系统,停止闪烁桌面任务栏图标。
    // 但,任务栏图标还会继续高亮。
    attention.stopFlashByTitleJs('有道云笔记');
    // 分隔线
    await new Promise(resolve => setTimeout(resolve, 500));
    // 根据【主窗体】进程ID,通知操作系统,开始闪烁桌面任务栏图标
    attention.startFlashByPpidJs(18928, 10, 500);
    await new Promise(resolve => setTimeout(resolve, 1000));
    // 根据【主窗体】进程ID,通知操作系统,停止闪烁桌面任务栏图标。
    // 但,任务栏图标还会继续高亮。
    attention.stopFlashByPpidJs(18928);
    // 卸载全局【日志·输出】回调函数钩子,以避免内存泄漏。
    attention.unsetLogger();
})();
function logger(text){
    console.log('[attention]', text);
}

另外,您也可以在工程根目录下运行命令 node test.js 来执行测试。

安装

npm i request-window-attention

导入已安装的 request-window-attention 模块

  • nodejs x64环境中,使用require('request-window-attention')
  • nodejs x86/ia32环境中,使用require('request-window-attention/dist/nodejs/win-ia32/request-window-attention.node')
  • nwjs x64容器内,使用require('request-window-attention/dist/nw/win-x64/request-window-attention.node')
  • nwjs ia32容器内,使用require('request-window-attention/dist/nw/win-ia32/request-window-attention.node')

(预编译包)兼容性说明

链接库

要求Windows 7+

nodejs C addons模块

要求nodejs 10+,因为从10版本往上nodejs运行时才开始全面地支持N-APIC插件扩展接口。

尽管预编译的.node文件是基于nodejs v16.4.0编译的,但理论上任何遵循N-API标准接口的C插件对nodejs版本应该是无感的。

node-webkit(nw) C addons模块

要求nwjs 0.49.2+

技术细节

没有太多技术,整个工程只是一个WIN32 COM ABI的“胶水”代码层。

nodejs / nw交叉编译输出目录

image

链接库编译输出目录

image

编译整个工程

切换到工程根目录并执行win32 bat脚本

build4publish.cmd

使用效果

nodejs调用场景

image

nwjs调用场景

image

依赖项

~0.3–2.2MB
~29K SLoC