OneNote 365 使用 AHK 实现一键换笔等功能的折腾记录
苏盟盟
编辑于 2024年10月14日 23:05

本文大部分都是折腾记录,如果想直接套用,可以跳转文末


OneNote 2021 LTSC

这是一个美好的版本,一切都是按照规矩办事,折腾起来简单轻松

程序窗口响应 WM_MOUSEWHEEL 和 WM_MOUSEHWHEEL,可以用AHK实现丝滑的滚动(像素级滚动)

程序在数位屏和数位板的使用场景下,笔鼠合一,从不分离。不会出现丢失鼠标焦点导致的无法滚动页面。

程序可以把画笔固定到快速访问栏,直接使用「Alt + 数字键」就可以切换画笔。

一切都是那么的美好,折腾起来简单、优雅、高效。

使用AHK实现像素级滚动

F17:: {

MouseGetPos &v_MouseX, &v_MouseY

v_Position_Param := (v_MouseY * 65536 + v_MouseX)

SendMessage(0x020A, -0x003C0000, v_Position_Param, "OneNote::DocumentCanvas1", "A")

}

首先获取鼠标坐标

然后把 Y 坐标放到 16 进制参数高位,X 坐标放到低位

接着发送 WM_MOUSEWHEEL 消息:

0x020A 代表 WM_MOUSEWHEEL,鼠标垂直滚动

0x020E 代表 WM_MOUSEHWHEEL,鼠标水平滚动

-0x003C0000

负数代表向下/向左滚动,正数代表向上/向右滚动

高四位 003C 代表一次的滚动距离,默认一行是十进制的 120,最低可以设置成 1,3C 代表十进制的 60,意思是一次滚动半行。

低四位 0000 代表滚动时按住的按键,也就是 Shift、Ctrl、Win、Alt,具体请参考微软文档。

发送消息的格式请参考 AutoHotkey 文档

在这个版本中甚至可以实现摇杆效果,下面是我折腾的摇杆移动页面

https://zhuanlan.zhihu.com/p/676055630


OneNote 365 / OneNote 2024

这个版本更新了很多内容,但最主要的是界面更新,这也是噩梦的来源。

在这个版本中,程序不再响应 WM_MOUSEWHEEL 的消息。

程序笔鼠分离,如果直接使用 AHK 的简单快捷键 WheelUp、WheelDown、WheelLeft、WheelRight,则会因为丢失鼠标焦点导致无法滚动。

比如使用数位屏时,笔移动到「笔工具栏」里面时笔鼠合一,笔移出工具栏后两者分离。这就导致每次换笔都会让鼠标焦点停留在「笔工具栏」里面,这时候使用简单快捷键相当于对工具栏使用,故无法让笔记页面滚动。

而且画笔再也无法单独添加到快速访问栏,无法原生实现快捷键换笔。

折腾一:页面滚动

程序不响应之前的消息,会不会是发送错了控件?

遂使用下面的脚本遍历发送

F16::

ShowControl(ThisHotKey) {     MouseGetPos &v_MouseX, &v_MouseY     v_Position_Param := (v_MouseY * 65536 + v_MouseX)     for n, ctrl in WinGetControls("A")     {         try {             SendMessage(……)             ToolTip ctrl             Sleep 1000         }         catch {             ToolTip "No "         }     } }

遗憾发现所有控件都不响应……

那会不会是鼠标滚动的消息发送到了其他窗口的控件?

遂使用 Spy++ 拦截消息,结果发现窗口没变,但使用 SBM_SETSCROLLINFO 消息,消息参数中有一个指向SCROLLINFO结构的指针……

我用ahk的话得先调用dll获取滚动条范围和当前位置,然后调用dll创建结构体……

不够优雅!(实则是不会)

那AHK还有没有其他的交互方法?

嘿,还真有

ControlClick "OneNote::MainWindow1", "A", , "WheelDown", 1

写好尝试,哈哈哈哈,上下滚动问题完美解决!

继续尝试,卧槽!程序只响应上下滚动,不响应左右滚动……

不信邪,用上面的遍历方法再次尝试,发现全部都不响应左右滚动……

那看来只有土办法了

既然无法滚动是因为丢失焦点,那就每次都重置焦点就好了

WinGetPos &x, &y, &w, &h, "A"

MouseMove w / 2, h / 2, 0 Send "{WheelDown}"

获取窗口坐标,每次滚动前强制把鼠标移动到窗口中心。

问题解决……

难道真的没有优雅的办法了吗?

翻阅AHK文档时发现滚动消息还有一个 WM_VSCROLL,是用户点击滚动栏的消息。

于是最终的半优雅方案出炉了:

loop 3

SendMessage 0x0115, 1, 0, "OneNote::DocumentCanvas1", "A"

0x0115是垂直滚动栏消息,0x0114是水平滚动栏消息

