KlayGE-004-InputCaps 例子分析

news2024/9/25 15:22:51

InputCaps处理外部输入的事件

该例子主要由两部分内容:

  • 外部输入事件获取

​ 可以处理keyboard、mouse、joystick、touch、sensor的输入事件

  • 显示一个ui图标按钮

Input

定义监听事件类型:

KlayGE::InputActionDefine actions[] =
	{
		InputActionDefine(KeyboardMsg, KS_AnyKey),

		InputActionDefine(MouseMsg, MS_X),
		InputActionDefine(MouseMsg, MS_Y),
		InputActionDefine(MouseMsg, MS_Z),
		InputActionDefine(MouseMsg, MS_AnyButton),

		InputActionDefine(JoystickMsg, JS_LeftThumbX),
		InputActionDefine(JoystickMsg, JS_LeftThumbY),
		InputActionDefine(JoystickMsg, JS_LeftThumbZ),
		InputActionDefine(JoystickMsg, JS_RightThumbX),
		InputActionDefine(JoystickMsg, JS_RightThumbY),
		InputActionDefine(JoystickMsg, JS_RightThumbZ),
		InputActionDefine(JoystickMsg, JS_LeftTrigger),
		InputActionDefine(JoystickMsg, JS_RightTrigger),
		InputActionDefine(JoystickMsg, JS_AnyButton),

		InputActionDefine(TouchMsg, TS_Pan),
		InputActionDefine(TouchMsg, TS_Tap),
		InputActionDefine(TouchMsg, TS_Press),
		InputActionDefine(TouchMsg, TS_PressAndTap),
		InputActionDefine(TouchMsg, TS_Zoom),
		InputActionDefine(TouchMsg, TS_Rotate),
		InputActionDefine(TouchMsg, TS_Flick),
		InputActionDefine(TouchMsg, TS_Wheel),
		InputActionDefine(TouchMsg, TS_AnyTouch),

		InputActionDefine(SensorMsg, SS_AnySensing),

		InputActionDefine(Exit, KS_Escape)
	};
}

在OnCreate中绑定事件监听

KlayGE::InputEngine& inputEngine = KlayGE::Context::Instance().InputFactoryInstance().InputEngineInstance();
	KlayGE::InputActionMap actionMap;
	actionMap.AddActions(actions, actions + std::size(actions));
	action_handler_t input_handler = MakeSharedPtr<input_signal>();
	 input_handler->Connect(
		[this](InputEngine const& sender, InputAction const& action)
		{
			this->InputHandler(sender, action);
		});
	inputEngine.ActionMap(actionMap, input_handler); 

	// 获取joystic_设备
	for (size_t i = 0; i < inputEngine.NumDevices(); ++i)
	{
		auto const& device = inputEngine.Device(i);
		if (device->Type() == InputEngine::IDT_Joystick)
		{
			joystick_ = checked_pointer_cast<InputJoystick>(device);
		}
	}

主要的消息处理函数InputHandler实现:

