看了一个视频,可以将旧手机改成蓝牙键盘进行输入,于是想试试。这一搞就搞了近一个月。本人不太会编程,只是写过个人用得着的程序,简化手中的工作。对于android开发并不懂。突击学习了一下蓝牙的知识。本来以为很简单。开始用微软的xamarin开发,毕竟微软的东西好用,而且语法熟悉。但后来发现xamarin的资料很少,最多的还是android java的。于是下了个android studio进行学习。一开始就发现grandle不好搞 ,搞 了很多天后搞定,至少可以运行demo程序了。但一直没有进展,有很多介绍客户端,服务器端的,在github上找了很多,倒有一些可以实现,但程序看不懂。本来想放弃,后来在csdn上看了几个大侠写的东西,又进行了测试,突然有一天发现测试通了。可以了。现在就将这个简单的程序给大家,有兴趣的同志可以看看。
手机做蓝牙键盘应该有很多种,我用的是最简单的。原来在ApI版本比较低的时候,有些人用了很多底层的技术,实现得非常好。但我看不懂。如github上有一个程序kontroller,在低API下可以运行,升级后无法运行。看了代码,本人水平太低,看不懂。最后实现的是用API28以后的版本,也非常简单,也是如csdn上很多大侠所说的那样,就是几个回调函数。这样将手机变成了蓝牙键盘。
这时候蓝牙既不是客户端,也不是服务器端。然后再去连接。我用的很简单,要求API31上,因为好象现在的蓝牙连接需要动态获取权限,我写的语句就是直接从网上抄下来的,成功动态给了权限。其他也不说什么,这是完整的代码,其实就是一个文件,另一个是定义HID设备的类。写的代码不规范,就是给大家个思路,再次感谢csdn上的大侠们。文章来源:https://www.toymoban.com/news/detail-766146.html
package com.example.sendkeyboard; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import android.Manifest; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHidDevice; import android.bluetooth.BluetoothHidDeviceAppQosSettings; import android.bluetooth.BluetoothHidDeviceAppSdpSettings; import android.bluetooth.BluetoothManager; import android.bluetooth.BluetoothProfile; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Bundle; import android.os.StrictMode; import android.provider.SyncStateContract; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.ImageView; import java.io.IOException; import java.io.OutputStream; import java.net.Socket; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Executors; public class MainActivity extends AppCompatActivity { BluetoothAdapter mBluetoothAdapter; BluetoothHidDevice mBluetoothHID; public String TAG = "Proxy Program"; boolean connected; private BluetoothManager mBluetoothManager; boolean IsRegisted; BluetoothDevice ConnectedDevice; private BluetoothProfile.ServiceListener mProfileListener = new BluetoothProfile.ServiceListener() { public void onServiceConnected(int profile, BluetoothProfile proxy) { //Log.d(TAG, "Connecting HIDService..."); if (profile == BluetoothProfile.HID_DEVICE) { if (!(proxy instanceof BluetoothHidDevice)) { Log.e(TAG, "Proxy received but it's not BluetoothHidDevice"); return; } Log.d(TAG, "Connecting HIDService..."); mBluetoothHID = (BluetoothHidDevice) proxy; BluetoothHidDeviceAppSdpSettings sdp = new BluetoothHidDeviceAppSdpSettings(HidConfig.NAME, HidConfig.DESCRIPTION, HidConfig.PROVIDER, BluetoothHidDevice.SUBCLASS1_COMBO, HidConfig.KEYBOARD_DESCRIPTOR); // if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) { // TODO: Consider calling // ActivityCompat#requestPermissions // here to request the missing permissions, and then overriding // public void onRequestPermissionsResult(int requestCode, String[] permissions, // int[] grantResults) // to handle the case where the user grants the permission. See the documentation // for ActivityCompat#requestPermissions for more details. Log.d(TAG, "Return before register"); String[] list = new String[]{Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT}; requestPermissions(list, 1); Log.d(TAG, "Return before register"); return; } BluetoothHidDeviceAppQosSettings inQos = new BluetoothHidDeviceAppQosSettings( BluetoothHidDeviceAppQosSettings.SERVICE_GUARANTEED, 200, 2, 200, 10000 /* 10 ms */, 10000 /* 10 ms */); BluetoothHidDeviceAppQosSettings outQos = new BluetoothHidDeviceAppQosSettings( BluetoothHidDeviceAppQosSettings.SERVICE_GUARANTEED, 900, 9, 900, 10000 /* 10 ms */, 10000 /* 10 ms */); mBluetoothHID.registerApp(sdp, inQos, outQos, Executors.newCachedThreadPool(), mCallback); //startActivityForResult(new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE), 1); //https://blog.csdn.net/lgdlchshg/article/details/127469781 } } public void onServiceDisconnected(int profile) { if (profile == BluetoothProfile.HID_DEVICE) { Log.d(TAG, "Unexpected Disconnect of HIDService..."); mBluetoothHID = null; mBluetoothHID.unregisterApp(); } } }; public final BluetoothHidDevice.Callback mCallback = new BluetoothHidDevice.Callback() { @Override public void onAppStatusChanged(BluetoothDevice pluggedDevice, boolean registered) { IsRegisted = registered; if(registered){ Log.d(TAG, "register OK!...................."); } } @Override public void onConnectionStateChanged(BluetoothDevice device, int state) { if (state == BluetoothProfile.STATE_DISCONNECTED) { connected = false; Log.d(TAG, "hid state is disconnected"); } else if (state == BluetoothProfile.STATE_CONNECTED) { connected = true; Log.d(TAG, "hid state is connected"); Log.d(TAG, "----------------------------------------hid state is connected"); Log.d(TAG, device.getName().toString()); // byte mBuffer = (byte) 63; // mBluetoothHID.sendReport(device,32, mBuffer); // 不知道为啥子这样写? ConnectedDevice = device; } else if (state == BluetoothProfile.STATE_CONNECTING) { Log.d(TAG, "hid state is connecting"); } } }; public void ShowBlueToothKB() { mBluetoothAdapter.getProfileProxy(this, mProfileListener, BluetoothProfile.HID_DEVICE); } public void SendBKToHost() { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) { // TODO: Consider calling // ActivityCompat#requestPermissions // here to request the missing permissions, and then overriding // public void onRequestPermissionsResult(int requestCode, String[] permissions, // int[] grantResults) // to handle the case where the user grants the permission. See the documentation // for ActivityCompat#requestPermissions for more details. Log.e(TAG, "check permission Error ,Exit SendBKtohost Function"); String[] list = new String[]{Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT}; requestPermissions(list, 1); return; } // onKeyDown((byte) 0x09); // onKeyUp((byte) 0x09); Log.e(TAG, "----------------Preparing Send Key------------------"); // mBluetoothHID.sendReport(ConnectedDevice,2, new byte[]{0, 0,(byte)0x09, 0, 0, 0, 0, 0}); //mBluetoothHID.sendReport(ConnectedDevice,2, new byte[]{0,0,0,0,0,0,0,0}); // sendKey("F"); //sendKey("_"); sendKey("enter"); try { Thread.sleep( 1000 ); } catch (Exception e){ System.exit( 0 ); //退出程序 } sendKey("S"); sendKey("enter"); // sendKey(">"); // sendKey("*"); //sendKey("enter"); } public void sendStringtodevice(String str) { for (int i=0;i<str.length();i++) { sendKey(str.substring(i,i+1)); } } public void ConnectotherBluetooth() { ConnectedDevice = mBluetoothAdapter.getRemoteDevice("04:7F:0E:40:74:6E"); if (ConnectedDevice != null) { Log.e(TAG, "Connected Device is OK"); Log.e(TAG, ConnectedDevice.getName()); } mBluetoothHID.connect(ConnectedDevice);//用代理去联接已联接的蓝牙设备,就能保证连接上 } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); inithashMap(); mBluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE); mBluetoothAdapter = mBluetoothManager.getAdapter(); //permit network in Main UI thread StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy(policy); Button btnInit = findViewById(R.id.btninit); btnInit.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //readData(); ShowBlueToothKB(); } }); ImageView imgsend=findViewById(R.id.imgsend); imgsend.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.e(TAG, "check permission"); String[] list = new String[]{Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT}; requestPermissions(list, 1); SendBKToHost(); //readData(); } }); ImageView imgbalckscreen=findViewById(R.id.imgbalckescreen); imgbalckscreen.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.e(TAG, "Send Blank screen"); SendBBKMessage(); //readData(); } }); Button btnconnect = findViewById(R.id.btnconnect); btnconnect.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.e(TAG, "Connect other BlueTooth"); // String[] list =new String[]{Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT}; // // requestPermissions(list, 3); ConnectotherBluetooth(); } }); } public void SendBBKMessage() { Log.e(TAG,"Send Message to Host"); try { Socket socket = new Socket("127.0.0.1", 10086);// OutputStream outputStream = socket.getOutputStream(); outputStream.write('s'); outputStream.flush(); //socket.SendUrgentData('S'); //2.拿到客户端的socket对象的输出流发送给服务器数据 //text1.setText("BBB"); outputStream.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); return; } } private byte[] mBuffer = new byte[8]; int id = 2; public void sendKey(String key) { byte b1 = 0; if (key.length() <= 1) { char keyChar = key.charAt(0); if ((keyChar >= 65) && (keyChar <= 90)) { b1 = 2; } } if (SHITBYTE.containsKey(key)) { b1 = 2; } mBluetoothHID.sendReport(ConnectedDevice, 2, new byte[]{b1, 0, KEY2BYTE.get(key.toUpperCase()),0,0,0,0,0}); mBluetoothHID.sendReport(ConnectedDevice, 2, new byte[]{0,0, 0,0,0,0,0,0}); } public Map<String,Byte> KEY2BYTE = new HashMap<String,Byte>(); public Map<String,Boolean> SHITBYTE = new HashMap<String,Boolean> (); public void inithashMap() { KEY2BYTE.put("A", (byte) 4); KEY2BYTE.put("B",(byte)5); KEY2BYTE.put("C",(byte)6); KEY2BYTE.put("D",(byte)7); KEY2BYTE.put("E",(byte)8); KEY2BYTE.put("F",(byte)9); KEY2BYTE.put("G",(byte)10); KEY2BYTE.put("H",(byte)11); KEY2BYTE.put("I",(byte)12); KEY2BYTE.put("J",(byte)13); KEY2BYTE.put("K",(byte)14); KEY2BYTE.put("L",(byte)15); KEY2BYTE.put("M",(byte)16); KEY2BYTE.put("N",(byte)17); KEY2BYTE.put("O",(byte)18); KEY2BYTE.put("P",(byte)19); KEY2BYTE.put("Q",(byte)20); KEY2BYTE.put("R",(byte)21); KEY2BYTE.put("S",(byte)22); KEY2BYTE.put("T",(byte)23); KEY2BYTE.put("U",(byte)24); KEY2BYTE.put("V",(byte)25); KEY2BYTE.put("W",(byte)26); KEY2BYTE.put("X",(byte)27); KEY2BYTE.put("Y",(byte)28); KEY2BYTE.put("Z",(byte)29); KEY2BYTE.put("1",(byte)30); KEY2BYTE.put("2",(byte)31); KEY2BYTE.put("3",(byte)32); KEY2BYTE.put("4",(byte)33); KEY2BYTE.put("5",(byte)34); KEY2BYTE.put("6",(byte)35); KEY2BYTE.put("7",(byte)36); KEY2BYTE.put("8",(byte)37); KEY2BYTE.put("9",(byte)38); KEY2BYTE.put("0",(byte)39); KEY2BYTE.put("ENTER",(byte)40); KEY2BYTE.put("ESC",(byte)41); KEY2BYTE.put("BACK_SPACE",(byte)42); KEY2BYTE.put("TAB",(byte)43); KEY2BYTE.put("SPACE",(byte)44); KEY2BYTE.put("-",(byte)45); KEY2BYTE.put("=",(byte)46); KEY2BYTE.put("[",(byte)47); KEY2BYTE.put("]",(byte)48); KEY2BYTE.put("\\",(byte)49); KEY2BYTE.put(";",(byte)51); KEY2BYTE.put("'",(byte)52); KEY2BYTE.put("`",(byte)53); KEY2BYTE.put(",",(byte)54); KEY2BYTE.put(".",(byte)55); KEY2BYTE.put("/",(byte)56); KEY2BYTE.put("SCROLL_LOCK",(byte)71); KEY2BYTE.put("INSERT ",(byte)73); KEY2BYTE.put("HOME ",(byte)74); KEY2BYTE.put("PAGE_UP ",(byte)75); KEY2BYTE.put("DELETE ",(byte)76); KEY2BYTE.put("END ",(byte)77); KEY2BYTE.put("PAGE_DOWN ",(byte)78); KEY2BYTE.put("DPAD_RIGHT ",(byte)79); KEY2BYTE.put("KEYCODE_DPAD_LEFT ",(byte)80); KEY2BYTE.put("KEYCODE_DPAD_DOWN ",(byte)81); KEY2BYTE.put("KEYCODE_DPAD_UP ",(byte)82); KEY2BYTE.put("NUM_LOCK ",(byte)83); KEY2BYTE.put("!",(byte)30); SHITBYTE.put("!",true); KEY2BYTE.put("@",(byte)31); SHITBYTE.put("@",true); KEY2BYTE.put("#",(byte)32); SHITBYTE.put("#",true); KEY2BYTE.put("$",(byte)33); SHITBYTE.put("$",true); KEY2BYTE.put("%",(byte)34); SHITBYTE.put("%",true); KEY2BYTE.put("^",(byte)35); SHITBYTE.put("^",true); KEY2BYTE.put("&",(byte)36); SHITBYTE.put("&",true); KEY2BYTE.put("*",(byte)37); SHITBYTE.put("*",true); KEY2BYTE.put("(",(byte)38); SHITBYTE.put("(",true); KEY2BYTE.put(")",(byte)39); SHITBYTE.put(")",true); KEY2BYTE.put("_",(byte)45); SHITBYTE.put("_",true); KEY2BYTE.put("+",(byte)46); SHITBYTE.put("+",true); KEY2BYTE.put("{",(byte)47); SHITBYTE.put("{",true); KEY2BYTE.put("}",(byte)48); SHITBYTE.put("}",true); KEY2BYTE.put("|",(byte)49); SHITBYTE.put("|",true); KEY2BYTE.put(":",(byte)51); SHITBYTE.put(":",true); KEY2BYTE.put("\"",(byte)52); SHITBYTE.put("\"",true); KEY2BYTE.put("<",(byte)54); SHITBYTE.put("<",true); KEY2BYTE.put(">",(byte)55); SHITBYTE.put(">",true); KEY2BYTE.put("?",(byte)56); SHITBYTE.put("?",true); } }
==================Hidconfig============文件文章来源地址https://www.toymoban.com/news/detail-766146.html
package com.example.sendkeyboard; public class HidConfig { public final static String NAME = "My Keyboard"; public final static String DESCRIPTION = " Keyboard"; public final static String PROVIDER = "df"; public final static byte[] KEYBOARD_DESCRIPTOR = { (byte) 0x05, (byte) 0x01, // USAGE_PAGE (Generic Desktop) (byte) 0x09, (byte) 0x06, // USAGE (Keyboard) (byte) 0xa1, (byte) 0x01, // COLLECTION (Application) (byte) 0x85, (byte) 0x02, //REPORT_ID (2) (byte) 0x05, (byte) 0x07, // USAGE_PAGE (Keyboard) (byte) 0x19, (byte) 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) (byte) 0x29, (byte) 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) (byte) 0x15, (byte) 0x00, // LOGICAL_MINIMUM (0) (byte) 0x25, (byte) 0x01, // LOGICAL_MAXIMUM (1) (byte) 0x75, (byte) 0x01, // REPORT_SIZE (1) (byte) 0x95, (byte) 0x08, // REPORT_COUNT (8) (byte) 0x81, (byte) 0x02, // INPUT (Data,Var,Abs) (byte) 0x95, (byte) 0x01, // REPORT_COUNT (1) (byte) 0x75, (byte) 0x08, // REPORT_SIZE (8) (byte) 0x81, (byte) 0x03, // INPUT (Cnst,Var,Abs) (byte) 0x95, (byte) 0x05, // REPORT_COUNT (5) (byte) 0x75, (byte) 0x01, // REPORT_SIZE (1) (byte) 0x05, (byte) 0x08, // USAGE_PAGE (LEDs) (byte) 0x19, (byte) 0x01, // USAGE_MINIMUM (Num Lock) (byte) 0x29, (byte) 0x05, // USAGE_MAXIMUM (Kana) (byte) 0x91, (byte) 0x02, // OUTPUT (Data,Var,Abs) (byte) 0x95, (byte) 0x01, // REPORT_COUNT (1) (byte) 0x75, (byte) 0x03, // REPORT_SIZE (3) (byte) 0x91, (byte) 0x03, // OUTPUT (Cnst,Var,Abs) (byte) 0x95, (byte) 0x06, // REPORT_COUNT (6) (byte) 0x75, (byte) 0x08, // REPORT_SIZE (8) (byte) 0x15, (byte) 0x00, // LOGICAL_MINIMUM (0) (byte) 0x25, (byte) 0x65, // LOGICAL_MAXIMUM (101) (byte) 0x05, (byte) 0x07, // USAGE_PAGE (Keyboard) (byte) 0x19, (byte) 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) (byte) 0x29, (byte) 0x65, // USAGE_MAXIMUM (Keyboard Application) (byte) 0x81, (byte) 0x00, // INPUT (Data,Ary,Abs) (byte) 0xc0, // END_COLLECTION // END_COLLECTION }; }
到了这里,关于使用旧手检做成蓝牙键盘的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!