KlayGE-004-InputCaps 例子分析

news/2024/11/24 6:10:13/

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.ppmy.cn/news/43567.html

相关文章

windows下nginxHTTP服务器入门教程初级篇

一、介绍Nginx是俄罗斯人编写的十分轻量级的HTTP服务器,Nginx&#xff0c;它的发音为“engine X”&#xff0c; 是一个高性能的HTTP和反向代理服务器&#xff0c;同时也是一个IMAP/POP3/SMTP 代理服务器&#xff0e; 二、Location语法语法&#xff1a;location [|||^~] /uri/ {…

Python 智能项目:1~5

原文&#xff1a;Intelligent Projects Using Python 协议&#xff1a;CC BY-NC-SA 4.0 译者&#xff1a;飞龙 本文来自【ApacheCN 深度学习 译文集】&#xff0c;采用译后编辑&#xff08;MTPE&#xff09;流程来尽可能提升效率。 不要担心自己的形象&#xff0c;只关心如何实…

3.1 多维度随机变量及其分布

思维导图&#xff1a; 学习目标&#xff1a; 要学习二维随机变量及联合分布&#xff0c;我会按照以下步骤进行&#xff1a; 了解基本概念&#xff1a;首先要了解二维随机变量的概念&#xff0c;即同时包含两个随机变量的变量。还要了解二维随机变量的取值范围以及联合概率密…

三种实现模型可视化的方式(print, torchinfo, tensorboard)

记录一下自己使用的三种模型可视化的方式&#xff0c;从简单到难 Print 最简单的是print&#xff0c;就不用多说了。 Torchinfo from torchinfo import summary import torch model (...) summary(model, (1,3,128,128))即可按照像文档路径一样的方式输出结构&#xff0c;…

Nginx网站服务

一款高性能、轻量级Web服务软件 稳定性高系统资源消耗低对HTTP并发连接的处理能力强 单台物理服务器可支持3w-5w个并发请求 Nginx相对于Apache的优点: 轻量级&#xff0c;同样是 web 服务&#xff0c;比Apache 占用更少的内存及资源&#xff0c;高并发&#xff0c;Nginx 处理…

网络安全如何入门?有哪些学习误区?

那年我高三毕业的时候要填志愿前几天 我妈问我想学什么专业。 我说&#xff0c;想学网络设计、或者计算机、网络安全工程师 那时候还比较年轻&#xff0c;也对网络&#xff0c;计算机这方面感兴趣嘛 于是我妈和我爸决定让我学网管。 我说不想做网管&#xff0c;想直接成为一…

Unity云渲染,加移动

上次我们根据官方所推出的教程&#xff0c;完成了云渲染&#xff0c;这次我们加个移动。 原谅我又水一篇文章&#x1f604;&#x1f604;&#x1f604;&#x1f604;&#x1f604;&#x1f604;&#x1f604;&#x1f604;&#x1f604; 云渲染的文章看这里&#xff1a;Unity…

Spring @Scheduled 定时任务 周设置的坑

Scheduled在spring-context包里。 具体位于org.springframework.scheduling.annotation.Scheduled 其cron字段的注释如下&#xff1a; /*** A cron-like expression, extending the usual UN*X definition to include triggers* on the second as well as minute, hour, day o…