Qt第三方库QHotKey设置小键盘数字快捷键

一、看了一圈没有找到可以设置小键盘的情况。

这两天在研究快捷键的使用。发现qt的里的快捷键不是全局的。找了两个第三方快捷键QHotKey,还有一个QxtGlobalShortcut。但是这两个都不能设置小键盘的数字。

比如QKeySequenceEdit (Ctrl+1) 这个快捷键,这个1只会响应主键盘的数字1对应的键盘码是0x31.而小键盘的1键盘码是0x61.

所以就算是设置成功了,再按快捷键的时候也是响应的主键盘的,按小键盘没用。

二、准备工作

0、键盘码对应关系

 Qt中的Qt::key0-9 对应的是0x30-0x39

  windows 下 主键盘上的数字0-9对应的是0x30-0x39 刚好和qt的一致。

     windwos下 小键盘上的数字0-9对应的键盘码是0x60-0x69.

看了Qt的Qt::key 枚举发现并没有 VK_NUMPAD0=0x60的枚举值。

仅有的0x60也是对应 Qt::Key_QuoteLeft并不是对应的小键盘的VK_NUMPAD0, 0x61-0x69是缺失状态。

还有一点需要注意的是,在看qt枚举的时候,发现在键盘(NumLock)不选中的情况下的小键盘0-9的码值。

对应的QKeySequenceEdit表现为:

alt+1->

alt+9->         

其他的可以自己试试。但是这个不是我想要的。

三、初步思考

是不是qt没有枚举全windows键盘码,导致第三方库都办法响应小键盘的0-9?如果我把小键盘码搞进去是不是就能响应了?

接下来就查看源码。

四、源码解析,初步分析

在注册快捷键的时候用的是这两个函数 setShortcut 以及他的重载。


//! A class to define global, systemwide Hotkeys
class QHOTKEY_SHARED_EXPORT QHotkey : public QObject
{
	Q_OBJECT
	friend class QHotkeyPrivate;

	//! Specifies whether this hotkey is currently registered or not
	Q_PROPERTY(bool registered READ isRegistered WRITE setRegistered NOTIFY registeredChanged)
	//! Holds the shortcut this hotkey will be triggered on
	Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut RESET resetShortcut)

public:
	//! Defines shortcut with native keycodes
	class QHOTKEY_SHARED_EXPORT NativeShortcut {
	public:
		//! The native keycode
		quint32 key;
		//! The native modifiers
		quint32 modifier;

		//! Creates an invalid native shortcut
		NativeShortcut();
		//! Creates a valid native shortcut, with the given key and modifiers
		NativeShortcut(quint32 key, quint32 modifier = 0);

		//! Checks, whether this shortcut is valid or not
		bool isValid() const;

		//! Equality operator
		bool operator ==(const NativeShortcut &other) const;
		//! Inequality operator
		bool operator !=(const NativeShortcut &other) const;

	private:
		bool valid;
	};

	//! Constructor
	explicit QHotkey(QObject *parent = Q_NULLPTR);
	//! Constructs a hotkey with a shortcut and optionally registers it
	explicit QHotkey(const QKeySequence &shortcut, bool autoRegister = false, QObject *parent = Q_NULLPTR);
	//! Constructs a hotkey with a key and modifiers and optionally registers it
	explicit QHotkey(Qt::Key keyCode, Qt::KeyboardModifiers modifiers, bool autoRegister = false, QObject *parent = Q_NULLPTR);
	//! Constructs a hotkey from a native shortcut and optionally registers it
	explicit QHotkey(const NativeShortcut &shortcut, bool autoRegister = false, QObject *parent = Q_NULLPTR);
	//! Destructor
	~QHotkey();

	//! READ-Accessor for QHotkey::registered
	bool isRegistered() const;
	//! READ-Accessor for QHotkey::shortcut - the key and modifiers as a QKeySequence
	QKeySequence shortcut() const;
	//! READ-Accessor for QHotkey::shortcut - the key only
	Qt::Key keyCode() const;
	//! READ-Accessor for QHotkey::shortcut - the modifiers only
	Qt::KeyboardModifiers modifiers() const;

	//! Get the current native shortcut
	NativeShortcut currentNativeShortcut() const;

