HTC Touch Pro 的重力感应功能

080605_htc_touch_pro_05

HTC Touch Pro带的重力感应功能很实用,不过一直在寻思能否找到重力感应器的SDK。在网上搜罗了一大圈,都没结果,看来厂商并不希望公开这样的接口。果不其然,在一个国外的网站上,发现了一篇有趣的文章:

http://scottandmichelle.net/scott/comments.html?entry=784

I spent a couple of sleepless hours last night writing a little Sensor Test for my new HTC Diamond. It’s a small app that lets you move a circle around the screen by tilting the device.

Exciting, eh? Well, the fun is in getting it to work. I asked HTC if they provide a development kit (SDK) for the tilt sensor, and they said “No”, so I had to figure it out myself by digging around (and trying to remember what I knew of ARM assembly). I’m just happy I managed to figure it out, and so others can write interesting games with it, I’m giving the source code to what I figured out away. Have fun, create something with it.

相当搞笑,这位哥们本来打算要求HTC提供这样的SDK开发包,想不到被HTC无情的拒绝了,于是一怒之下,把重力感应相关的库文件给反向工程了,并公开了源码。这下可好了,咱们可以开动大脑,设计更多的和重力相关的有趣的应用了。研究了这位外国哥们的代码,重力感应器相关的API,主要包含在一个叫做”HTCSensorSDK.dll”的动态库里面,该动态库主要输出的两个函数分别是:HTCSensorOpen和HTCSensorClose ,用于打开重力感应器和关闭重力感应器。当重力感应器打开之后,可以对手机当前位置的变化进行监视,其实是通过检测注册表的某个键值实现的,具体的路径在Software\HTC\HTCSensor\GSensor的EventChanged。在打开重力感应器的情况下,当这个键的值发生变化,意味着手机的位置已经发生了变动。手机位置的定义包括六种情况,以地平线位置作为参考,可分为:手机正面(屏幕)向上、手机正面(屏幕)向下、手机正面(屏幕)向左、手机正面(屏幕)向右、手机正面(屏幕)向前、手机正面(屏幕)向后。而这六种位置在注册表键EventChanged中均有不同的值表示。

为了方便应用,我将开启/关闭 重力感应器的代码抽取了出来,做成一个动态连接库,暴露的接口如下:

<span class="lnum">   1:  </span><span class="kwrd">extern</span> <span class="str">"C"</span> __declspec(dllexport) BOOL EnableGSensor();




<span class="lnum">   2:  </span><span class="kwrd">extern</span> <span class="str">"C"</span> __declspec(dllexport) BOOL DisableGSensor();

这样就能方便的开启和关闭重力感应器了。

下面就可以用简单的MFC Dialog程序来测试重力感应了:

定义注册表路径和被监视的键值

<span class="lnum">   1:  </span><span class="preproc">#define</span> SN_GSENSOR_ROOT     HKEY_LOCAL_MACHINE




<span class="lnum">   2:  </span><span class="preproc">#define</span> SN_GSENSOR_PATH     _T(<span class="str">"Software\\HTC\\HTCSensor\\GSensor"</span>)




<span class="lnum">   3:  </span><span class="preproc">#define</span> SN_GSENSOR_VALUE    _T(<span class="str">"EventChanged"</span>)

定义注册表值掩码,以及6个不同位置的值

<span class="lnum">   1:  </span><span class="preproc">#define</span> SN_GSENSOR_BITMASK  0xF










<span class="lnum">   2:  </span> 










<span class="lnum">   3:  </span><span class="preproc">#define</span> orIENTATION_LANDSCAPE           0










<span class="lnum">   4:  </span><span class="preproc">#define</span> orIENTATION_REVERSE_LANDSCAPE   1










<span class="lnum">   5:  </span><span class="preproc">#define</span> orIENTATION_PORTRAIT            2










<span class="lnum">   6:  </span><span class="preproc">#define</span> orIENTATION_UPSIDE_DOWN         3










<span class="lnum">   7:  </span><span class="preproc">#define</span> orIENTATION_FACE_DOWN           4










<span class="lnum">   8:  </span><span class="preproc">#define</span> orIENTATION_FACE_UP             5

定义注册表值变化的Windows Message类型

<span class="lnum">   1:  </span><span class="preproc">#define</span> WM_EVENTCHANGED (WM_USER + 1)

在消息映射宏中,定义响应自定义消息WM_EVENTCHANGED的处理函数

<span class="lnum">   1:  </span>ON_MESSAGE(WM_EVENTCHANGED,OnEventChanged)

这样,我们就可以在Dialog程序的初始化函数里面实现相应的代码:

<span class="lnum">   1:  </span>BOOL CTestDlg::OnInitDialog()










