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

bin+lib request-window-attention

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

7 releases

0.1.6 Dec 11, 2023
0.1.5 Dec 9, 2023
0.1.4 Aug 27, 2023

#179 in GUI

MIT license

37KB
489 lines

request-window-attention

功能

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

窗体标题名

从这里看,

图片

动机

自从nwjs 40+以后,闪烁电脑桌面任务栏图标的js api接口win.requestAttention(attention)就对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 ModuleC插件是给亲们的专供。
  4. nwjs C addions模块 —— 前端兄弟们注意了:“nwjsnodejsC addions并不通用”。它们的C addions头文件有差异。所以,交叉使用会链接失败的。

额外说明

  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 win-64运行时环境

// 以`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

编译整个工程

cd至工程根目录和执行win32 bat脚本

build4publish.cmd

使用效果

nodejs调用场景

image

nwjs调用场景

image

Dependencies

~0.3–2.2MB
~29K SLoC