public slots:
	//! WRITE-Accessor for QHotkey::registered
	bool setRegistered(bool registered);

	//! WRITE-Accessor for QHotkey::shortcut
	bool setShortcut(const QKeySequence &shortcut, bool autoRegister = false);

	//! WRITE-Accessor for QHotkey::shortcut
	bool setShortcut(Qt::Key keyCode, Qt::KeyboardModifiers modifiers, bool autoRegister = false);
	//! RESET-Accessor for QHotkey::shortcut
	bool resetShortcut();

	//! Set this hotkey to a native shortcut
	bool setNativeShortcut(NativeShortcut nativeShortcut, bool autoRegister = false);

signals:
	//! Will be emitted if the shortcut is pressed
	void activated(QPrivateSignal);

	//! NOTIFY-Accessor for QHotkey::registered
	void registeredChanged(bool registered);

private:
	Qt::Key _keyCode;
	Qt::KeyboardModifiers _modifiers;

	NativeShortcut _nativeShortcut;
	bool _registered;
};

挑一个看看源码

bool QHotkey::setShortcut(const QKeySequence &shortcut, bool autoRegister)
{
	if(shortcut.isEmpty()) {
		return resetShortcut();
	} else if(shortcut.count() > 1) {
		qCWarning(logQHotkey, "Keysequences with multiple shortcuts are not allowed! "
							  "Only the first shortcut will be used!");
	}

	return setShortcut(Qt::Key(shortcut[0] & ~Qt::KeyboardModifierMask),
			Qt::KeyboardModifiers(shortcut[0] & Qt::KeyboardModifierMask),
			autoRegister);
}

发现也是解析出来key(0-9 a-z) 和 组合键。(ctrl shift alt ...)

然后调用了 setShortCut.


bool QHotkey::setShortcut(Qt::Key keyCode, Qt::KeyboardModifiers modifiers, bool autoRegister)
{
	if(_registered) {
		if(autoRegister) {
			if(!QHotkeyPrivate::instance()->removeShortcut(this))
				return false;
		} else
			return false;
	}

	if(keyCode == Qt::Key_unknown) {
		_keyCode = Qt::Key_unknown;
		_modifiers = Qt::NoModifier;
		_nativeShortcut = NativeShortcut();
		return true;
	}

	_keyCode = keyCode;
	_modifiers = modifiers;
	_nativeShortcut = QHotkeyPrivate::instance()->nativeShortcut(keyCode, modifiers);
	if(_nativeShortcut.isValid()) {
		if(autoRegister)
			return QHotkeyPrivate::instance()->addShortcut(this);
		else
			return true;
	} else {
		qCWarning(logQHotkey) << "Unable to map shortcut to native keys. Key:" << keyCode << "Modifiers:" << modifiers;
		_keyCode = Qt::Key_unknown;
		_modifiers = Qt::NoModifier;
		_nativeShortcut = NativeShortcut();
		return false;
	}
}

看了这两个函数就知道了。问题肯定是出在这里了。解析完是Qt::key 然而Qt::key中并没有小键盘的数字。所以?? 那是肯定不会响应的。

那么问题来了,怎么解决。

我的方法简单粗暴。直接把VK_NUMPAD0-9 强制转换成 Qt::key 但是这种会覆盖那个Qt::key中的0x60(Qt::Key_QuoteLeft) ,但是不管了。先搞再说。

于是我测试了一下:

QKeySequence keySequenceFromString = (QKeySequence(Qt::CTRL , Qt::ALT , VK_NUMPAD1));

m_pMousePointGetHot->setShortcutEx(keySequenceFromString, true))

发现不行会出错。

Keysequences with multiple shortcuts are not allowed! "  "Only the first shortcut will be used!

这两句话就是在解析的时候 之后调用setShortcut的时候 函数头出现的。意思很清晰。

到这里。麻了。难道思路有问题。

于是我看到了第二个setShortcut函数。

bool QHotkey::setShortcut(Qt::Key keyCode, Qt::KeyboardModifiers modifiers, bool autoRegister)

上面的图片有内容。

我想着抛弃Qt::key中的0-9数字,把他转换成VK_NUMPAD0-9。搞个转换函数强制塞进去试试