void InputCaps::InputHandler(KlayGE::InputEngine const& sender, KlayGE::InputAction const& action)
{
	switch (action.first)
	{
		case KeyboardMsg:
		{
			key_str_.clear();
			InputKeyboardActionParamPtr param = checked_pointer_cast<InputKeyboardActionParam>(action.second);
			for (uint32_t i = 0; i < 0xEF; ++i)
			{
				if (param->buttons_state[i])
				{
					key_str_ += key_name[i] + L' ';
				}
			}
		}
		break;

		case MouseMsg:
		{
			InputMouseActionParamPtr param = checked_pointer_cast<InputMouseActionParam>(action.second);
			std::wostringstream stream;
			stream << param->abs_coord.x() << ' ' << param->abs_coord.y() << ' ';
			stream << param->move_vec.x() << ' ' << param->move_vec.y() << ' ' << param->wheel_delta << ' ';
			for (uint32_t i = 0; i < 8; ++i)
			{
				if (param->buttons_state & (1UL << i))
				{
					stream << "button" << i << L' ';
				}
			}
			mouse_str_ = stream.str();
		}
		break;

		case JoystickMsg:
		{
			InputJoystickActionParamPtr param = checked_pointer_cast<InputJoystickActionParam>(action.second);
			std::wostringstream stream;
			stream << param->thumbs[0].x() << ' ' << param->thumbs[0].y() << ' ' << param->thumbs[0].z() << ' ';
			stream << param->thumbs[1].x() << ' ' << param->thumbs[1].y() << ' ' << param->thumbs[1].z() << ' ';
			stream << param->triggers[0] << ' ' << param->triggers[1] << ' ';
			for (uint32_t i = 0; i < 16; ++i)
			{
				if (param->buttons_state & (1UL << i))
				{
					stream << "button" << i << L' ';
				}
			}
			joystick_str_ = stream.str();

			if (joystick_)
			{
				for (uint32_t i = 0; (i < joystick_->NumVibrationMotors()) && (i < 2); ++i)
				{
					joystick_->VibrationMotorSpeed(i, param->triggers[i]);
				}
			}
		}
		break;

		case TouchMsg:
		{
			InputTouchActionParamPtr param = checked_pointer_cast<InputTouchActionParam>(action.second);
			std::wostringstream stream;
			stream << touch_name[param->gesture - 0x300] << ' ';
			if (param->gesture != TS_None)
			{
				stream << "center " << param->center.x() << ' ' << param->center.y() << ' ';
				switch (param->gesture)
				{
				case TS_Pan:
				case TS_Tap:
				case TS_Flick:
					stream << "move " << param->move_vec.x() << ' ' << param->move_vec.y() << ' ';
					break;

				case TS_Zoom:
					stream << "factor " << param->zoom << ' ';
					break;

				case TS_Rotate:
					stream << "angle " << param->rotate_angle << ' ';
					break;

				default:
					break;
				}
			}
			if (param->wheel_delta != 0)
			{
				stream << "Wheel " << param->wheel_delta << ' ';
			}
			for (uint32_t i = 0; i < 16; ++i)
			{
				if (param->touches_down & (1UL << i))
				{
					stream << "Touch" << i << L" Down ";
				}
				if (param->touches_up & (1UL << i))
				{
					stream << "Touch" << i << L" Up ";
				}
			}
			touch_str_ = stream.str();
		}
		break;

		case SensorMsg:
		{
			InputSensorActionParamPtr param = checked_pointer_cast<InputSensorActionParam>(action.second);
			std::wostringstream stream;
			stream << "Lat: " << param->latitude << "  Lng: " << param->longitude;
			stream << " Orientation: " << param->orientation_quat.x() << ' ' << param->orientation_quat.y()
				<< ' ' << param->orientation_quat.z() << ' ' << param->orientation_quat.w();
			sensor_str_ = stream.str();
		}
		break;

	case Exit:
		this->Quit();
		break;
	}
}

UI

ui使用内置的ui解析脚本:uiml格式文件,从外部获取一个特定尺寸的图片作为按钮显示在指定位置

<?xml version='1.0' encoding='utf-8' standalone='no'?>
<ui>
	<dialog id="Logo" caption="Logo" x="-128" y="0" align_x="right" align_y="top" width="128" height="128" show_caption="false" opacity="true" bg_color_a="0">
		<control type="tex_button" id="LogoButton" texture="powered_by_klayge.dds" x="0" y="0" width="128" height="128" is_default="0"/>
	</dialog>
</ui>

在OnCreate函数中加载ui资源

KlayGE::UIManager::Instance().Load(*KlayGE::ResLoader::Instance().Open("InputCaps.uiml"));

在DoUpdateOverlay函数中渲染

	KlayGE::UIManager::Instance().Render();

在Onsize时,更新:

KlayGE::UIManager::Instance().SettleCtrls();

编写本例子遇到的坑

以下类无法找到,link失败:

1>InputCaps.obj : error LNK2019: 无法解析的外部符号 "__declspec(dllimport) class std::unique_ptr<class KlayGE::Signal::Detail::Mutex,struct std::default_delete<class KlayGE::Signal::Detail::Mutex> > __cdecl KlayGE::Signal::Detail::CreateMutexA(void)" (__imp_?CreateMutexA@Detail@Signal@KlayGE@@YA?AV?$unique_ptr@VMutex@Detail@Signal@KlayGE@@U?$default_delete@VMutex@Detail@Signal@KlayGE@@@std@@@std@@XZ),函数 "public: __cdecl KlayGE::Signal::Detail::SignalTemplateBase<void __cdecl(class KlayGE::InputEngine const &,struct std::pair<unsigned short,class std::shared_ptr<struct KlayGE::InputActionParam> > const &),struct KlayGE::Signal::CombinerDefault<void> >::SignalTemplateBase<void __cdecl(class KlayGE::InputEngine const &,struct std::pair<unsigned short,class std::shared_ptr<struct KlayGE::InputActionParam> > const &),struct KlayGE::Signal::CombinerDefault<void> >(void)" (??0?$SignalTemplateBase@$$A6AXAEBVInputEngine@KlayGE@@AEBU?$pair@GV?$shared_ptr@UInputActionParam@KlayGE@@@std@@@std@@@ZU?$CombinerDefault@X@Signal@2@@Detail@Signal@KlayGE@@QEAA@XZ) 中引用了该符号
1>F:\code\project\test\Learning.test\GFX\KlayGE\KlayGELearning\bin\Debug\InputCaps.exe : fatal error LNK1120: 1 个无法解析的外部命令

