当前位置: 首页 > article >正文

如何在WPF中捕获窗口外的事件

捕获窗口消息关于窗口消息可以参考下面的文章https://www.cnblogs.com/zhaotianff/p/11285312.htmlhttps://www.cnblogs.com/zhaotianff/p/11297319.html在WPF中对于操作系统层面的原始输入 / 窗口消息如WM_LBUTTONDOWN、WM_MOUSEMOVE都定义了对应的事件。例如WM_LBUTTONDOWN对应WPFMouseLeftButtonDown事件、WM_MOUSEMOVE对应WPF的MouseMove事件。我们只需要添加事件处理函数就可以对这些Win32消息作出响应如下所示MainWindow.xaml1 Window MouseMoveWindow_MouseMove MouseLeftButtonDownWindow_MouseLeftButtonDown 2 3 /WindowMainWindow.xaml.cs1 private void Window_MouseMove(object sender, MouseEventArgs e) 2 { 3 4 } 5 6 private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) 7 { 8 9 }它的底层逻辑是通过接管所有Win32消息的模式来实现WPF会把这些Win32消息转换为对应的事件。通过添加事件处理函数就可以对这些操作系统层面的Win32消息进行处理。捕获窗口外的消息有时候我们想捕获窗口外的消息应该如何去操作呢。例如鼠标已经移出窗口外了但是我还是想知道鼠标何时按下。我们可以借助Win32 APIRegisterRawInputDevices和GetRawInputData函数来实现。RegisterRawInputDevices函数注册提供原始输入数据的设备。函数声明如下1 BOOL RegisterRawInputDevices( 2 [in] PCRAWINPUTDEVICE pRawInputDevices, 3 [in] UINT uiNumDevices, 4 [in] UINT cbSize 5 );参数pRawInputDevices指向一组RAWINPUTDEVICE结构代表提供原始输入的设备。uiNumDevicespRawInputDevices指向的RAWINPUTDEVICE结构的数量。cbSize指向RAWINPUTDEVICE结构的大小(以字节为单位)返回值如果函数成功则返回值为TRUE否则返回值为FALSE。GetRawInputData可以从指定的设备中获取原始输入GetRawInputData定义如下1 UINT GetRawInputData( 2 [in] HRAWINPUT hRawInput, 3 [in] UINT uiCommand, 4 [out, optional] LPVOID pData, 5 [in, out] PUINT pcbSize, 6 [in] UINT cbSizeHeader 7 );参数hRawInput指向RAWINPUT结构的句柄。它来自于WM_INPUT中的lParam。uiCommand它是命令标志。此参数可以是以下值之一。值含义RID_HEADER0x10000005从 RAWINPUT 结构获取标头信息。RID_INPUT0x10000003从 RAWINPUT 结构获取原始数据。pData指向来自RAWINPUT结构的数据指针这取决于uiCommand的值。如果pData为NULL则在* pcbSize中返回所需的缓冲区大小。cbSizeHeader指定RAWINPUTHEADER结构的大小以字节为单位。返回值如果pData为NULL且函数成功则返回值为零。如果pData不为空且函数成功则返回值为复制到pData中的字节数。如果有错误则返回值为UINT-1。这里还涉及了一个结构体RAWINPUTDEVICE这个结构体定义原始输入设备的信息RAWINPUTDEVICE定义如下1 typedef struct tagRAWINPUTDEVICE { 2 USHORT usUsagePage; //指向原始输入设备的顶级集合使用的页面。 3 USHORT usUsage; //指向原始输入设备的顶级集合的用法。 4 DWORD dwFlags; //指定如何解释由usUsagePage和usUsage提供的信息。它默认值为零默认情况下只要具有窗口焦点操作系统就会将具有顶级集合TLC设备的原始输入发送到已注册的应用程序中。 5 HWND hwndTarget; //指向目标窗口的句柄。如果是NULL则它会遵循键盘焦点。 6 } RAWINPUTDEVICE, *PRAWINPUTDEVICE, *LPRAWINPUTDEVICE;WPF中的实现步骤如下1、引用Win32 api函数及定义相应结构体1 namespace WPFGetRawInputData.Winapi 2 { 3 /// summary 4 /// 原始输入设备类型枚举 5 /// /summary 6 public enum RawInputType : uint 7 { 8 RIM_TYPEKEYBOARD 1, // 键盘 9 RIM_TYPEMOUSE 0 // 鼠标 10 } 11 12 /// summary 13 /// 原始输入设备结构体 14 /// /summary 15 [StructLayout(LayoutKind.Sequential)] 16 public struct RAWINPUTDEVICE 17 { 18 public ushort UsagePage; // 设备使用页键盘/鼠标固定值 19 public ushort Usage; // 设备使用ID键盘/鼠标固定值 20 public uint Flags; // 注册标志 21 public IntPtr WindowHandle; // 接收输入的窗口句柄 22 } 23 24 /// summary 25 /// 原始输入数据头部 26 /// /summary 27 [StructLayout(LayoutKind.Sequential)] 28 public struct RAWINPUTHEADER 29 { 30 public RawInputType Type; 31 public uint Size; 32 public IntPtr Device; 33 public IntPtr WParam; 34 } 35 36 /// summary 37 /// 原始键盘输入结构体 38 /// /summary 39 [StructLayout(LayoutKind.Sequential)] 40 public struct RAWKEYBOARD 41 { 42 public ushort MakeCode; 43 public ushort Flags; 44 public ushort Reserved; 45 public ushort VKey; 46 public uint Message; 47 public uint ExtraInformation; 48 } 49 50 /// summary 51 /// 原始鼠标输入结构体 52 /// /summary 53 [StructLayout(LayoutKind.Explicit,Size 4)] 54 public struct RAWMOUSE 55 { 56 [FieldOffset(0)] 57 public ushort Flags; 58 [FieldOffset(4)] 59 public uint Buttons; 60 [FieldOffset(4)] 61 public DUMMYSTRUCTNAME dUMMYSTRUCTNAME; 62 [FieldOffset(8)] 63 public uint RawButtons; 64 [FieldOffset(12)] 65 public int LastX; 66 [FieldOffset(16)] 67 public int LastY; 68 [FieldOffset(20)] 69 public uint ExtraInformation; 70 } 71 72 public struct DUMMYSTRUCTNAME 73 { 74 public ushort ButtonFlags; 75 public ushort ButtonData; 76 } 77 78 /// summary 79 /// 原始输入数据联合体键盘/鼠标二选一 80 /// /summary 81 [StructLayout(LayoutKind.Explicit)] 82 public struct RAWINPUTDATA 83 { 84 [FieldOffset(0)] 85 public RAWMOUSE Mouse; 86 [FieldOffset(0)] 87 public RAWKEYBOARD Keyboard; 88 } 89 90 /// summary 91 /// 原始输入结构体 92 /// /summary 93 [StructLayout(LayoutKind.Sequential)] 94 public struct RAWINPUT 95 { 96 public RAWINPUTHEADER Header; 97 public RAWINPUTDATA Data; 98 } 99 100 public static class User32 101 { 102 // 注册原始输入设备 103 [DllImport(user32.dll, SetLastError true)] 104 public static extern bool RegisterRawInputDevices( 105 [MarshalAs(UnmanagedType.LPArray, SizeParamIndex 0)] 106 RAWINPUTDEVICE[] pRawInputDevices, 107 uint uiNumDevices, 108 uint cbSize); 109 110 // 获取原始输入数据 111 [DllImport(user32.dll, SetLastError true)] 112 public static extern uint GetRawInputData( 113 IntPtr hRawInput, 114 uint uiCommand, 115 IntPtr pData, 116 ref uint pcbSize, 117 uint cbSizeHeader); 118 119 // 窗口消息常量 120 public const uint WM_INPUT 0x00FF; 121 122 // 键盘使用页/ID 123 public const ushort HID_USAGE_PAGE_GENERIC 0x01; 124 public const ushort HID_USAGE_GENERIC_KEYBOARD 0x06; 125 126 // 鼠标使用页/ID 127 public const ushort HID_USAGE_GENERIC_MOUSE 0x02; 128 129 // 注册标志输入数据发送到窗口消息队列 130 public const uint RIDEV_INPUTSINK 0x00000100; 131 } 132 }注意这里有个非常大的坑在定义RAWMOUSE时要注意联合体以及4字节对齐问题。关于联合体在P/Invoke时的封送可以参考https://www.cnblogs.com/zhaotianff/p/13949849.html说明推荐使用nuget包Cswin32可以参考我前面的文章https://www.cnblogs.com/zhaotianff/p/186579032、注册原始输入设备1 //注册 2 RAWINPUTDEVICE[] devices new RAWINPUTDEVICE[2]; 3 4 // 注册键盘 5 devices[0] new RAWINPUTDEVICE 6 { 7 UsagePage User32.HID_USAGE_PAGE_GENERIC, 8 Usage User32.HID_USAGE_GENERIC_KEYBOARD, 9 Flags User32.RIDEV_INPUTSINK, 10 WindowHandle mainWindowHandle 11 }; 12 13 // 注册鼠标 14 devices[1] new RAWINPUTDEVICE 15 { 16 UsagePage User32.HID_USAGE_PAGE_GENERIC, 17 Usage User32.HID_USAGE_GENERIC_MOUSE, 18 Flags User32.RIDEV_INPUTSINK, 19 WindowHandle mainWindowHandle 20 }; 21 22 // 调用API注册设备 23 var result User32.RegisterRawInputDevices( 24 devices, 25 (uint)devices.Length, 26 (uint)Marshal.SizeOf(typeof(RAWINPUTDEVICE))); 27 28 if (result false) 29 { 30 System.Windows.MessageBox.Show(注册失败); 31 32 //调用GetLastError查看原因 33 } 34 else 35 { 36 DisplayMessage(注册成功); 37 }3、添加Win32消息捕获1 protected override void OnSourceInitialized(EventArgs e) 2 { 3 base.OnSourceInitialized(e); 4 5 mainWindowHandle new WindowInteropHelper(this).Handle; 6 HwndSource.FromHwnd(mainWindowHandle).AddHook(HwndProc); 7 } 8 9 public IntPtr HwndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) 10 { 11 // 处理WM_INPUT消息 12 if (msg User32.WM_INPUT) 13 { 14 //处理原始输入数据 15 ProcessRawInput(lParam); 16 handled true; 17 } 18 return IntPtr.Zero; 19 }4、获取原始数据1 /// summary 2 /// 解析原始输入数据 3 /// /summary 4 /// param namelParam/param 5 private void ProcessRawInput(IntPtr lParam) 6 { 7 uint dataSize 0; 8 // 第一步获取数据大小 9 User32.GetRawInputData( 10 lParam, 11 0x10000003, // RID_INPUT获取原始输入数据 12 IntPtr.Zero, 13 ref dataSize, 14 (uint)Marshal.SizeOf(typeof(RAWINPUTHEADER))); 15 16 if (dataSize 0) return; 17 18 // 第二步分配内存并获取数据 19 IntPtr dataPtr Marshal.AllocHGlobal((int)dataSize); 20 try 21 { 22 uint result User32.GetRawInputData( 23 lParam, 24 0x10000003, 25 dataPtr, 26 ref dataSize, 27 (uint)Marshal.SizeOf(typeof(RAWINPUTHEADER))); 28 29 if (result ! dataSize) return; 30 31 // 第三步解析数据 32 RAWINPUT rawInput Marshal.PtrToStructureRAWINPUT(dataPtr); 33 switch (rawInput.Header.Type) 34 { 35 //键盘 36 case RawInputType.RIM_TYPEKEYBOARD: 37 ProcessKeyboardInput(rawInput.Data.Keyboard); 38 break; 39 //鼠标 40 case RawInputType.RIM_TYPEMOUSE: 41 ProcessMouseInput(rawInput.Data.Mouse); 42 break; 43 } 44 } 45 finally 46 { 47 Marshal.FreeHGlobal(dataPtr); 48 } 49 } 50 51 /// summary 52 /// 处理键盘输入 53 /// /summary 54 /// param namekeyboard/param 55 private void ProcessKeyboardInput(RAWKEYBOARD keyboard) 56 { 57 // 判断按键按下Flags0或释放Flags1 58 bool isKeyDown (keyboard.Flags 0x01) 0; 59 60 // 转换为键盘按键 61 System.Windows.Forms.Keys key (System.Windows.Forms.Keys)keyboard.VKey; 62 63 // 输出调试信息可替换为自定义逻辑 64 string action isKeyDown ? 按下 : 释放; 65 66 DisplayMessage($键盘{key} {action} (扫描码{keyboard.MakeCode})); 67 } 68 69 // 处理鼠标输入 70 private void ProcessMouseInput(RAWMOUSE mouse) 71 { 72 // 鼠标按键状态 73 bool leftButtonDown (mouse.dUMMYSTRUCTNAME.ButtonFlags 0x0001) ! 0; 74 bool leftButtonUp (mouse.dUMMYSTRUCTNAME.ButtonFlags 0x0002) ! 0; 75 bool rightButtonDown (mouse.dUMMYSTRUCTNAME.ButtonFlags 0x0004) ! 0; 76 bool rightButtonUp (mouse.dUMMYSTRUCTNAME.ButtonFlags 0x0008) ! 0; 77 78 // 输出调试信息可替换为自定义逻辑 79 if (leftButtonDown) 80 { 81 DisplayMessage(鼠标左键按下); 82 } 83 84 if (leftButtonUp) 85 { 86 DisplayMessage(鼠标左键释放); 87 } 88 89 if (rightButtonDown) 90 { 91 DisplayMessage(鼠标右键按下); 92 } 93 94 if (rightButtonUp) 95 { 96 DisplayMessage(鼠标右键释放); 97 } 98 }运行效果