Qt::Key TransNumToPadNum(const Qt::Key k)
{
	switch (k)
	{
	case Qt::Key_0:
		return Qt::Key(VK_NUMPAD0);
		break;
	case Qt::Key_1:
		return Qt::Key(VK_NUMPAD1);
		break;
	case Qt::Key_2:
		return Qt::Key(VK_NUMPAD2);
		break;
	case Qt::Key_3:
		return Qt::Key(VK_NUMPAD3);
		break;
	case Qt::Key_4:
		return Qt::Key(VK_NUMPAD4);
		break;
	case Qt::Key_5:
		return Qt::Key(VK_NUMPAD5);
		break;
	case Qt::Key_6:
		return Qt::Key(VK_NUMPAD6);
		break;
	case Qt::Key_7:
		return Qt::Key(VK_NUMPAD7);
		break;
	case Qt::Key_8:
		return Qt::Key(VK_NUMPAD8);
		break;
	case Qt::Key_9:
		return Qt::Key(VK_NUMPAD9);
		break;
	default:
		return k;
		break;
	}
}

雅黑,可以了,发现不报错了。

但是快捷键按键没有效果....

于是就跟进去看看里面的源码:可以跟着看。

QHotkey::setShortcut  ->

QHotkeyPrivate::instance()->nativeShortcut  ->  这里判断了按键是否有效。

QHotkeyPrivate::nativeShortcutInvoked->

QHotkey::NativeShortcut QHotkeyPrivate::nativeShortcutInvoked(Qt::Key keycode, Qt::KeyboardModifiers modifiers)
{
	bool ok1, ok2 = false;
	auto k = nativeKeycode(keycode, ok1);
	auto m = nativeModifiers(modifiers, ok2);
	if(ok1 && ok2)
		return {k, m};
	else
		return {};
}

到这里已经大致知道什么原因了。

在转换的时候 ok1是false的。就看看nativeKeycode:

这里就是根源了。他把qt的key对应起来windows的键盘码做了一个转换。问题找到了。

就是在这里地方。还是因为qt里的qt::key 没有小键盘。所以根本不可能映射。

于是我修改了一下这个对应关系,新增VK_NUMPAD0-9。

quint32 QHotkeyPrivateWin::nativeKeycode(Qt::Key keycode, bool &ok)
{
	ok = true;
	switch (keycode)
	{
	case VK_NUMPAD0:
	case VK_NUMPAD1:
	case VK_NUMPAD2:
	case VK_NUMPAD3:
	case VK_NUMPAD4:
	case VK_NUMPAD5:
	case VK_NUMPAD6:
	case VK_NUMPAD7:
	case VK_NUMPAD8:
	case VK_NUMPAD9:
		return keycode;
	default:
		break;
	}
	if(keycode <= 0xFFFF) {//Try to obtain the key from it's "character"
		const SHORT vKey = VkKeyScanW(keycode);
		if(vKey > -1)
			return LOBYTE(vKey);
	}

	//find key from switch/case --> Only finds a very small subset of keys
	switch (keycode)
    ...

}

这样外面的key如果是小键盘的话就不会出错了。

再次测试。响应了,他可以了。完美,牛逼!!!

QKeySequence keySequenceFromString = "Ctrl+Alt+1";

Qt::Key keyCode = Qt::Key(k[0] & ~Qt::KeyboardModifierMask);
		Qt::KeyboardModifiers modifiers = Qt::KeyboardModifiers(k[0] & Qt::KeyboardModifierMask);
keyCode = ui.keySequenceEdit->TransNumToPadNum(keyCode);
QKeySequence ktmpex(keyCode, modifiers);
ktmp = ktmpex;
// 报错Keysequences with multiple shortcuts are not allowed! "
// "Only the first shortcut will be used!
//m_pMousePointGetHot->setShortcutWithPad(ktmp, true);
m_pMousePointGetHot->setShortcut(keyCode, modifiers, true);

// 这里要把组合键和单键摘出来,调用另外一个setShortCut

五、封装以及整理。

 在qhotkey.h中我新建一个注册快捷键的函数(其实搞了两个,但是用的是红色圈住的)