不够完全优雅是因为这个方法最低只能一次滚动一整行,而且只能通过循环提高滚动速度,设置成 2(也就是10)就是一次滚动一页了,具体请搜索参考 CSDN 的实例介绍。

折腾二:快捷键切换画笔

最开始是使用 Quicker 按照老思路写了一个小动作

https://getquicker.net/Sharedaction?code=817c9743-88a7-4d2d-8b3c-08daf231a4a0

但这个小动作要速度就不稳定,要稳定就没速度,而且使用数位屏时如果不抬起笔,就会导致OneNote卡顿出错。

然后就吸取教训用了土办法

ToolTip "荧光黄"

SetTimer () => ToolTip(), -1000 MouseClick ……

直接记下画笔在笔工具栏的位置,然后鼠标瞬移点击。

但这个方法局限性很大,且不说不能随便增删画笔,光是不能调整窗口大小就已经注定这个方法不能入选。

灵光一现,优雅随之而来

还记得前面的 ControlClick 吗?其实在研究滚动的时候我就发现「笔工具栏」是一个单独的窗口,并不在主窗口中。

故我们可以直接对「笔工具栏」的窗口进行操作,这样脚本的适应性就更强了一些:

ToolTip "荧光黄"

SetTimer () => ToolTip(), -1000 WinGetPos &x, &y, &w, &h, "笔工具栏" ControlClick "x" w / 16 * 9.5 " y" h / 2, "笔工具栏", , "Left", 1

直接获取工具栏位置坐标,然后通过运算就可以直接点击画笔,连鼠标都不需要瞬移。不仅适应不同窗口大小,更适应上下笔工具栏(左右自己写吧,坐标计算里面xy互换一下)

解释一下最后的坐标运算

16 是我的笔工具栏里面工具的数量,这里替换成你的数量,记得算上撤销、恢复、鼠标、索套、橡皮、手写文字这六个。

9.5 替换成你工具的 序号 - 0.5,比如我的黄色荧光笔在第 10 号,那就填 9.5。某画笔在第 14 号,那就填 13.5


总结

对于 OneNote 365 / 2024 等新界面版本(也包括 非 LTSC 的 2021 版)

滚动页面

;向下滚动

F17:: {     loop 3         SendMessage 0x0115, 1, 0, "OneNote::DocumentCanvas1", "A" }

;向上滚动

F18:: {     loop 3         SendMessage 0x0115, 0, 0, "OneNote::DocumentCanvas1", "A" }

;向左滚动

F13:: {     loop 3         SendMessage 0x0114, 0, 0, "OneNote::DocumentCanvas1", "A" }

;向右滚动

F21:: {     loop 3         SendMessage 0x0114, 1, 0, "OneNote::DocumentCanvas1", "A" }

将键盘旋钮或按键设置成对应快捷键即可

快捷切换画笔

这里使用了一键单击和双击,比如下面的黑色,快捷键按一次是细黑,快速按两次是粗黑

;黑色

F14:: PenBlack(ThisHotkey)  ; 这是一个命名的函数热键. {     static penKey_presses := 0     if penKey_presses > 0 ; SetTimer 已经启动, 所以我们记录键击.     {         penKey_presses += 1         return     }     ; 否则, 这是新开始系列中的首次按下. 把次数设为 1 并启动计时器     penKey_presses := 1     SetTimer KeyFunction, -300 ; 在 400 毫秒内等待更多的键击.负数代表计时器只检测一次     KeyFunction()  ; 这是一个嵌套函数.     {         if penKey_presses = 1 ; 此键按下了一次.         {             ToolTip "细黑"             SetTimer () => ToolTip(), -1000             WinGetPos &x, &y, &w, &h, "笔工具栏"             ControlClick "x" w / 16 * 6.5 " y" h / 2, "笔工具栏", , "Left", 1         }         else if penKey_presses >= 2 ; 此键按下了两次.         {             ToolTip "粗黑"             SetTimer () => ToolTip(), -1000             WinGetPos &x, &y, &w, &h, "笔工具栏"             ControlClick "x" w / 16 * 11.5 " y" h / 2, "笔工具栏", , "Left", 1         }         ; 不论触发了上面的哪个动作, 都对 count 进行重置         ; 为下一个系列的按键做准备:         penKey_presses := 0     } }

具体如何修改画笔切换的脚本,请参见上文。

演示实例

快捷键设置

快捷键键盘:【YOUYOU科技数码产品】淘宝店,【YYR4自定义键盘】

麻烦店主结下钱(doge)

实际演示

除了第一下点黑笔,其他都是快捷键盘一键完成,未动鼠标

AHK文件分享

链接:https://pan.baidu.com/s/1-Q7gdzmZt2Uxwsg8z8Mmlw?pwd=k3iz 

提取码:k3iz 

--来自百度网盘超级会员V9的分享

请不要直接套用,请依据情况修改!

请不要直接套用,请依据情况修改!

请不要直接套用,请依据情况修改!