[转载]android遥控器:控制电脑上的暴风影音播放(C#作为服务端) – FMN – 博客园.
源码:点此下载
不知道大家有没有和我一样的习惯,喜欢躺在床上看电影,手里还拿着手机玩。。。
所以我就想到了这样一个程序:用Android手机控制电脑上的暴风影音播放(当然,同样的方法也适用于pps什么的)。大冷天的,来电话需要暂停电影电视的播放,只要在被窝里轻轻一晃手机,就停止播放了,感觉还是挺爽的,哈哈。
首先讲一下手机和电脑的互联:
1,家里有无线网路由器的话,直接将手机介入无线网就可以了。
2,只有手机和笔记本的话,可以打开Android的wifi热点。设置-无线和网络-绑定与便携式热点,打开便携式热点。然后用笔记本连接。这里要注意一下,笔记本自动获取ip的话,就可以通过android上网了,想阻止笔记本联网(省流量),可以看下笔记本自动获取到的ip和掩码,然后将ip改为手动设置,填入刚才自动获取的ip和掩码,注意千万不要设置网关和dns,不然你就等着流量耗完泪奔吧。
下面是实现原理:
播放器都有自己的快捷键,比如暴风:空格键是暂停,ctrl+left是快退,ctrl+right是快进。所以我就想到了用 PostMessage方法向(本来是用SendMessage的,可是不管用,后来改成PostMessage后就好了–//)暴风影音窗口发送键盘 消息。所以要在电脑上用C#写一个程序,用来接收android手机的消息,然后使用PostMessage方法来控制暴风影音。无论暴风影音最小化还是 全屏播放都是可以接收到消息的。
下面是实现方法:
一,首先是电脑上的C#监听程序,首先新建一个SendMsg类,实现向暴风影音发送消息。
其中向键盘发送的消息,我使用了spy++来不作的,不知道使用的google一下。其中碰到了一个问题,无法使用postMessage向进程发送“Ctrl+left”组合键,网上查了一下也说不可以,希望知道的朋友写一下方法。所以我就在暴风影音里修改了一下快捷键,将快进和快退功能分别变为right和left。
实现播放暂停的代码片段:
/// <summary> /// 开始,暂停 /// </summary> public void StartOrStop() { PostMessage(mainWindowHander, 0x0100, 0x20, 0x20390001); PostMessage(mainWindowHander, 0x0101, 0x20, 0x20390001); }
PostMessage中0x20390001代表空格键。PostMessage发动键盘消息的使用可以参考C#中使用 SendMessage 向非顶端窗体发送组合键。
上面的这个方法模拟在暴风影音上按下,松开空格键。
下面是控制暴风影音的代码:
using System; using System.Runtime.InteropServices; using System.Diagnostics; using System.Threading; namespace 暴风control { public class SendMsg { [DllImport("user32.dll", EntryPoint = "PostMessage")] //使用系统的非托管代码。 public static extern int PostMessage( IntPtr hwnd, int wMsg, uint wParam, uint lParam ); IntPtr mainWindowHander; /// <summary> /// 遍历电脑所有的进程,获取暴风影音句柄 /// </summary> public SendMsg() { Process[] allProcesses = Process.GetProcesses(); foreach (Process p in allProcesses) { if (p.ProcessName == "StormPlayer") //最新版暴风的进程名是StormPlayer,以前的是Storm在任务管理器里可以看到,这里不一样要修改一下。 mainWindowHander = p.MainWindowHandle; } if (mainWindowHander == IntPtr.Zero) { Process p = new Process(); p.StartInfo.FileName = @"D:\Baofeng\StormPlayer\StormPlayer.exe"; //暴风影音地址,改成你们自己的。 p.Start(); Thread.Sleep(3000); //这里是笨方法,要等待3秒,以免暴风影音进程还没有启动就获取句柄。 mainWindowHander = p.MainWindowHandle; } } /// <summary> /// 开始,暂停 /// </summary> public void StartOrStop() { PostMessage(mainWindowHander, 0x0100, 0x20, 0x20390001); PostMessage(mainWindowHander, 0x0101, 0x20, 0x20390001); } /// <summary> /// 快退 /// </summary> public void Back() { PostMessage(mainWindowHander, 0x0100, 0x25, 0x204b0001); PostMessage(mainWindowHander, 0x0101, 0x25, 0x204b0001); } /// <summary> /// 快进 /// </summary> public void Qian() { PostMessage(mainWindowHander, 0x0100, 0x27, 0x204d0001); PostMessage(mainWindowHander, 0x0101, 0x27, 0x204d0001); } } }
二,C#和android使用socket通信。
C#服务端的代码:
using System; using System.Text; using System.Net.Sockets; using System.Net; using System.Threading; using System.Windows.Forms; namespace 暴风control { class NetControl { SendMsg sendMsg = new SendMsg(); TextBox textBox; public NetControl(TextBox tmpTextBox) { textBox = tmpTextBox; } public void BeginListen() { Thread.CurrentThread.IsBackground = true; TcpListener server = new TcpListener(IPAddress.Any, 12121); server.Start(); while (true) { TcpClient client= server.AcceptTcpClient(); Thread clientThread = new Thread(new ParameterizedThreadStart(receiveMsg)); clientThread.Start(client); } } /// <summary> /// 服务器侦听 /// </summary> /// <param name="result"></param> private void receiveMsg(Object obj) { Control.CheckForIllegalCrossThreadCalls = false; Thread.CurrentThread.IsBackground = true; using (TcpClient client =(TcpClient)obj) { using (NetworkStream stream = client.GetStream()) { int dataLength = 0; string str; string msg; do { byte[] buffer = new byte[32]; dataLength = stream.Read(buffer, 0, buffer.Length); str = Encoding.ASCII.GetString(buffer, 0, dataLength); msg = Encoding.ASCII.GetString(buffer); sendMessage(msg); textBox.Text += "\r\n" + msg + "\r\n-----"; } while (client.Connected && msg.Substring(0, 4)!="over"); //就受到over字符串就断开连接,否则会出现死循环。。。 } } } /// <summary> /// 根据收到信息,使用不同的功能(快进,暂停等) /// </summary> private void sendMessage(string msg) { string res=msg.Substring(0,4); switch (res) { case "back": sendMsg.Back(); break; case "qian": sendMsg.Qian(); break; case "stsp": sendMsg.StartOrStop(); break; } } } }
android端的socket相关代码(现学现用,大家见谅。。):
package com.android.baofengControl; import java.io.BufferedWriter; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; import android.content.Context; import android.widget.TextView; public class Client { Socket client; PrintWriter out; TextView txt; Context context; public Client(TextView txt,Context context) { this.txt=txt; this.context=context; } ///建立连接,并保持 public void connectServer(String ip) { InetAddress serverAddress = null; try { serverAddress = InetAddress.getByName(ip); } catch (UnknownHostException e) { txt.setText(e.getLocalizedMessage()+txt.getText()); e.printStackTrace(); } try { client=new Socket(serverAddress,12121); out=new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())),true); } catch (IOException e) { txt.setText(e.getLocalizedMessage()+txt.getText()); e.printStackTrace(); } } //发送消息 public void sendMsg(String msg) throws IOException { out.println(msg); } //发送over结束字符,然后断开连接 public void close() { out.println("over"); out.close(); txt.setText("end"+txt.getText()); } }
三,摇晃手机控制播放
这里使用了网上已有的代码,稍加修改。
package com.android.baofengControl; import java.io.IOException; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; public class MySensor { SensorManager sensorManager; Client client; ///开始监听加速传感器 public void Listen(SensorManager sensorManager,Client client) { this.client=client; //发送联网数据的类。 this.sensorManager=sensorManager; Sensor sensor=sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); sensorManager.registerListener(sensorEventListener, sensor, SensorManager.SENSOR_DELAY_NORMAL); } SensorEventListener sensorEventListener =new SensorEventListener(){ long lastUpdate,lastShakeTime = 0; float x,y,last_x = 0,last_y = 0; static final int SHAKE_THRESHOLD = 750; public void onAccuracyChanged(android.hardware.Sensor arg0, int arg1) { // TODO Auto-generated method stub } public void onSensorChanged(SensorEvent e) { long curTime = System.currentTimeMillis(); // detect per 100 Millis if ((curTime - lastUpdate) > 100) { long diffTime = (curTime - lastUpdate); lastUpdate = curTime; //这里做了简化,没有用z的数据 x = e.values[SensorManager.DATA_X]; y = e.values[SensorManager.DATA_Y]; //z = Math.abs(values[SensorManager.DATA_Z]); float acceChangeRate = 0;// = Math.abs(x+y - last_x - last_y) / diffTime * 1000; if(last_x != 0) acceChangeRate = Math.abs(x+y - last_x - last_y) / diffTime * 10000; //这里设定2个阀值,一个是加速度的,一个是shake的间隔时间的 if (acceChangeRate > SHAKE_THRESHOLD && curTime - lastShakeTime > 1000) { lastShakeTime = curTime; try { client.sendMsg("stsp"); //发送消息。。。。。。。。。。。。。。。 } catch (IOException e1) { e1.printStackTrace(); } } last_x = x; last_y = y; } }}; }
最后,运行程序,然后可以按home键隐藏,只要要一下手机就可以控制暴风了。我的是2.3.7系统,测试通过。