相关文章:

如何在WPF中捕获窗口外的事件

捕获窗口消息 关于窗口消息,可以参考下面的文章 https://www.cnblogs.com/zhaotianff/p/11285312.html https://www.cnblogs.com/zhaotianff/p/11297319.html 在WPF中,对于操作系统层面的原始输入 / 窗口消息,如 WM_LBUTTONDOWN、WM_MOUSE…...

在Rocky Linux 10.1上,用kubeadm和containerd 2.2.1从零搭建k8s 1.35.0集群(含Cilium网络配置)

在Rocky Linux 10.1上构建Kubernetes 1.35.0生产级集群:从Containerd配置到Cilium网络实战 当企业级应用向云原生架构迁移时,一个稳定高效的Kubernetes集群成为技术栈的核心枢纽。本文将手把手带你在Rocky Linux 10.1上,使用kubeadm工具链和…...

基于PyTorch 2.8与LSTM的时间序列预测:从算法理论到代码实现

基于PyTorch 2.8与LSTM的时间序列预测:从算法理论到代码实现 1. LSTM时间序列预测效果惊艳展示 长短期记忆网络(LSTM)作为循环神经网络的明星变体,在时间序列预测领域展现出惊人的建模能力。最近我们在PyTorch 2.8环境下进行了一系列实验,结…...