意思就是找不到这个函数:

__declspec(dllimport) class std::unique_ptr<class KlayGE::Signal::Detail::Mutex,struct std::default_delete<class KlayGE::Signal::Detail::Mutex> > __cdecl KlayGE::Signal::Detail::CreateMutexA(void)

在KlayGE_Core_vc142.dll中,只找到了这个

class std::unique_ptr<class KlayGE::Signal::Detail::Mutex,struct std::default_delete<class KlayGE::Signal::Detail::Mutex> > __cdecl KlayGE::Signal::Detail::CreateMutexW(void)
    

很明显,CreateMutex是windows kernel32中的api函数,但KlayGE却导出了一个同名的函数,导致函数签名错误。KlayGE默认使用unicode字符集,我的项目未设置,使用了多字节,结果就成了CreateMutexA。

最终的解决办法

ADD_DEFINITIONS(-DUNICODE -D_UNICODE)

但是,最好不要让自己的函数名称和常用库的API同名,这里出现冲突也和window的unicode使用宏定义有很大原因,如下:

#ifdef UNICODE
#define CreateMutex  CreateMutexW
#else
#define CreateMutex  CreateMutexA
#endif // !UNICODE

最终效果

请添加图片描述

源码

KlayGE学习主目录

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【opencv】图像数字化——认识OpenCV中的Mat类(4 访问单通道Mat对象中的值)

4 访问单通道Mat对象中的值 4.1使用成员函数at() 格式&#xff1a;m.at(r,c)&#xff0c;访问第r行c列 #include <opencv2/core/core.hpp> #include<iostream> using namespace std; using namespace cv; int main() {//构造矩阵Mat m (Mat_<int>(3,…

浅浅了解一下JWT

JWT 介绍 JWT 是 JSON Web Token 的缩写&#xff0c;JWT 本身没有定义任何技术实现&#xff0c;它只是定义了一种基于 Token 的会话管理的规则&#xff0c;涵盖 Token 需要包含的标准内容和 Token 的生成过程。 首先&#xff0c;俺们先来看看一个 JWT Token 长这样。 eyJhbGci…

burpsuite 插件编写入门

文章目录 一、什么是扩展 / 插件&#xff1f;实现一个简单的 插件/扩展 系统 二、burp 的扩展三、开发步骤总结 一、什么是扩展 / 插件&#xff1f; 关于这个话题&#xff0c;知乎有一个回答题不错&#xff0c;主要也是引用了wikipedia 插件/扩展&#xff0c;是向现有的计算机…

Go的Gin框架拦截器实现登录认证结合JWT实现会话记录

JWT jwt全称 Json web token&#xff0c;是一种认证和信息交流的工具。 授权&#xff1a;这是使用JWT最常见的场景。一旦用户登录&#xff0c;每个后续请求都将包含JWT&#xff0c;允许用户访问该令牌允许的路由、服务和资源。 信息交流&#xff1a;JSON Web令牌是在各方之间…

3.redis-事务

01-Redis事务概述 概述 Redis事务是一个单独的隔离操作&#xff1a;事务中的所有命令都会序列化放到一个队列中按顺序地执行。事务 在执行的过程中&#xff0c;不会被其他客户端发送来的命令请求所打断。 不支持ACID ①atomicity, 原子性, redis事务中的指令执行失败, 不影响后…

记一次 腾讯会议 的意外崩溃分析

一&#xff1a;背景 1. 讲故事 前段时间在用 腾讯会议 直播的时候&#xff0c;居然意外崩溃了&#xff0c;还好不是在训练营上课&#xff0c;不然又得重录了&#xff0c;崩完之后发现 腾讯会议 的 bugreport 组件会自动生成一个 minidump&#xff0c;截图如下&#xff1a; 作…

tcpdump 抓包

一、Tcpdump抓包 抓取端口为2008的数据包 抓包文件内容 抓取到的内容保存在文件中&#xff0c;可以通过wireshark分析 二、tcpdump的一些命令 tcpdump和ethereal可以用来获取和分析网络通讯活动&#xff0c;他们都是使用libpcap库来捕获网络封包的。 ​在混杂模式下他们可以监…

Oracle-主备切换问题(BUG-31747989)

背景: 用户在Oracle Rac 19.6版本通过switchover方式进行主备切换&#xff0c;在备切主完成之后&#xff0c;进行open的过程中&#xff0c;状态长时间无法完成疑似hang住。 问题: ​ Oracle Rac 19.6版本通过switchover方式进行主备切换,切换完成之后进行open&#xf…

100个开源手写人工智能算法(持续更新中)

