第二标题:SOCKET通讯与SENINPUT发送键盘消息
by the way,其实大部分代码都是抄抄抄,拼凑出来的简陋作品,连隐藏黑窗口都没做,高手们别见笑
咳咳,言归正传,事情起因是这样的——
PC用的键盘是五年前的普通键盘,久了不好用,经常卡涩,恰好手头有一把蓝牙键盘,原本是买来应急,想在手机上敲键盘用的,然而……吃灰了许久
但是,有键盘,却发现没有插电脑上接收蓝牙信号的适配器,以前有过一个不知何时没了……
买一个也不贵,但手里旧手机两部,明明都有蓝牙功能,却不能利用起来,也太浪费了!!!
一开始的想法,是直接手机插电脑上,把手机的键盘信号存到文件,再从电脑这边读取手机的文件,很简单的IO操作就能完成,然而旧手机连接起来有点毛病,有时候会断……
恰好有个大佬提建议,用SOCKET!
这东西原本只是知道点原理,具体的从来没用过,也没怎么学过,搜了一下,发现还挺简单的,linux和win上都成功实现,这里贴上win平台上的伺听端代码
补充说明:作为服务器听取端,是在第一级路由上的,手机在第二级路由的WIFI上时,能连接,反过来或者其他情况行不行,不确定
#include <QCoreApplication>
#include <winsock.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <winuser.h>
#include <windows.h>
//#pragma comment (lib, "ws2_32.lib") 用QT敲的,这个连接在设置里弄
#define SERVER_PORT 12341int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);//初始化 DLLWSADATA wsaData;WSAStartup(MAKEWORD(2, 2),&wsaData);//创建套接字SOCKET servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);if(servSock == INVALID_SOCKET){perror("faild socket");return 0;}//绑定套接字sockaddr_in sockAddr;memset(&sockAddr, 0, sizeof(sockAddr)); //每个字节都用0填充sockAddr.sin_family = PF_INET; //使用IPv4地址sockAddr.sin_addr.s_addr = inet_addr("192.168.0.118"); //具体的IP地址sockAddr.sin_port = htons(SERVER_PORT); //端口if(bind(servSock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR)) == -1){printf("bind faild : %d",WSAGetLastError());return 0;}//进入监听状态int lisb = listen(servSock, 20);printf("listen return:%d\n",lisb);while(1){//接收客户端请求SOCKADDR clntAddr;int nSize = sizeof(SOCKADDR);SOCKET clntSock = accept(servSock, (SOCKADDR*)&clntAddr, &nSize);if(clntSock == INVALID_SOCKET)continue;elseprintf("get clint!");char buffer[200] = {0};int grecv = recv(clntSock,buffer,sizeof(buffer),0);if(strlen(buffer)>4){char kvalue[5]={0};//我用up down表明松开、按下int kcode;//手机转发出来的keycodesscanf(buffer,"%[^' '] %d",kvalue,&kcode);//sscanf是真的好用,匹配读取int kivalue = strlen(kvalue)>=4?0:1;//判断按下松开,用0,1表示skbmsg(kivalue,trascode(kcode));//传递给发送键盘信号的函数printf("%s,%d",kvalue,kcode);}//关闭套接字closesocket(clntSock);}closesocket(servSock);//终止 DLL 的使用WSACleanup();return 0;return a.exec();
}
上面大半的注释都是照抄的,连代码一起【doge】
循环接受连接并读取键盘消息后,就得转成电脑端的键盘消息了,代码如下(其实应该是“如上”,C嘛……)——
\\第一个函数,把手机KEYCODE部分不一样的转成PC系统用的标准码,这个参考意义不大,恰好跟我一样蛋疼想这么玩的,得自己试试各个键码,对照标准码
int trascode(int rgkecode)
{int result = rgkecode;switch (rgkecode) {case 16777216: result = 112; break;case 16777376: result = 113; break;case 45: result = 189; break;case 16777469: result = 115; break;case 16777362: result = 116; break;case 16777346: result = 118; break;case 16777344: result = 119; break;case 16777347: result = 120; break;case 16777329: result = 121; break;case 61: result = 187; break;case 16777219: result = 8; break;case 16777217: result = 9; break;case 16777252: result = 20; break;case 16777248: result = 16; break;case 16777249: result = 17; break;case 16777251: result = 18; break;case 16777220: result = 13; break;case 16777235: result = 38; break;case 16777237: result = 40; break;case 16777234: result = 37; break;case 16777236: result = 39; break;case 96: result = 192; break;case 44: result = 188; break;case 46: result = 190; break;case 47: result = 191; break;case 59: result = 186; break;case 39: result = 222; break;case 91: result = 219; break;case 93: result = 221; break;case 92: result = 220; break;default:break;}return result;
}//吐槽一个,微软用SENDINPUT取代KEYEVEN,是因为后者会出BUG么……我原本是想用KEYEVEN的,然而出现严重的BUG,哪怕程序终止了,BUG现象还在
void skbmsg(int kvalue,int kcode)
{INPUT input[1];memset(input,0,sizeof(INPUT));input[0].type = INPUT_KEYBOARD;//表明为键盘事件input[0].ki.wVk = kcode;//键码if(kvalue)//如果没有下面这句,默认是按下input[0].ki.dwFlags = KEYEVENTF_KEYUP;SendInput(1,input,sizeof(INPUT));
//这个函数更多的相关知识,有兴趣的就自己百度\BING\GOOGLE了
}
手机端的代码得等我切换到deepin上,我在linux-deepin上用QT敲的,不过下篇不会有LINUX端的代码
——因为没成功……
没搞定给系统发送键盘信号这个关键部分,尝试用 open\write /dev/input/…… 失败了