金融行情API对接指南:WebSocket实时订阅外汇/期货/数字货币(附代码示例)

引言在量化交易或金融看盘软件开发中,获取低延迟的实时行情(Tick级数据)是核心环节。传统的HTTP轮询不仅效率低,且容易触发风控。目前主流方案是采用WebSocket协议实现全双工通信,服务端主动推送,极大降低资…...

OpenClaw多模型对比:千问3.5-9B与本地LLaMA混搭方案

OpenClaw多模型对比:千问3.5-9B与本地LLaMA混搭方案 1. 为什么需要多模型混搭 去年冬天的一个深夜,我正用OpenClaw自动处理一批数据清洗任务。当脚本运行到第三个文件时,突然收到短信提醒——当月API调用费用已超预算。查看日志才发现&…...

Vue3前端项目集成指南:调用Qwen3-14B-AWQ模型API实现智能交互

Vue3前端项目集成指南:调用Qwen3-14B-AWQ模型API实现智能交互 1. 前言:为什么要在Vue3中集成大模型API 最近几年,大语言模型在各类应用中的集成变得越来越普遍。作为前端开发者,我们经常需要将这些强大的AI能力整合到自己的项目…...

查看Ubuntu的版本

执行命令 cat /etc/issue 可以查看Ubuntu的版本,例如:...