你是否曾经对开源框架中算法的运行原理感到好奇&#xff1f;又是否曾经想过使用自己写的算法来进行机器学习&#xff1f; 现在&#xff0c;向您推荐一款基于 Python 语言的开源手写机器学习算法项目&#xff01; https://github.com/yuluxingchen/AI/ 这个项目中预计将包含了…

【10 浅学jsp】

浅学 jsp 一、jsp1. jsp介绍2. JSP执行流程3. JSP的本质还是Servlet4. JSP语法4.1 注释4.2 代码块4.3JSP表达式4.4JSP声明 5. JSP指令page 指令include 包含指令包含 其他页面taglib 引入外部标签库 6. JSP细节6.1 pageContext 页面域对象 7. Servlet四大域对象小结8. MVC模型 …

利用MFC实现一个托盘功能

文章目录 1.将主窗口隐藏起来&#xff0c;并移除任务栏图标显示2. 制作系统托盘3. 右键托盘得到信息4. 选择信息栏触发事件5. 添加开机自启动与关闭开机自启动OnSetPowerBoot与OnCancelPowerBoot 右键点击托盘&#xff0c;弹出如下的图标 1.将主窗口隐藏起来&#xff0c;并移除…

Qt开发技术:Q3D图表开发笔记(三):Q3DSurface三维曲面图介绍、Demo以及代码详解

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/130264470 各位读者&#xff0c;知识无穷而人力有穷&#xff0c;要么改需求&#xff0c;要么找专业人士&#xff0c;要么自己研究 红胖子网络科技博…

怎么批量把heic格式转化jpg,3招快速解决

怎么批量把heic格式转化jpg&#xff1f;heic是一种新型的图像文件格式&#xff0c;是苹果独家搞出来的一个图片格式&#xff0c;它小巧玲珑&#xff0c;而且图像质量超好&#xff0c;专门给iOS11系统用户用的。这种格式比老JPEG更厉害&#xff0c;不仅图片质量好&#xff0c;而…

如何减少电脑内存占用或优化内存?

内存(Memory)是计算机一个重要的组成部件&#xff0c;也称为内存储器或主存储器。它可以暂时存放CPU中运算的数据&#xff0c;以及与硬盘等外部存储器交换的数据&#xff0c;是CPU和硬盘之间的桥梁。若电脑内存占用过高&#xff0c;这会影响到电脑运行的速度&#xff0c;那该如…

Redis的哈希槽分区

目录 1. 一致性算法分区的缺点2. 哈希槽分区3. Redis为什么是16384个槽 1. 一致性算法分区的缺点 可以参考一致性哈希算法分区这篇文章 2. 哈希槽分区 Redis集群中内置了16384个哈希槽。redis会根据服务器节点数量大致均等的将哈希槽映射到不同的节点 当写入一条数据&#x…

Java版本的工程项目管理系统源代码之工程项目管理系统面临的挑战

​ ​工程项目管理系统是指从事工程项目管理的企业&#xff08;以下简称工程项目管理企业&#xff09;受业主委托&#xff0c;按照合同约定&#xff0c;代表业主对工程项目的组织实施进行全过程或若干阶段的管理和服务。 ​系统定义 工程项目管理企业不直接与该工程项目的总承包…

UE4/5多人游戏详解(六、多人游戏插件的菜单,创建会话设置和加入)

目录 简单的菜单 创建新的c类&#xff1a; 这里可能出现的报错&#xff1a; 菜单设置&#xff1a; 代码&#xff1a; UI创建&#xff1a; C类中创建按钮的指针&#xff1a; 子系统创建 创建会话函数&#xff1a; 创建会话后前往大厅&#xff1a; 重载函数 变量添加…

Java 线程

线程&#xff1a;线程是进程的组成部分&#xff0c;一个进程可以拥有多个线程&#xff0c;而一个线程必须拥有一个父进程。线程可以拥有自己的堆栈&#xff0c;自己的程序计数器和自己的局部变量&#xff0c;但不能拥有系统资源。它与父进程的其他线程共享该进程的所有资源。 …

PowerShell install Docker+docker-compoer

docker 前言 Docker 是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中&#xff0c;然后发布到任何流行的 Linux或Windows 机器上&#xff0c;也可以实现虚拟化。容器是完全使用沙箱机制&#xff0c;相互之间不会有任何接口。 …

Linux搭建SVN服务器详细教程

前言 本文讲解 Linux 系统下如何搭建 SVN 服务器&#xff0c;详细说明各配置项的功能&#xff0c;最终实现可管控多个项目的复杂配置。 SVN 是 subversion 的缩写&#xff0c;是一个开放源代码的版本控制系统&#xff0c;通过采用分支管理系统的高效管理&#xff0c;实现最终集…