实现如下:这里有个弊端就是小键盘的字符必须

/*
	包含小键盘数字, 但是小键盘数字仅作为最后一个快捷按键使用
*/
bool QHotkey::setShortcutWithPad(const QKeySequence& shortcut, bool autoRegister) {
	if (shortcut.isEmpty()) {
		return resetShortcut();
	}
	else if (shortcut.count() > 1) {
		qCWarning(logQHotkey, "Keysequences with multiple shortcuts are not allowed! "
			"Only the first shortcut will be used!");
	}
	 // 小键盘数字
	quint32 keyCode = shortcut[shortcut.count() -1];
	
	return setShortcut((Qt::Key)keyCode,
		Qt::KeyboardModifiers(shortcut[0] & Qt::KeyboardModifierMask),
		autoRegister);
}

直接用这个bool setShortcut(const QKeySequence &shortcut, bool autoRegister = false);这个函数也行,但是传递keycode的时候要传递 小键盘的0-9 VK_NUMPAD0-9。

由于Qt里是用的QKeySequenceEdit,但是他无法键入小键盘的keycode.所以重新简单集成封装一下:

CustomKeySeqEdit.h

#pragma once

#include <QKeySequenceEdit>
#include <QKeyEvent>

class CustomKeySeqEdit  : public QKeySequenceEdit
{
	Q_OBJECT

public:
	CustomKeySeqEdit(QWidget *parent);
	~CustomKeySeqEdit();
	void setKeyNumPadNumber(bool b);
	bool isKeyNumPadNumber();
	Qt::Key TransNumToPadNum(const Qt::Key k);
private:
	void keyPressEvent(QKeyEvent* e) override;
	//virtual bool nativeEvent(const QByteArray& eventType, void* message, long* result);
private:
	bool m_isNumPad = false;
};

CustomKeySeqEdit.cpp

#include "CustomKeySeqEdit.h"
#include <windows.h>
#include <windowsx.h>  //提供消息关键字的识别


CustomKeySeqEdit::CustomKeySeqEdit(QWidget *parent)
	: QKeySequenceEdit(parent)
{
	//this->installEventFilter(this);
}

CustomKeySeqEdit::~CustomKeySeqEdit()
{}

void CustomKeySeqEdit::setKeyNumPadNumber(bool b)
{
	m_isNumPad = b;
}

bool CustomKeySeqEdit::isKeyNumPadNumber()
{
	return m_isNumPad;
}

// 这个很垃圾,不应该放在这里。但是为了测试快些就随便放了
Qt::Key CustomKeySeqEdit::TransNumToPadNum(const Qt::Key k)
{
	switch (k)
	{
	case Qt::Key_0:
		return Qt::Key(VK_NUMPAD0);
		break;
	case Qt::Key_1:
		return Qt::Key(VK_NUMPAD1);
		break;
	case Qt::Key_2:
		return Qt::Key(VK_NUMPAD2);
		break;
	case Qt::Key_3:
		return Qt::Key(VK_NUMPAD3);
		break;
	case Qt::Key_4:
		return Qt::Key(VK_NUMPAD4);
		break;
	case Qt::Key_5:
		return Qt::Key(VK_NUMPAD5);
		break;
	case Qt::Key_6:
		return Qt::Key(VK_NUMPAD6);
		break;
	case Qt::Key_7:
		return Qt::Key(VK_NUMPAD7);
		break;
	case Qt::Key_8:
		return Qt::Key(VK_NUMPAD8);
		break;
	case Qt::Key_9:
		return Qt::Key(VK_NUMPAD9);
		break;
	default:
		return k;
		break;
	}
}

#include <QDebug>
void CustomKeySeqEdit::keyPressEvent(QKeyEvent* e)
{
	if (e->key() < Qt::Key_0 || e->key() > Qt::Key_9) {
		return QKeySequenceEdit::keyPressEvent(e);
	}
	// 我们只关心小键盘
	int keyCode = e->nativeVirtualKey();
	m_isNumPad = false;
	qDebug() <<"key:" << e->key()   << keyCode;
	if (keyCode >= 0x60 && keyCode <= 0x69) {
		m_isNumPad = true;
	}
	QKeySequenceEdit::keyPressEvent(e);

}
/*  这个不行,不会响应。
bool CustomKeySeqEdit::nativeEvent(const QByteArray& eventType, void* message, long* result)
{
	MSG* msg = static_cast<MSG*>(message);
	switch (msg->message)
	{
	case WM_KEYDOWN:
	{
		m_isNumPad = false;
		int value = msg->wParam;
		if (value >= VK_NUMPAD0 && value <= VK_NUMPAD9) {
			m_isNumPad = true;
		}
	}
		break;
	default:
		break;
	}

	return false;
}
*/

