找回密码
 立即注册
  • QQ空间
  • 回复
  • 收藏

对低头打字党的福音

前提条件 手机连着电脑 可以外接副屏显示,现在需要设计一个小程序实现任何输入法输入的信息实时在手机上显示好的,这是一个非常有趣且实用的需求。我们可以设计一个跨平台的实时投屏显示系统,它由三部分组成:电脑端服务程序、手机端显示App 和 两者之间的通信链路。由于“任何输入法”这个前提,我们不能修改或劫持系统输入法,因此核心思路是:在电脑端捕获全局键盘输入,实时发送到手机端进行显示。系统架构设计电脑端 (服务端/发送端)功能:监听电脑上的所有键盘输入,并通过网络将文本内容发送至手机。技术选型:Python(首选,因开发快捷,库丰富)pynput 或 keyboard 库:用于全局监听键盘事件。socket 库:用于建立网络通信,将数据发送到手机。手机端 (客户端/接收显示端)功能:接收从电脑发来的文本信息,并以清晰、可定制的方式全屏显示。技术选型:Android (Kotlin/Java) 或 iOS (Swift)一个简单的Android App(覆盖最广),使用 Socket 或更高层的网络框架(如 OkHttp 的 WebSocket)接收数据。一个全屏的 TextView 组件来显示内容。通信协议方式:使用 TCP Socket 或 WebSocket。WebSocket更适合双向、持续的实时通信,但TCP Socket更简单直接。数据格式:简单的字符串(UTF-8编码)或JSON(例如 {"text": "你好世界"})以便未来扩展。连接方式:电脑和手机必须在同一个局域网(Wi-Fi) 下。实现步骤详解第一部分:电脑端程序 (Python实现示例)安装必要的库bash复制下载pip install pynput编写代码 (computer_sender.py)python复制下载import socketfrom pynput import keyboard# ===== 配置部分 =====PHONE_IP = '192.168.1.100'  # 手机的IP地址,需要在手机上查看PORT = 12345                # 选择一个端口号,两边要一致# ===================# 创建Socket连接client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)try:    client_socket.connect((PHONE_IP, PORT))    print(f"已连接到手机 {PHONE_IP}:{PORT}")except Exception as e:    print(f"连接失败: {e}")    exit()# 缓冲区,用于处理组合键(如中文输入)current_text = ""def on_press(key):    global current_text    try:        # 处理普通字符键        if hasattr(key, 'char') and key.char is not None:            current_text += key.char            # 可以在这里选择实时发送每个字符,或者等回车再发送            # send_text(key.char)                 except AttributeError:        # 处理特殊键        if key == keyboard.Key.space:            current_text += ' '        elif key == keyboard.Key.enter:            # 按下回车时,将当前缓冲的文本发送出去并清空缓冲区            send_text(current_text + '\n') # 加换行符以便手机端换行            current_text = ""        elif key == keyboard.Key.backspace:            current_text = current_text[:-1]        # ESC键作为清除屏幕的快捷方式        elif key == keyboard.Key.esc:            send_text("CLEAR_SCREEN") # 发送一个特殊指令            current_text = ""def on_release(key):    # 如果按下ESC,则退出监听    if key == keyboard.Key.esc:        # 这里我们用来退出程序        return Falsedef send_text(text):    try:        # 发送编码后的文本数据        client_socket.send(text.encode('utf-8'))    except Exception as e:        print(f"发送错误: {e}")# 监听键盘with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:    print("键盘监听已启动...开始在电脑上输入吧!")    listener.join()# 关闭连接client_socket.close()第二部分:手机端程序 (Android简化示例)创建一个新的Android项目选择 Empty Activity。修改布局文件 (activity_main.xml)创建一个全屏、居中的大字TextView。xml复制下载运行<?xml version="1.0" encoding="utf-8"?><androidx.constraintlayout.widget.ConstraintLayout    xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:background="#000000">    <TextView        android:id="@+id/tv_display"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:textColor="#FFFFFF"        android:textSize="36sp"        app:layout_constraintBottom_toBottomOf="parent"        app:layout_constraintLeft_toLeftOf="parent"        app:layout_constraintRight_toRightOf="parent"        app:layout_constraintTop_toTopOf="parent" /></androidx.constraintlayout.widget.ConstraintLayout>修改MainActivity (MainActivity.kt)在后台线程中建立Socket连接,接收数据并更新UI。kotlin复制下载import android.os.Bundleimport androidx.appcompat.app.AppCompatActivityimport kotlinx.android.synthetic.main.activity_main.*import java.io.BufferedReaderimport java.io.InputStreamReaderimport java.net.ServerSocketimport kotlin.concurrent.threadclass MainActivity : AppCompatActivity() {    override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        setContentView(R.layout.activity_main)        // 启动一个线程来运行Socket服务器,避免阻塞主UI线程        thread {            startServerSocket()        }    }    private fun startServerSocket() {        val PORT = 12345        try {            val serverSocket = ServerSocket(PORT)            println("服务器启动,等待连接...")            val clientSocket = serverSocket.accept() // 这是一个阻塞调用            println("电脑已连接!")            val inputStream = clientSocket.getInputStream()            val reader = BufferedReader(InputStreamReader(inputStream, "UTF-8"))            val buffer = CharArray(1024)            var numChars: Int            // 持续读取数据            while (reader.read(buffer).also { numChars = it } != -1) {                val receivedText = String(buffer, 0, numChars)                // 在主线程上更新UI                runOnUiThread {                    if (receivedText == "CLEAR_SCREEN") {                        tv_display.text = ""                    } else {                        // 追加新文本                        tv_display.append(receivedText)                    }                }            }            serverSocket.close()        } catch (e: Exception) {            e.printStackTrace()            runOnUiThread {                tv_display.text = "错误: ${e.message}"            }        }    }}添加网络权限在 AndroidManifest.xml 中添加:xml复制下载运行<uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />使用流程准备工作:保证电脑和手机连接同一个Wi-Fi。在手机设置中找到手机的IP地址(关于手机->状态信息->IP地址)。启动手机端:在Android Studio中运行App,安装到手机。启动App,它会显示一个黑屏,并开始等待连接。启动电脑端:修改 computer_sender.py 中的 PHONE_IP 为你的手机IP。在电脑上运行Python脚本:python computer_sender.py看到“已连接到手机”的提示后,即可开始输入。开始使用:在电脑上任意地方(记事本、浏览器、Word)打字,文本就会实时显示在手机屏幕上。按 Enter 键换行。按 Esc 键清空手机屏幕。注意事项与优化方向隐私与安全:此程序会捕获所有键盘输入,请绝对谨慎使用,确保只在可信的网络环境下运行,避免泄露密码等敏感信息。输入法兼容性:对于中文等需要组合输入的输入法,pynput 可能在组合过程中就发送了拼音字母。上面的代码使用了一个缓冲区,在按下回车后才发送,这是一种解决方案。更复杂的方案需要处理预编辑文本(IME composition),这非常复杂,通常需要操作系统级别的接口。稳定性:网络中断、程序崩溃等情况需要考虑重连机制。功能增强:手机端作为输入源:可以扩展为双向通信,让手机也能发送文本到电脑(反向遥控)。文本样式设置:在手机端增加设置,改变字体大小、颜色、背景色。历史记录:保存显示过的文本。使用WebSocket:替代原生Socket,连接更稳定,更适合双向通信。生成二维码:电脑端生成一个包含IP和端口信息的二维码,手机端扫码即可连接,避免手动输入IP。这个设计提供了一个简单但功能完整的起点,你可以根据实际需求进行进一步的开发和优化。开启新对话
回复

使用道具 举报

说点什么

您需要登录后才可以回帖 登录 | 立即注册
HOT • 推荐