从训练到推理全链路断电不丢数据,AI研发团队必须掌握的4类异构备份策略,

第一章:AI原生软件研发容灾备份策略设计 2026奇点智能技术大会(https://ml-summit.org) AI原生软件具备模型权重、训练流水线、推理服务、向量数据库与动态提示工程等多模态状态,其容灾备份不能简单套用传统应用的冷备/热备范式,而需构建语义…...

为什么你的Copilot总写错接口参数?根源在缺失“契约优先”的文档生成范式——3步迁移至OpenAPI-First AI协作模式

第一章:AI原生软件研发文档自动化生成方案 2026奇点智能技术大会(https://ml-summit.org) 在AI原生软件开发范式下,代码与文档的边界持续消融。高质量、实时同步的技术文档不再作为后期交付物,而应成为代码演进过程中的自然副产品。本方案聚…...

【技术前沿】大模型驱动的无损数据压缩:突破传统极限的新范式

1. 大模型如何重新定义数据压缩的极限 十年前我第一次接触数据压缩技术时,被那些复杂的数学公式和编码规则搞得晕头转向。当时使用的还是基于香农信息论的传统方法,虽然效果不错,但总觉得遇到了某种看不见的天花板。直到最近看到LMCompress这…...

告别数据混乱:Smartbi智分析中‘找不到数据’和‘应用数据替换’难题一站式解决

告别数据混乱:Smartbi智分析中‘找不到数据’和‘应用数据替换’难题一站式解决 当你第一次将精心整理的数据导入Smartbi智分析平台,却发现数据"消失"在系统中;或是从应用商店安装了漂亮的报表模板,却不知如何将自己的数…...

别再谈OKR了!SITS2026重磅发布《AI原生团队动力学模型》:用3个动态参数替代KPI,实测交付周期压缩41%

第一章:SITS2026演讲:AI原生研发的文化变革 2026奇点智能技术大会(https://ml-summit.org) 在SITS2026主会场,来自全球37家头部科技企业的工程负责人共同指出:AI原生研发已不再仅是工具链升级,而是一场以“人机协同决…...

硬盘分区数据彻底清除工具|支持多算法覆写擦除,确保文件销毁不可恢复

温馨提示:文末有联系方式工具核心功能说明 本工具专为硬盘分区级数据安全销毁设计,可对用户指定的整个磁盘分区执行底层覆盖式擦除,确保所有原始数据(包括已删除文件残留、系统临时文件、隐藏扇区数据等)被完全覆盖并失…...

点云深度学习系列博客(六): 从注意力到三维感知——Point Transformer的架构演进与实战解析

1. 从NLP到三维视觉:注意力机制的跨界之旅 第一次看到Transformer在点云上跑通实验结果时,我正对着屏幕上的3D分割结果发呆——那些精确到毫米级的物体边界,完全颠覆了我对传统点云处理方法的认知。这要归功于注意力机制的神奇迁移能力&#…...

祝贺电影《日掛中天》荣获2026亚洲艺术电影节两项提名

祝贺电影《日掛中天》荣获2026亚洲艺术电影节两项提名 。 祝贺演员辛芷蕾 提名最佳女主角; 祝贺演员冯绍峰 提名最佳男配角。#亚洲艺术电影节#AAFF2026#电影节#辛芷蕾#冯绍峰#电影日掛中天...

SamloaderKotlin 完全指南:跨平台三星固件下载工具的免费终极解决方案

SamloaderKotlin 完全指南:跨平台三星固件下载工具的免费终极解决方案 【免费下载链接】SamloaderKotlin 项目地址: https://gitcode.com/gh_mirrors/sa/SamloaderKotlin 你是否曾经为了下载三星官方固件而四处寻找工具?是否厌倦了那些复杂的命令…...

【仅限首批参会者获取】:2026奇点大会AI原生审查沙箱环境访问权(含金融/医疗双领域合规审查模板)

第一章:2026奇点智能技术大会:AI原生代码审查 2026奇点智能技术大会(https://ml-summit.org) 在2026奇点智能技术大会上,“AI原生代码审查”不再作为辅助工具存在,而是深度嵌入软件开发生命周期的每个环节——从提交前的本地预检…...

一篇SCI论文从投稿到接收的全过程复盘:以Pattern Recognition Letters为例

SCI论文投稿全流程实战指南:以Pattern Recognition Letters为例 第一次投稿SCI期刊的经历,就像在迷雾中摸索前行——每个状态变更都牵动神经,每次邮件提醒都让人心跳加速。作为计算机视觉领域的老牌期刊,Pattern Recognition Lett…...

宝塔面板7.7.0免费解锁专业版监控报表插件(附详细操作步骤)

宝塔面板7.7.0专业版监控报表插件深度解锁指南 在网站运维领域,数据可视化与实时监控已成为高效管理的标配。宝塔面板作为国内最受欢迎的服务器管理工具之一,其专业版的网站监控报表插件能提供精准的访问分析、蜘蛛抓取记录和流量统计功能。对于预算有限…...

Windows大数据开发环境搭建完整指南:使用winutils解决Hadoop兼容性问题

Windows大数据开发环境搭建完整指南:使用winutils解决Hadoop兼容性问题 【免费下载链接】winutils Windows binaries for Hadoop versions (built from the git commit ID used for the ASF relase) 项目地址: https://gitcode.com/gh_mirrors/wi/winutils 对…...

如何关闭Data Guard保护模式_降级为Max Performance以恢复主库读写

必须先确认保护模式和数据库角色,仅MAXIMUM AVAILABILITY或MAXIMUM PROTECTION需降级;执行前须停同步、确保主库OPEN且备库无MRP进程;降级后若仍不可写,需排查STANDBY_FILE_MANAGEMENT、归档目标状态及FORCE LOGGING等隐含依赖。确…...

1163 Dijkstra Sequence

思路&#xff1a;1.先建图2.然后对每一种序列都处理一次&#xff0c;然后看看这个序列到起点的距离是不是逐渐递增的#include<bits/stdc.h> using namespace std; const int N 1e5 10; int h[N],e[2 * N],w[2 * N],ne[2 * N],idx; int xu[N]; bool st[N];; typedef pai…...

7-Zip-JBinding:如何在Java中轻松使用7-Zip的强大压缩功能?

7-Zip-JBinding&#xff1a;如何在Java中轻松使用7-Zip的强大压缩功能&#xff1f; 【免费下载链接】sevenzipjbinding 7-Zip-JBinding 项目地址: https://gitcode.com/gh_mirrors/se/sevenzipjbinding 7-Zip-JBinding是一个免费、跨平台的Java库&#xff0c;它让Java开…...

Python 批量导出数据库数据至 Excel 文件分

简介 langchain专门用于构建LLM大语言模型&#xff0c;其中提供了大量的prompt模板&#xff0c;和组件&#xff0c;通过chain(链)的方式将流程连接起来&#xff0c;操作简单&#xff0c;开发便捷。 环境配置 安装langchain框架 pip install langchain langchain-community 其中…...

OpenCode问题解决:常见安装配置错误与快速排查方法

OpenCode问题解决&#xff1a;常见安装配置错误与快速排查方法 1. 引言 OpenCode作为一款开源的AI编程助手框架&#xff0c;凭借其终端优先、多模型支持和隐私安全等特性&#xff0c;已经成为开发者社区的热门工具。然而在实际安装和使用过程中&#xff0c;不少开发者会遇到各…...

intv_ai_mk11在金融投教中的应用:专业术语解释与投资建议生成案例

intv_ai_mk11在金融投教中的应用&#xff1a;专业术语解释与投资建议生成案例 1. 金融投教场景的痛点分析 在金融投资教育领域&#xff0c;普通投资者常常面临两大核心挑战&#xff1a; 专业术语理解障碍&#xff1a;金融领域充斥着大量专业词汇和复杂概念&#xff0c;如&quo…...

充电桩怎么选?内行人才知道的选购逻辑,一次讲透

很多车主装充电桩时都踩过坑&#xff1a;买了装不了、功率不匹配、信号不好用、安全不放心…… 其实充电桩怎么选有非常清晰的专业逻辑&#xff0c;只要掌握正确思路&#xff0c;就能一步选对&#xff0c;不花冤枉钱。今天从实用角度&#xff0c;把家用充电桩的选购要点讲透彻。…...

别再只盯着代码覆盖率了!VCS功能覆盖率实战:从covergroup定义到交叉覆盖率的避坑指南

别再只盯着代码覆盖率了&#xff01;VCS功能覆盖率实战&#xff1a;从covergroup定义到交叉覆盖率的避坑指南 在芯片验证领域&#xff0c;我们常常陷入一个误区&#xff1a;将代码覆盖率视为验证完备性的唯一标准。然而&#xff0c;一个残酷的事实是——即使代码覆盖率高达100%…...

Visio中高效导出无白边SVG矢量图的完整指南

1. 为什么需要无白边SVG矢量图&#xff1f; 写论文或者做演示文稿时&#xff0c;经常需要在文档中插入各种图表。Visio作为一款专业的绘图工具&#xff0c;能够帮助我们快速创建流程图、架构图等专业图形。但直接将Visio图形导出为SVG格式时&#xff0c;往往会发现图片周围有大…...

UL4200A是美国针对纽扣电池安全标准

UL 4200A-2023 是美国针对含纽扣 / 硬币电池消费品的强制性安全标准&#xff08;16 CFR 1263&#xff09;&#xff0c;核心是防儿童开启 防误吞&#xff0c;2024 年 3 月 19 日起美国市场强制合规。一、标准核心信息全称&#xff1a;ANSI/UL 4200A-2023《含纽扣 / 硬币电池消费…...