使用:

至此,算是愉快结束了。 可以用QKeySequenceEdit使用小键盘的数字了。

可以正常拾取坐标啦!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/717017.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

springboot小型超市商品展销系统-计算机毕业设计源码01635

摘 要 科技进步的飞速发展引起人们日常生活的巨大变化&#xff0c;电子信息技术的飞速发展使得电子信息技术的各个领域的应用水平得到普及和应用。信息时代的到来已成为不可阻挡的时尚潮流&#xff0c;人类发展的历史正进入一个新时代。在现实运用中&#xff0c;应用软件的工作…

onnx基本概念

onnx基本概念 参考 文章目录 onnx基本概念Input, Output, Node, Initializer, AttributesSerialization with protobuf元数据List of available operators and domains支持的类型Opset版本Subgraphs, tests and loopsExtensibilityFunctionsShape (and Type) Inferencetools O…

Fiddler抓包工具介绍

下载 下载:Web Debugging Proxy and Troubleshooting Tools|Fiddler 进去要填一个表 汉化版 百度网盘 请输入提取码 提取码&#xff1a;xq9t 下载过附件之后分别把两个文件 点开fiddler就ok了 配置https fiddler要想抓到https包(解密的),点击tools->options勾选三个对…

数据结构之“双向链表”

前言 前面我们介绍了单向链表&#xff0c;我们这里的双向链表是为了弥补单向链表只能从头节点开始单向遍历&#xff0c;插入和删除节点时需要更多的操作&#xff0c;因为无法直接访问前一个节点。 目录 前言 一、双向链表的结构 二、实现双向链表 2.1符号定义 2.2节点创…

半监督学习

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 介绍一、Self Training自训练1、介绍2、代码示例3、参数解释 二、Label Propagation&#xff08;标签传播&#xff09;1、介绍2、代码示例3、参数解释 三、Label Spread…

物联网工程的未来发展趋势及影响

物联网工程是在互联网基础上的一种新兴技术&#xff0c;其核心思想是通过网络连接不同物体&#xff0c;实现智能化的交流与互动。在未来&#xff0c;物联网工程将继续向更多领域发展&#xff0c;如智能家居、智能城市、智能交通等。首先&#xff0c;物联网工程在智能家居领域的…

华为中小企业组网

一、组网图 说明&#xff1a;接入交换机ACC1&#xff08;S2750&#xff09;&#xff0c;核心/汇聚交换机CORE&#xff08; S5700 &#xff09;和出口路由器Router&#xff08;AR系列路由器&#xff09;为例。 核心交换机配置VRRP保证网络可靠性&#xff0c;配置负载分担有效利…

Windows 10永久关闭“系统准备工具 3.14“禁止开机自启

文章目录 一、问题描述二、解决方法总结 一、问题描述 每次开机都会显示如下图所示的 系统准备工具 3.14 二、解决方法 按win R键打开运行窗口 → 输入cmd → 点击 确定 如图所示输入下面如图所示代码 → 按 回车 → 输入 Y → 按 回车 XCOPY C:\windows\System32\svchost.e…

劝你现在别秦L,不然得后悔死

文 | AUTO芯球 作者 | 雷慢 这真得听劝&#xff0c; 现在别急着买车&#xff0c;不然过不了两个月你得后悔死&#xff0c; 你现在看到秦L将B级车价格打下来了&#xff0c;就急着买车&#xff0c; 几个月后比亚迪还有更大的王炸&#xff0c;价格战还得更残酷&#xff01; …

C#开发-集合使用和技巧(五)集合中的转换方法

