Nebula2探秘13-输入管理器nInputServer
happykevins文
本节将介绍如何创建和使用nInputServer来检测输入设备的状态及事件。
在创建InputServer之前首先要创建一个Windows窗口,这项工作我们已经在第11节中完成。您可能会注意到本节的代码结构与第11节非常相似,只是多出了创建nInputServer的代码和一个DumpInput函数(用来检测用户输入,并将结果输出到控制台)。
与创建其他Server一样,只需要在KernelServer中将它new出来然后Open一下即可;但是目前的Nebula2版本并没有提供对应的Close函数,所以用户并不需要为销毁InputServer做什么,下面是创建inputserver及建立事件映射的代码:
///创建nInputServer
nInputServer*input=(nInputServer*)ks->New("ndi8server","/sys/servers/input");
input->Open();
///----------------------------------------------------------------------------
///+添加按键映射
///@1.可以在脚本中配置
///@2.可以通过设备的映射名来索取设备并检测设备状态
///@3.可以将脚本函数与设备直接帮定,这样在设备产生事件时会自动调用相关函数
input->BeginMap();
input->Map("keyb0:space.down","reset");
input->Map("relmouse0:btn0.pressed","look");
input->Map("relmouse0:+x","right");
input->EndMap();
///-添加按键映射
///----------------------------------------------------------------------------
nInputServer*input=(nInputServer*)ks->New("ndi8server","/sys/servers/input");
input->Open();
///----------------------------------------------------------------------------
///+添加按键映射
///@1.可以在脚本中配置
///@2.可以通过设备的映射名来索取设备并检测设备状态
///@3.可以将脚本函数与设备直接帮定,这样在设备产生事件时会自动调用相关函数
input->BeginMap();
input->Map("keyb0:space.down","reset");
input->Map("relmouse0:btn0.pressed","look");
input->Map("relmouse0:+x","right");
input->EndMap();
///-添加按键映射
///----------------------------------------------------------------------------
nInputServer提供了一下3种处理设备事件的方式:
1.传统的遍历消息列表并转发或处理的模式。
2.由用户逻辑轮训事件。
3.由InputServer主动出发用户感兴趣的事件。
其中第2、3种的使用方式基本一样,只不过2是用户为事件起一个别名,而3是用户直接把脚本函数注册到事件上而已。
下面的函数DumpInput展示了如何使用第1种方式遍历并处理事件列表:
///----------------------------------------------------------------------------
///+输入测试
///
voidDumpInput()
{
///遍历事件列表,并将事件详细信息分类输出到控制台
for(nInputEvent*inputEvent=nInputServer::Instance()->FirstEvent();
inputEvent!=NULL;
inputEvent=nInputServer::Instance()->NextEvent(inputEvent))
{
///根据事件的DeviceID区分设备
switch(inputEvent->GetDeviceId())
{
caseN_INPUT_MOUSE(0):
printf("MouseEventDetected![BTN:%i]",inputEvent->GetButton());
switch(inputEvent->GetType())
{
caseN_INPUT_MOUSE_MOVE:
printf("[MouseMove]");
break;
caseN_INPUT_BUTTON_DOWN:
printf("[ButtonDown]");
break;
caseN_INPUT_BUTTON_UP:
printf("[ButtonUp]");
break;
}
break;
caseN_INPUT_KEYBOARD(0):
printf("KeyEventDetected![KEY:%i]",inputEvent->GetKey());
switch(inputEvent->GetType())
{
caseN_INPUT_KEY_DOWN:
printf("[KeyDown]");
break;
caseN_INPUT_KEY_UP:
printf("[KeyUp]");
break;
caseN_INPUT_KEY_CHAR:
printf("[CharEvent]");
break;
}
break;
}
printf(" ");
}
}
///
///-输入测试
///----------------------------------------------------------------------------
///+输入测试
///
voidDumpInput()
{
///遍历事件列表,并将事件详细信息分类输出到控制台
for(nInputEvent*inputEvent=nInputServer::Instance()->FirstEvent();
inputEvent!=NULL;
inputEvent=nInputServer::Instance()->NextEvent(inputEvent))
{
///根据事件的DeviceID区分设备
switch(inputEvent->GetDeviceId())
{
caseN_INPUT_MOUSE(0):
printf("MouseEventDetected![BTN:%i]",inputEvent->GetButton());
switch(inputEvent->GetType())
{
caseN_INPUT_MOUSE_MOVE:
printf("[MouseMove]");
break;
caseN_INPUT_BUTTON_DOWN:
printf("[ButtonDown]");
break;
caseN_INPUT_BUTTON_UP:
printf("[ButtonUp]");
break;
}
break;
caseN_INPUT_KEYBOARD(0):
printf("KeyEventDetected![KEY:%i]",inputEvent->GetKey());
switch(inputEvent->GetType())
{
caseN_INPUT_KEY_DOWN:
printf("[KeyDown]");
break;
caseN_INPUT_KEY_UP:
printf("[KeyUp]");
break;
caseN_INPUT_KEY_CHAR:
printf("[CharEvent]");
break;
}
break;
}
printf(" ");
}
}
///
///-输入测试
///----------------------------------------------------------------------------
另外在游戏主循环每一帧结束的位置都要调用nInputServer::FlushEvents()方法以确保事件列表被清除,否则即使已经被处理过的事件也会一直保留在列表中。
下面是完整的程序代码:
/****************************************************************************/
/*Nebula2-Tutorial13*/
/*InputServer*/
/*author:happykevins*/
/****************************************************************************/
/*Nebula2-Tutorial13*/
/*InputServer*/
/*author:happykevins*/
/****************************************************************************/
///----------------------------------------------------------------------------
///+必要头文件
//nebula2includes
#include"kernel/nkernelserver.h"
#include"kernel/nfileserver2.h"
#include"input/ninputserver.h"
#include"gfx2/nd3d9server.h"
//Tutorial工具库:一些通用的宏定义
#include"../NebulaUtils/nutildefs.h"
///-必要头文件
///----------------------------------------------------------------------------
///----------------------------------------------------------------------------
///+链接库
#pragmacomment(lib,"wsock32.lib")
#pragmacomment(lib,"dxguid.lib")
#pragmacomment(lib,"dxerr9.lib")
#pragmacomment(lib,"d3d9.lib")
#pragmacomment(lib,"d3dx9d.lib")
#pragmacomment(lib,"dinput8.lib")
#pragmacomment(lib,"d_nkernel.lib")
#pragmacomment(lib,"d_nnebula.lib")
#pragmacomment(lib,"d_ndirect3d9.lib")
#pragmacomment(lib,"d_ndinput8.lib")
///-链接库
///----------------------------------------------------------------------------
///----------------------------------------------------------------------------
///+声明使用的Nebula2Package&Module
nNebulaUseModule(nresource);
nNebulaUseModule(nresourceserver);
nNebulaUseModule(nfont2);
nNebulaUseModule(nmesh2);
nNebulaUseModule(nmesharray);
nNebulaUseModule(nshader2);
nNebulaUseModule(ntexture2);
nNebulaUseModule(ngfxserver2);
nNebulaUseModule(ninputserver);
nNebulaUsePackage(ndirect3d9);
nNebulaUsePackage(ndinput8);
///-声明使用的Nebula2Package&Module
///----------------------------------------------------------------------------
nKernelServer*ks=NULL;
nGfxServer2*gfx2=NULL;
///----------------------------------------------------------------------------
///+初始化环境,创建需要的Server
///
boolInitApp()
{
///创建KernelServer
ks=n_new(nKernelServer);
///----------------------------------------------------------------------------
///+向KernelServer中添加Package&Module
nNebulaAddModule(nresource);
nNebulaAddModule(nresourceserver);
nNebulaAddModule(nfont2);
nNebulaAddModule(nmesh2);
nNebulaAddModule(nmesharray);
nNebulaAddModule(nshader2);
nNebulaAddModule(ntexture2);
nNebulaAddModule(ngfxserver2);
nNebulaAddModule(ninputserver);
ks->AddPackage(ndirect3d9);
ks->AddPackage(ndinput8);
///+向KernelServer中添加Package&Module
///----------------------------------------------------------------------------
///创建D3D9Server
gfx2=(nGfxServer2*)ks->New("nd3d9server","/sys/servers/gfx");
///创建ResourceServer
nResourceServer*res=(nResourceServer*)ks->New("nresourceserver","/sys/servers/resource");
///获得FileServer设置shaders的路径
nFileServer2*file=(nFileServer2*)ks->Lookup("sys/servers/file2");
///@note:这是启动d3d9server必须的
///因为d3d9server在初始化时会访问"shaders:shape.fx",用它来控制绘制调试图形的渲染状态
file->SetAssign("shaders","bin:../../datafiles/shaders/fixed");
///初始化显示模式
nDisplayMode2mode;
mode.SetXPos(0);
mode.SetYPos(0);
mode.SetWidth(320);
mode.SetHeight(200);
///将显示模式应用到d3d9server
gfx2->SetDisplayMode(mode);
///启动d3d9server
gfx2->OpenDisplay();
///创建nInputServer
nInputServer*input=(nInputServer*)ks->New("ndi8server","/sys/servers/input");
input->Open();
///----------------------------------------------------------------------------
///+添加按键映射
///@1.可以在脚本中配置
///@2.可以通过设备的映射名来索取设备并检测设备状态
///@3.可以将脚本函数与设备直接帮定,这样在设备产生事件时会自动调用相关函数
input->BeginMap();
input->Map("keyb0:space.down","reset");
input->Map("relmouse0:btn0.pressed","look");
input->Map("relmouse0:+x","right");
input->EndMap();
///-添加按键映射
///----------------------------------------------------------------------------
returntrue;
}
///
///+初始化环境,创建需要的Server
///----------------------------------------------------------------------------
///----------------------------------------------------------------------------
///+退出程序,清理资源
///
boolCloseApp()
{
///关闭d3d9server
gfx2->CloseDisplay();
///销毁KernelServer
n_delete(ks);
returntrue;
}
///
///-退出程序,清理资源
///----------------------------------------------------------------------------
///----------------------------------------------------------------------------
///+输入测试
///
voidDumpInput()
{
///遍历事件列表,并将事件详细信息分类输出到控制台
for(nInputEvent*inputEvent=nInputServer::Instance()->FirstEvent();
inputEvent!=NULL;
inputEvent=nInputServer::Instance()->NextEvent(inputEvent))
{
///根据事件的DeviceID区分设备
switch(inputEvent->GetDeviceId())
{
caseN_INPUT_MOUSE(0):
printf("MouseEventDetected![BTN:%i]",inputEvent->GetButton());
switch(inputEvent->GetType())
{
caseN_INPUT_MOUSE_MOVE:
printf("[MouseMove]");
break;
caseN_INPUT_BUTTON_DOWN:
printf("[ButtonDown]");
break;
caseN_INPUT_BUTTON_UP:
printf("[ButtonUp]");
break;
}
break;
caseN_INPUT_KEYBOARD(0):
printf("KeyEventDetected![KEY:%i]",inputEvent->GetKey());
switch(inputEvent->GetType())
{
caseN_INPUT_KEY_DOWN:
printf("[KeyDown]");
break;
caseN_INPUT_KEY_UP:
printf("[KeyUp]");
break;
caseN_INPUT_KEY_CHAR:
printf("[CharEvent]");
break;
}
break;
}
printf(" ");
}
}
///
///-输入测试
///----------------------------------------------------------------------------
///----------------------------------------------------------------------------
///+Application
intmain(intargc,constchar**argv)
{
///初始化Application
if(!InitApp())
{
n_error("程序初始化失败! ");
return0;
}
///这里相当于游戏循环,gfx2->Trigger()将触发win32的消息泵
while(gfx2->Trigger())
{
///一帧开始
gfx2->BeginFrame();
///绘制场景开始
if(gfx2->BeginScene())
{
///设置渲染缓冲区
gfx2->Clear(nGfxServer2::AllBuffers,0.2f,0.2f,0.8f,1.0f,0,0);
///绘制场景结束
gfx2->EndScene();
///显示场景
gfx2->PresentScene();
}
///一帧结束
gfx2->EndFrame();
///检测输入事件,并输出到控制台
DumpInput();
///清空输入事件列表
nInputServer::Instance()->FlushEvents();
n_sleep(0.01f);
}
///释放资源
if(!CloseApp())
{
n_error("释放资源失败! ");
return0;
}
return0;
}
///-Application
///----------------------------------------------------------------------------