.NET CF WM设备(手机)振动


        有时候需要在转换页面的时候用振动提示用户以获得更好的用户体验,这就需要提到在WM设备上实现振动的问题了。这里提供2中方式,但都是换汤不换药。一种是P/Invoke调用系统API来实现,另一种是通过使用OpenNETCF来实现(我认为也是通过调用系统API来实现,难道他有设备供应商更底层的接口,呵呵,玩笑!)。 
        当然,在实现的时候需要考虑是在PPC还是SP平台上,不同的平台有不同实现,这也是由2种平台的差异性造成的。
        好,进入正题!

方法一: 通过P/Inovke调用系统API
g 1. 在PPC上
ContractedBlock.gif ExpandedBlockStart.gif PPC
    // for PPC
    public class Vibrate_PPC
ExpandedBlockStart.gifContractedBlock.gif    
{
        
// 可用的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()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
        }


        
// 查找可用的Led,并振动
        public static bool Play()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
bool bRes = false;

            NLED_SETTINGS_INFO nsi 
= new NLED_SETTINGS_INFO();
            nsi.OffOnBlink 
= (int)LedState.On;

            
if (m_availableNo == 0xFFFFFFFF)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
// 获取设备数
                NLED_COUNT_INFO pOutput = new NLED_COUNT_INFO();
                
if (!NLedGetDeviceCount(NLED_COUNT_INFO_ID, ref pOutput))
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    
// 初始化失败,跑出异常
                    return false;
                }


                
// 设备上一般有至少2个Led, 0为扬声器Led, 而振动器为最后一个
                m_availableNo = pOutput.cLeds - 1;
                nsi.LedNum 
= m_availableNo;
                bRes 
= NLedSetDevice(NLED_SETTINGS_INFO_ID, ref nsi);
            }

            
else
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
// 如果之前已经得到正确的Led号,那么就直接调用了
                nsi.LedNum = m_availableNo;
                bRes 
= NLedSetDevice(NLED_SETTINGS_INFO_ID, ref nsi);
            }


            
if (bRes)
                
return true;
            
else
                
return false;
        }


        
public static bool Stop()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (m_availableNo != 0xFFFFFFFF)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                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;
        }


ContractedSubBlock.gifExpandedSubBlockStart.gif
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
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            Off,
            On,
            Blink
        }


        [StructLayout(LayoutKind.Sequential)]
        
private struct NLED_COUNT_INFO
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
public uint cLeds;
        }


        [StructLayout(LayoutKind.Sequential)]
        
private struct NLED_SUPPORTS_INFO
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
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
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
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上
ContractedBlock.gif ExpandedBlockStart.gif Smartphone
    // for SmartPhone
    public sealed class Vibrate_SP
ExpandedBlockStart.gifContractedBlock.gif    
{
        
private static bool m_bSupport = false;
        
private Vibrate_SP()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
        }


        
public static bool Play()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
int iRes = -1;
            
if (m_bSupport)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                iRes 
= VibratePlay(0, IntPtr.Zero, uint.MaxValue, uint.MaxValue);
            }

            
else
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
int caps = -1;
                caps 
= VibrateGetDeviceCaps(VibrationCapabilities.Amplitude);
                
// 0: 不支持振动
                
// 1: 说明设备具有振动功能,并且可以使用,但是仅仅具有打开关闭震动,无法对振动进行调节
                
// 2-7: 说明了设备提供了不同等级的振动功能,数字越大提供的调节能力越强
                if (caps <= 0)
                    
return false;
                
else
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    m_bSupport 
= true;
                    iRes 
= VibratePlay(0, IntPtr.Zero, uint.MaxValue, uint.MaxValue);
                }

            }


            
if (iRes == 0)
                
return true;
            
else
                
return false;
        }


        
public static bool Stop()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (VibrateStop() != 0)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
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
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            Amplitude,
            Frequency,
            last
        }

    }



g 3. 提供统一接口,不考虑平台
因为要考虑不同平台,因此要添加Microsoft.WindowsCE.Forms组件并引用 “using Microsoft.WindowsCE.Forms”。然后就可以通过SystemSettings和WinCEPlatform来判断所属平台了。
ContractedBlock.gif ExpandedBlockStart.gif 统一接口
    public class Vibrate
ExpandedBlockStart.gifContractedBlock.gif    
{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 实现震动
        
/// </summary>
        
/// <param name="microSeconds">震动毫秒数</param>

        public static void Play(int microSeconds)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (SystemSettings.Platform == WinCEPlatform.PocketPC)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                Vibrate_PPC.Play();
                System.Threading.Thread.Sleep(microSeconds);
                Vibrate_PPC.Stop();
            }

            
else if (SystemSettings.Platform == WinCEPlatform.Smartphone)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                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中调用振动的接口。
ContractedBlock.gif ExpandedBlockStart.gif OpenNETCF
        private void Btn_OpenNETCF_Click(object sender, EventArgs e)
ExpandedBlockStart.gifContractedBlock.gif        
{
            
// PPC
            if (SystemSettings.Platform == WinCEPlatform.PocketPC)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                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)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                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上
ContractedBlock.gif ExpandedBlockStart.gif 修正通过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(1ref 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

声明:
这里集中了在WinCEWindows 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.

  

转载于:https://www.cnblogs.com/Lisen/archive/2009/08/15/1546859.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值