<span class="lnum">   2:  </span>{










<span class="lnum">   3:  </span>    CDialog::OnInitDialog();










<span class="lnum">   4:  </span> 










<span class="lnum">   5:  </span>    <span class="rem">// Set the icon for this dialog.  The framework does this automatically</span>










<span class="lnum">   6:  </span>    <span class="rem">//  when the application's main window is not a dialog</span>










<span class="lnum">   7:  </span>    SetIcon(m_hIcon, TRUE);            <span class="rem">// Set big icon</span>










<span class="lnum">   8:  </span>    SetIcon(m_hIcon, FALSE);        <span class="rem">// Set small icon</span>










<span class="lnum">   9:  </span> 










<span class="lnum">  10:  </span>    <span class="rem">// TODO: Add extra initialization here</span>










<span class="lnum">  11:  </span>    g_hSensorEvent = NULL;










<span class="lnum">  12:  </span>    










<span class="lnum">  13:  </span>    RegistryNotifyWindow(










<span class="lnum">  14:  </span>        SN_GSENSOR_ROOT, 










<span class="lnum">  15:  </span>        SN_GSENSOR_PATH, 










<span class="lnum">  16:  </span>        SN_GSENSOR_VALUE,










<span class="lnum">  17:  </span>        GetSafeHwnd(), 










<span class="lnum">  18:  </span>        WM_EVENTCHANGED, 










<span class="lnum">  19:  </span>        SN_GSENSOR, 










<span class="lnum">  20:  </span>        NULL, 










<span class="lnum">  21:  </span>        &g;_hSensorEvent);










<span class="lnum">  22:  </span> 










<span class="lnum">  23:  </span>        gSensorWrapper.EnableGSensor();










<span class="lnum">  24:  </span> 










<span class="lnum">  25:  </span>    <span class="kwrd">return</span> TRUE;  <span class="rem">// return TRUE  unless you set the focus to a control</span>










<span class="lnum">  26:  </span>}

RegistryNotifyWindow函数,通过监视注册表的指定路径下,指定键值的变化,向我们的窗口发送WM_EVENTCHANGED消息,而我们在消息映射宏中所定义的OnEventChanged函数,就用来响应和处理这样的自定义消息。

最后,在我们的OnEventChanged函数中,就可以获得当前手机的位置了:

<span class="lnum">   1:  </span>afx_msg LRESULT CHangupPhoneDlg::OnEventChanged(WPARAM wParam, LPARAM lParam)




<span class="lnum">   2:  </span>{




<span class="lnum">   3:  </span>        nLastEvent = (wParam & SN_GSENSOR_BITMASK);




<span class="lnum">   4:  </span>        




<span class="lnum">   5:  </span>        <span class="kwrd">switch</span> (nLastEvent)




<span class="lnum">   6:  </span>        {




<span class="lnum">   7:  </span>        <span class="kwrd">case</span> orIENTATION_LANDSCAPE:




<span class="lnum">   8:  </span>            szMessage = _T(<span class="str">"Last Event: 正面向右"</span>);




<span class="lnum">   9:  </span>            <span class="kwrd">break</span>;




<span class="lnum">  10:  </span>        <span class="kwrd">case</span> orIENTATION_REVERSE_LANDSCAPE:




<span class="lnum">  11:  </span>            szMessage = _T(<span class="str">"Last Event: 正面向左"</span>);




<span class="lnum">  12:  </span>            <span class="kwrd">break</span>;




<span class="lnum">  13:  </span>        <span class="kwrd">case</span> orIENTATION_PORTRAIT:




<span class="lnum">  14:  </span>            szMessage = _T(<span class="str">"Last Event: 正面向后"</span>);




<span class="lnum">  15:  </span>            <span class="kwrd">break</span>;




<span class="lnum">  16:  </span>        <span class="kwrd">case</span> orIENTATION_UPSIDE_DOWN:




<span class="lnum">  17:  </span>            szMessage = _T(<span class="str">"Last Event: 正面向前"</span>);




<span class="lnum">  18:  </span>            <span class="kwrd">break</span>;




<span class="lnum">  19:  </span>        <span class="kwrd">case</span> orIENTATION_FACE_DOWN:




<span class="lnum">  20:  </span>            szMessage = _T(<span class="str">"Last Event: 正面向下"</span>);




<span class="lnum">  21:  </span>            <span class="kwrd">break</span>;




<span class="lnum">  22:  </span>        <span class="kwrd">case</span> orIENTATION_FACE_UP:




<span class="lnum">  23:  </span>            szMessage = _T(<span class="str">"Last Event: 正面向上"</span>);




<span class="lnum">  24:  </span>            <span class="kwrd">break</span>;




<span class="lnum">  25:  </span>        <span class="kwrd">default</span>:




<span class="lnum">  26:  </span>            szMessage = _T(<span class="str">"Last Event: Unknown"</span>);




<span class="lnum">  27:  </span>            <span class="kwrd">break</span>;




<span class="lnum">  28:  </span>        }




<span class="lnum">  29:  </span> 




<span class="lnum">  30:  </span>        <span class="kwrd">this</span>->GetDlgItem(IDC_DISPLAY)->SetWindowTextW(szMessage);




<span class="lnum">  31:  </span> 




<span class="lnum">  32:  </span> 




<span class="lnum">  33:  </span>    <span class="kwrd">return</span> 0L;




<span class="lnum">  34:  </span>}

启动测试程序,翻转手机到不同的位置,就能在Dialog框中,实时看到当前手机位置状态,Cool!

测试程序比较简单,就不放上来了,把封装的重力感应器的动态库放上来,供有兴趣的同学下载。

可以进行测试的手机型号:多普达(Dopod) Touch Diamond、多普达(Dopod) Touch Pro 或者 HTC Touch Diamond 和 HTC Touch Pro.

我的开发测试环境: Windows Vista 64bit, Visual Studio 2008 SP1, Windows Mobile 6.0 Professional SDK.

点击下载此文件

支持原创技术分享,据说打赏我的人,都找到了女朋友!