有时候需要在转换页面的时候用振动提示用户以获得更好的用户体验,这就需要提到在WM设备上实现振动的问题了。这里提供2中方式,但都是换汤不换药。一种是P/Invoke调用系统API来实现,另一种是通过使用OpenNETCF来实现(我认为也是通过调用系统API来实现,难道他有设备供应商更底层的接口,呵呵,玩笑!)。
当然,在实现的时候需要考虑是在PPC还是SP平台上,不同的平台有不同实现,这也是由2种平台的差异性造成的。
好,进入正题!
方法一: 通过P/Inovke调用系统API
g 1. 在PPC上
PPC
// for PPC
public class Vibrate_PPC
{
// 可用的Led号
private static uint m_availableNo = 0xFFFFFFFF;
// NLED_COUNT_INFO结构对应ID
private const int NLED_COUNT_INFO_ID = 0;
// NLED_SETTINGS_INFO结构对应ID
private const int NLED_SETTINGS_INFO_ID = 2;
private Vibrate_PPC()
{
}
// 查找可用的Led,并振动
public static bool Play()
{
bool bRes = false;
NLED_SETTINGS_INFO nsi = new NLED_SETTINGS_INFO();
nsi.OffOnBlink = (int)LedState.On;
if (m_availableNo == 0xFFFFFFFF)
{
// 获取设备数
NLED_COUNT_INFO pOutput = new NLED_COUNT_INFO();
if (!NLedGetDeviceCount(NLED_COUNT_INFO_ID, ref pOutput))
{
// 初始化失败,跑出异常
return false;
}
// 设备上一般有至少2个Led, 0为扬声器Led, 而振动器为最后一个
m_availableNo = pOutput.cLeds - 1;
nsi.LedNum = m_availableNo;
bRes = NLedSetDevice(NLED_SETTINGS_INFO_ID, ref nsi);
}
else
{
// 如果之前已经得到正确的Led号,那么就直接调用了
nsi.LedNum = m_availableNo;
bRes = NLedSetDevice(NLED_SETTINGS_INFO_ID, ref nsi);
}
if (bRes)
return true;
else
return false;
}
public static bool Stop()
{
if (m_availableNo != 0xFFFFFFFF)
{
NLED_SETTINGS_INFO nsi = new NLED_SETTINGS_INFO();
nsi.LedNum = m_availableNo;
nsi.OffOnBlink = (int)LedState.Off;
if (NLedSetDevice(NLED_SETTINGS_INFO_ID, ref nsi))
return true;
else
return false;
}
return false;
}
P/Invoke#region P/Invoke
[DllImport("coredll.dll", EntryPoint = "NLedGetDeviceInfo")]
private static extern bool NLedGetDeviceCount(short nID, ref NLED_COUNT_INFO pOutput);
[DllImport("coredll.dll", EntryPoint = "NLedGetDeviceInfo")]
private static extern bool NLedGetDeviceSupports(short nID, ref NLED_SUPPORTS_INFO pOutput);
[DllImport("coredll.dll")]
private static extern bool NLedSetDevice(short nID, ref NLED_SETTINGS_INFO pOutput);
public enum LedState
{
Off,
On,
Blink
}
[StructLayout(LayoutKind.Sequential)]
private struct NLED_COUNT_INFO
{
public uint cLeds;
}
[StructLayout(LayoutKind.Sequential)]
private struct NLED_SUPPORTS_INFO
{
public uint LedNum;
public int lCycleAdjust;
public bool fAdjustTotalCycleTime;
public bool fAdjustOnTime;
public bool fAdjustOffTime;
public bool fMetaCycleOn;
public bool fMetaCycleOff;
}
[StructLayout(LayoutKind.Sequential)]
private struct NLED_SETTINGS_INFO
{
public uint LedNum;
public int OffOnBlink;
public int TotalCycleTime;
public int OnTime;
public int OffTime;
public int MetaCycleOn;
public int MetaCycleOff;
}
#endregion
}
g 2. 在Smartphone上
Smartphone
// for SmartPhone
public sealed class Vibrate_SP
{
private static bool m_bSupport = false;
private Vibrate_SP()
{
}
public static bool Play()
{
int iRes = -1;
if (m_bSupport)
{
iRes = VibratePlay(0, IntPtr.Zero, uint.MaxValue, uint.MaxValue);
}
else
{
int caps = -1;
caps = VibrateGetDeviceCaps(VibrationCapabilities.Amplitude);
// 0: 不支持振动
// 1: 说明设备具有振动功能,并且可以使用,但是仅仅具有打开关闭震动,无法对振动进行调节
// 2-7: 说明了设备提供了不同等级的振动功能,数字越大提供的调节能力越强
if (caps <= 0)
return false;
else
{
m_bSupport = true;
iRes = VibratePlay(0, IntPtr.Zero, uint.MaxValue, uint.MaxValue);
}
}
if (iRes == 0)
return true;
else
return false;
}
public static bool Stop()
{
if (VibrateStop() != 0)
{
return false;
}
return true;
}
[DllImport("aygshell.dll", SetLastError = true)]
private static extern int VibrateGetDeviceCaps(VibrationCapabilities caps);
[DllImport("aygshell.dll", EntryPoint = "Vibrate", SetLastError = true)]
private static extern int VibratePlay(int cvn, IntPtr rgvn, uint fRepeat, uint dwTimeout);
[DllImport("aygshell.dll", SetLastError = true)]
private static extern int VibrateStop();
public enum VibrationCapabilities
{
Amplitude,
Frequency,
last
}
}
g 3. 提供统一接口,不考虑平台
因为要考虑不同平台,因此要添加Microsoft.WindowsCE.Forms组件并引用 “using Microsoft.WindowsCE.Forms”。然后就可以通过SystemSettings和WinCEPlatform来判断所属平台了。
统一接口
public class Vibrate
{
/**//// <summary>
/// 实现震动
/// </summary>
/// <param name="microSeconds">震动毫秒数</param>
public static void Play(int microSeconds)
{
if (SystemSettings.Platform == WinCEPlatform.PocketPC)
{
Vibrate_PPC.Play();
System.Threading.Thread.Sleep(microSeconds);
Vibrate_PPC.Stop();
}
else if (SystemSettings.Platform == WinCEPlatform.Smartphone)
{
Vibrate_SP.Play();
System.Threading.Thread.Sleep(microSeconds);
Vibrate_SP.Stop();
}
}
}
方法二: 通过使用OpenNETCF来实现
http://www.opennetcf.com/ 为我们提供非常好用的组件,这其中有许多是免费使用的,当然如果您需要更精彩的内容,支付点美金也是值得的。下面的介绍的方法就是使用该OpenNETCF来实现。
在使用前您需要去
http://www.opennetcf.com/Default.aspx?tabid=65下载该文件(免费版即可),下载后安装就可以使用里面的组件了。安装后您会发现有3个文件夹,一个是组件库文件夹,一个是发布文件夹,一个是Sample。
然后需要包含Bin文件夹中的两个组件OpenNETCF.WindowsCE.dll和OpenNETCF.WindowsMobile.dll。前者是提供了在PPC中调用振动的接口,后者提供了在Smartphone中调用振动的接口。
OpenNETCF
private void Btn_OpenNETCF_Click(object sender, EventArgs e)
{
// PPC
if (SystemSettings.Platform == WinCEPlatform.PocketPC)
{
OpenNETCF.WindowsCE.Notification.Led led = new OpenNETCF.WindowsCE.Notification.Led();
led.SetLedStatus(1, OpenNETCF.WindowsCE.Notification.Led.LedState.On);
System.Threading.Thread.Sleep(2000);
led.SetLedStatus(1, OpenNETCF.WindowsCE.Notification.Led.LedState.Off);
}
// SP
else if (SystemSettings.Platform == WinCEPlatform.Smartphone)
{
OpenNETCF.WindowsMobile.Vibrate.Play();
System.Threading.Thread.Sleep(2000);
OpenNETCF.WindowsMobile.Vibrate.Stop();
}
}
好了,上面的实现相信已经很清楚了,如果还不清楚,可以下载下面的例子试试,调试一下就明白了!
--------------------
例子下载:
Vibrate.rar
修正:
---------------------------------------------------------------------------------------------------------------------------------
2009 - 08 - 24
在“老羽”的指点下,修正了原来的在PPC上调用NLedSetDevice的“short nID”参数问题。
之前的“设备上一般有至少2个Led, 0为扬声器Led, 而振动器为最后一个”的观点在HDC的设备上是
可行的,但并不保证所以的WM设备是可行的,比如”老羽"的夏新N810。
通过P/Inovke调用系统API
在PPC上
修正通过P/Invoke方式
/// <summary>
/// for PPC
/// </summary>
public class Vibrate_PPC
{
// 可用的Led号
private static uint m_availableNo = 0xFFFFFFFF;
// NLED_COUNT_INFO 结构对应ID
private const int NLED_COUNT_INFO_ID = 0;
// NLED_SUPPORTS_INFO 结构对应ID
private const int NLED_SUPPORTS_INFO_ID = 1;
// NLED_SETTINGS_INFO 结构对应ID
private const int NLED_SETTINGS_INFO_ID = 2;
private Vibrate_PPC()
{
}
// 查找可用的Led,并振动
public static bool Play()
{
bool bRes = false;
NLED_SETTINGS_INFO nsi = new NLED_SETTINGS_INFO();
nsi.OffOnBlink = (int)LedState.On;
if (m_availableNo == 0xFFFFFFFF)
{
// 获取设备数
NLED_COUNT_INFO pOutput = new NLED_COUNT_INFO();
if (!NLedGetDeviceCount(NLED_COUNT_INFO_ID, ref pOutput))
{
// 初始化失败,跑出异常
return false;
}
uint ledCount = pOutput.cLeds;
for (uint i = 0; i < ledCount; ++i)
{
NLED_SUPPORTS_INFO nspti = new NLED_SUPPORTS_INFO();
nspti.LedNum = i;
// 首先获取设备支持
if (NLedGetDeviceSupports(NLED_SUPPORTS_INFO_ID, ref nspti))
{
// 该条件是判断振动器是否可用的条件
if (nspti.lCycleAdjust == -1)
{
m_availableNo = i;
nsi.LedNum = m_availableNo;
bRes = NLedSetDevice(NLED_SETTINGS_INFO_ID, ref nsi);
}
}
}
}
else
{
// 如果之前已经得到正确的Led号,那么就直接调用了
nsi.LedNum = m_availableNo;
bRes = NLedSetDevice(NLED_SETTINGS_INFO_ID, ref nsi);
}
if (bRes)
{
return true;
}
else
{
return false;
}
}
public static bool Stop()
{
if (m_availableNo != 0xFFFFFFFF)
{
NLED_SETTINGS_INFO nsi = new NLED_SETTINGS_INFO();
nsi.LedNum = m_availableNo;
nsi.OffOnBlink = (int)LedState.Off;
if (NLedSetDevice(1, ref nsi))
return true;
else
return false;
}
return false;
}
#region P/Invoke
[DllImport("coredll.dll", EntryPoint = "NLedGetDeviceInfo")]
private static extern bool NLedGetDeviceCount(short nID, ref NLED_COUNT_INFO pOutput);
[DllImport("coredll.dll", EntryPoint = "NLedGetDeviceInfo")]
private static extern bool NLedGetDeviceSupports(short nID, ref NLED_SUPPORTS_INFO pOutput);
[DllImport("coredll.dll")]
private static extern bool NLedSetDevice(short nID, ref NLED_SETTINGS_INFO pOutput);
public enum LedState
{
Off,
On,
Blink
}
[StructLayout(LayoutKind.Sequential)]
private struct NLED_COUNT_INFO
{
public uint cLeds;
}
[StructLayout(LayoutKind.Sequential)]
private struct NLED_SUPPORTS_INFO
{
public uint LedNum;
public int lCycleAdjust;
public bool fAdjustTotalCycleTime;
public bool fAdjustOnTime;
public bool fAdjustOffTime;
public bool fMetaCycleOn;
public bool fMetaCycleOff;
}
[StructLayout(LayoutKind.Sequential)]
private struct NLED_SETTINGS_INFO
{
public uint LedNum;
public int OffOnBlink;
public int TotalCycleTime;
public int OnTime;
public int OffTime;
public int MetaCycleOn;
public int MetaCycleOff;
}
#endregion
--------------------
例子下载:
---------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------
李森 – listen
E-mail: lisencool@gmail.com
|
声明:
这里集中了在WinCE和Windows Mobile开发中的一些基本常识。我很乐意和大家分享,也希望大家提出意见,并给我投稿,我会第一时间替您发表并署上您的大名!
Announce:
Here collects general knowledge on WinCE and Windows mobile. I 'm very glad to share them with all friends, and also hope you can share your problems and opinions and contribute articles to me to share with others. I'll publish your articles and sign your name at the first time.
|