在C#中&#xff0c;Select, ToList, 和 ToArray 都是用于集合转换的方法&#xff0c;它们各自有不同的用途和适用场景。 测试数据 /// <summary>/// 设备类/// </summary>class Device{/// <summary>/// Id/// </summary>public int Id { get; set; }…

学周刊杂志学周刊杂志社学周刊编辑部2024年第19期目录

热点关注 “一带一路”背景下高校创新创业教育的机遇、挑战与发展对策 温玲子; 1-4 高职院校创新创业教育模式的实践研究 杜卉; 5-8 谈高职医学院校计算机教学中学生创新创业能力培养 王磊; 9-12 教改新论《学周刊》投稿&#xff1a;cn7kantougao163.com 大数据…

实战 | 基于YOLOv10的车辆追踪与测速实战【附源码+步骤详解】

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

音频文件下载后,如何轻松转换格式?

在我们日常的数字生活中&#xff0c;下载各种音频文件是司空见惯的事情。然而&#xff0c;有时候我们可能需要将这些音频文件转换为不同的格式&#xff0c;以适应不同的设备或编辑需求。无论您是希望将下载的音频文件转换为通用的MP3格式&#xff0c;还是需要将其转换为高保真的…

eNSP学习——OSPF在帧中继网络中的配置

目录 主要命令 原理概述 实验目的 实验场景 实验拓扑 实验编址 实验步骤 1、基本配置 2、在帧中继上搭建OSPF网络 主要命令 //检查帧中继的虚电路状态 display fr pvc-info//检查帧中继的映射表 display fr map-info//手工指定OSPF邻居,采用单播方式发送报文 [R1]os…

Scala入门【安装与使用、变量与数据类型、运算符、函数、条件判断、循环、字符串、面向对象、数组】

视频地址:Scala大专/本科专用课程_哔哩哔哩_bilibili 目录 P01【01Scala安装与使用】16:15 P02【02变量与数据类型】17:14 P03【03运算符】12:41 P04【04函数】16:40 P05【05条件判断】10:56 P06【06循环】13:33 P07【07字符串】19:09 P08【08面向对象】17:27 P09【0…

栅格数据实现最优参数地理探测器(OPGD)详细教程!(上)

数据准备 要探寻一堆因素对因变量的影响,首先你要确定要用哪些自变量来影响哪个因变量 想好了之后 你需要到相应的网站去下载你的研究区的自变量和因变量数据的栅格数据(可以是离散的,也可以是连续的) 后续操作是到Arcgis里对你的数据处理一下 由于不是教程的重点,这里就…

电脑微信聊天记录监控要怎么做?找谁找?

电脑微信聊天记录的监控通常涉及到使用特定的监控软件&#xff0c;这些软件设计用于企业管理和网络监控&#xff0c;以确保工作场所的通信安全和提高工作效率。以下是进行电脑微信聊天记录监控的一般步骤和建议&#xff1a; 如何进行监控&#xff1a; 1.明确目的与合法性&…

滑动窗口(LeeCode209题,以JS为例)

什么是滑动窗口&#xff1f; 滑动窗口是算法中一种非常有用的技术&#xff0c;特别是在处理数据序列或数组时。它的核心思想是维护一个固定大小的窗口&#xff0c;这个窗口在数据序列上滑动&#xff0c;以便于在窗口内的元素上进行操作或计算。滑动窗口技术通常用于解决与数据…

2024年粤港澳青少年信息学创新大赛图形化编程小低组真题试卷

2024年粤港澳青少年信息学创新大赛图形化编程小低组真题试卷 题目总数&#xff1a;16 总分数&#xff1a;100 单选题 第 1 题 单选题 默认小猫角色&#xff0c;以下哪个Scratch程序可以在点击绿旗后让小猫说”你好!"一共10秒? A. B. C. D. 第 2 题 单选题 …

如何根据使用场景选购3D扫描仪?

三维扫描建模是指通过专业的三维扫描仪对产品进行三维数据的采集&#xff0c;快速获取物体精确的3D数据&#xff0c;实现1:1复刻原物体&#xff0c;扫描后所得的数字化3D模型以obj、fbx、glb、gltf等格式保存。 积木易搭自主研发多款三维扫描设备&#xff0c;拥有多项国家专利&…