screen-keyboard 1.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,7 @@
1
+ include README.md
2
+ include LICENSE
3
+ include requirements.txt
4
+ recursive-include src *.html
5
+ recursive-include src *.py
6
+ recursive-include src *.md
7
+ recursive-include src *.txt
@@ -0,0 +1,122 @@
1
+ Metadata-Version: 2.4
2
+ Name: screen-keyboard
3
+ Version: 1.0.1
4
+ Summary: 手机键盘控制电脑 - 通过手机浏览器控制电脑输入
5
+ Author-email: Your Name <your-email@example.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/your-username/screen-keyboard
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.8
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Requires-Python: >=3.8
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Requires-Dist: flask>=2.3.0
20
+ Requires-Dist: flask-socketio>=5.3.0
21
+ Requires-Dist: pynput>=1.7.6
22
+ Requires-Dist: python-socketio>=5.10.0
23
+ Requires-Dist: python-engineio>=4.8.0
24
+ Requires-Dist: simple-websocket>=1.0.0
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest; extra == "dev"
27
+ Requires-Dist: black; extra == "dev"
28
+ Requires-Dist: flake8; extra == "dev"
29
+ Dynamic: license-file
30
+
31
+ # 手机键盘控制电脑
32
+
33
+ 通过手机浏览器访问网页,使用虚拟键盘控制电脑输入。
34
+
35
+ **原理**:网页发送键盘按键到电脑,由电脑上的输入法(如搜狗、微软拼音)处理拼音转换。
36
+
37
+ ## 快速安装
38
+
39
+ ### 方法一:pip 安装(推荐)
40
+
41
+ ```bash
42
+ # 安装
43
+ pip install screen-keyboard
44
+
45
+ # 运行
46
+ screen-keyboard
47
+ ```
48
+
49
+ ### 方法二:源码安装
50
+
51
+ ```bash
52
+ # 克隆或直接下载后
53
+ pip install -e .
54
+
55
+ # 运行
56
+ screen-keyboard
57
+ # 或
58
+ python app.py
59
+ ```
60
+
61
+ ### 方法三:一行命令安装
62
+
63
+ ```bash
64
+ curl -sL https://raw.githubusercontent.com/your-username/screen-keyboard/main/install-one-line.sh | bash
65
+ ```
66
+
67
+ ## 使用方法
68
+
69
+ ### 1. 启动服务
70
+
71
+ ```bash
72
+ screen-keyboard
73
+ # 或
74
+ python app.py
75
+ ```
76
+
77
+ ### 2. 手机访问
78
+
79
+ 服务端启动后会显示局域网地址,例如:
80
+ ```
81
+ 局域网地址:http://192.168.1.100:5000
82
+ ```
83
+
84
+ 在手机上连接同一 WiFi,用浏览器访问该地址即可。
85
+
86
+ ## 功能
87
+
88
+ - ✅ 全键盘布局(QWERTY)
89
+ - ✅ 符号/数字键盘切换
90
+ - ✅ Shift 大写切换
91
+ - ✅ 特殊按键(回车、退格、空格)
92
+ - ✅ 方向键(倒 T 布局)
93
+ - ✅ 触控板鼠标控制
94
+ - ✅ 摇杆鼠标控制
95
+ - ✅ 鼠标左右中键 + 滚轮
96
+ - ✅ Win+Space 中英文切换
97
+ - ✅ 拖动窗口/文件(双击触控板后拖动)
98
+
99
+ ## 说明
100
+
101
+ - 确保手机和电脑在同一局域网
102
+ - 电脑需开启拼音输入法
103
+ - 如果防火墙阻止,请开放 5000 端口
104
+
105
+ ## 开发
106
+
107
+ ```bash
108
+ # 创建 conda 环境
109
+ conda env create -f environment.yml
110
+ conda activate screen-keyboard
111
+
112
+ # 安装依赖
113
+ pip install -r requirements.txt
114
+
115
+ # 运行
116
+ python app.py
117
+ ```
118
+
119
+ ## License
120
+
121
+ MIT License
122
+
@@ -0,0 +1,92 @@
1
+ # 手机键盘控制电脑
2
+
3
+ 通过手机浏览器访问网页,使用虚拟键盘控制电脑输入。
4
+
5
+ **原理**:网页发送键盘按键到电脑,由电脑上的输入法(如搜狗、微软拼音)处理拼音转换。
6
+
7
+ ## 快速安装
8
+
9
+ ### 方法一:pip 安装(推荐)
10
+
11
+ ```bash
12
+ # 安装
13
+ pip install screen-keyboard
14
+
15
+ # 运行
16
+ screen-keyboard
17
+ ```
18
+
19
+ ### 方法二:源码安装
20
+
21
+ ```bash
22
+ # 克隆或直接下载后
23
+ pip install -e .
24
+
25
+ # 运行
26
+ screen-keyboard
27
+ # 或
28
+ python app.py
29
+ ```
30
+
31
+ ### 方法三:一行命令安装
32
+
33
+ ```bash
34
+ curl -sL https://raw.githubusercontent.com/your-username/screen-keyboard/main/install-one-line.sh | bash
35
+ ```
36
+
37
+ ## 使用方法
38
+
39
+ ### 1. 启动服务
40
+
41
+ ```bash
42
+ screen-keyboard
43
+ # 或
44
+ python app.py
45
+ ```
46
+
47
+ ### 2. 手机访问
48
+
49
+ 服务端启动后会显示局域网地址,例如:
50
+ ```
51
+ 局域网地址:http://192.168.1.100:5000
52
+ ```
53
+
54
+ 在手机上连接同一 WiFi,用浏览器访问该地址即可。
55
+
56
+ ## 功能
57
+
58
+ - ✅ 全键盘布局(QWERTY)
59
+ - ✅ 符号/数字键盘切换
60
+ - ✅ Shift 大写切换
61
+ - ✅ 特殊按键(回车、退格、空格)
62
+ - ✅ 方向键(倒 T 布局)
63
+ - ✅ 触控板鼠标控制
64
+ - ✅ 摇杆鼠标控制
65
+ - ✅ 鼠标左右中键 + 滚轮
66
+ - ✅ Win+Space 中英文切换
67
+ - ✅ 拖动窗口/文件(双击触控板后拖动)
68
+
69
+ ## 说明
70
+
71
+ - 确保手机和电脑在同一局域网
72
+ - 电脑需开启拼音输入法
73
+ - 如果防火墙阻止,请开放 5000 端口
74
+
75
+ ## 开发
76
+
77
+ ```bash
78
+ # 创建 conda 环境
79
+ conda env create -f environment.yml
80
+ conda activate screen-keyboard
81
+
82
+ # 安装依赖
83
+ pip install -r requirements.txt
84
+
85
+ # 运行
86
+ python app.py
87
+ ```
88
+
89
+ ## License
90
+
91
+ MIT License
92
+
@@ -0,0 +1,50 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "screen-keyboard"
7
+ version = "1.0.1"
8
+ description = "手机键盘控制电脑 - 通过手机浏览器控制电脑输入"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ authors = [{name = "Your Name", email = "your-email@example.com"}]
12
+ requires-python = ">=3.8"
13
+ classifiers = [
14
+ "Development Status :: 4 - Beta",
15
+ "Intended Audience :: Developers",
16
+ "Programming Language :: Python :: 3",
17
+ "Programming Language :: Python :: 3.8",
18
+ "Programming Language :: Python :: 3.9",
19
+ "Programming Language :: Python :: 3.10",
20
+ "Programming Language :: Python :: 3.11",
21
+ "Programming Language :: Python :: 3.12",
22
+ ]
23
+ dependencies = [
24
+ "flask>=2.3.0",
25
+ "flask-socketio>=5.3.0",
26
+ "pynput>=1.7.6",
27
+ "python-socketio>=5.10.0",
28
+ "python-engineio>=4.8.0",
29
+ "simple-websocket>=1.0.0",
30
+ ]
31
+
32
+ [project.optional-dependencies]
33
+ dev = ["pytest", "black", "flake8"]
34
+
35
+ [project.scripts]
36
+ screen-keyboard = "screen_keyboard.app:main"
37
+
38
+ [project.urls]
39
+ Homepage = "https://github.com/your-username/screen-keyboard"
40
+
41
+ [tool.setuptools]
42
+ package-dir = {"" = "src"}
43
+ include-package-data = true
44
+
45
+ [tool.setuptools.packages.find]
46
+ where = ["src"]
47
+ include = ["*"]
48
+
49
+ [tool.setuptools.package-data]
50
+ "*" = ["*.html", "*.md", "*.txt"]
@@ -0,0 +1,6 @@
1
+ flask>=2.3.0
2
+ flask-socketio>=5.3.0
3
+ pynput>=1.7.6
4
+ python-socketio>=5.10.0
5
+ python-engineio>=4.8.0
6
+ evdev>=1.6.0
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,246 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ 手机键盘控制电脑 - 服务端
4
+ 使用 Flask + Socket.IO 实现 WebSocket 通信
5
+ 使用 pynput 模拟键盘输入
6
+ """
7
+
8
+ import os
9
+ import socket
10
+ from flask import Flask, send_from_directory, request
11
+ from flask_socketio import SocketIO
12
+ from pynput.keyboard import Controller, Key, KeyCode
13
+ from pynput.mouse import Controller as MouseController, Button
14
+
15
+ # 获取包所在目录
16
+ PACKAGE_DIR = os.path.dirname(os.path.abspath(__file__))
17
+
18
+ app = Flask(__name__, static_folder=PACKAGE_DIR)
19
+ app.config['SECRET_KEY'] = 'secret!'
20
+ socketio = SocketIO(app, cors_allowed_origins="*", async_mode='threading', transports=['polling', 'websocket'])
21
+
22
+ keyboard = Controller()
23
+ mouse = MouseController()
24
+
25
+
26
+ def get_local_ip():
27
+ """获取本机局域网 IP 地址"""
28
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
29
+ try:
30
+ s.connect(('10.255.255.255', 1))
31
+ ip = s.getsockname()[0]
32
+ except:
33
+ ip = '127.0.0.1'
34
+ finally:
35
+ s.close()
36
+ return ip
37
+
38
+
39
+ @app.route('/')
40
+ def index():
41
+ return send_from_directory(PACKAGE_DIR, 'index.html')
42
+
43
+
44
+ @socketio.on('connect')
45
+ def handle_connect():
46
+ print(f'客户端连接:{request.sid}')
47
+
48
+
49
+ @socketio.on('disconnect')
50
+ def handle_disconnect():
51
+ print(f'客户端断开:{request.sid}')
52
+
53
+
54
+ @socketio.on('key')
55
+ def handle_key(data):
56
+ """处理键盘按键事件"""
57
+ key = data.get('key', '')
58
+ key_type = data.get('type', 'char')
59
+
60
+ if key_type == 'special':
61
+ if not handle_special_key(key):
62
+ print(f'Unknown special key: {key}')
63
+ else:
64
+ keyboard.type(key)
65
+
66
+
67
+ @socketio.on('key_combo')
68
+ def handle_key_combo(data):
69
+ """处理组合键 (如 Ctrl+Tab、Ctrl+C、Win+Space、Ctrl+Shift+C)"""
70
+ key = data.get('key', '')
71
+ ctrl = data.get('ctrl', False)
72
+ ctrl_right = data.get('ctrl_right', False)
73
+ alt = data.get('alt', False)
74
+ alt_right = data.get('alt_right', False)
75
+ win = data.get('win', False)
76
+ shift = data.get('shift', False)
77
+ shift_right = data.get('shift_right', False)
78
+
79
+ # 构建修饰键列表
80
+ modifiers = []
81
+ if ctrl:
82
+ modifiers.append(Key.ctrl)
83
+ if ctrl_right:
84
+ modifiers.append(Key.ctrl_r)
85
+ if alt:
86
+ modifiers.append(Key.alt)
87
+ if alt_right:
88
+ modifiers.append(Key.alt_r)
89
+ if win:
90
+ modifiers.append(Key.cmd)
91
+ if shift:
92
+ modifiers.append(Key.shift)
93
+ if shift_right:
94
+ modifiers.append(Key.shift_r)
95
+
96
+ # 按顺序按下修饰键
97
+ for mod in modifiers:
98
+ keyboard.press(mod)
99
+
100
+ # 按下目标键
101
+ if len(key) == 1:
102
+ keyboard.press(key.lower())
103
+ keyboard.release(key.lower())
104
+ else:
105
+ # 特殊键
106
+ handle_special_key(key)
107
+
108
+ # 释放修饰键
109
+ for mod in reversed(modifiers):
110
+ keyboard.release(mod)
111
+
112
+
113
+ # ===== 鼠标控制 =====
114
+ @socketio.on('mouse_move')
115
+ def handle_mouse_move(data):
116
+ """处理鼠标移动"""
117
+ x = data.get('x', 0)
118
+ y = data.get('y', 0)
119
+ mouse.move(x, y)
120
+
121
+
122
+ @socketio.on('mouse_click')
123
+ def handle_mouse_click(data):
124
+ """处理鼠标点击"""
125
+ button = data.get('button', 'left')
126
+ if button == 'left':
127
+ mouse.click(Button.left)
128
+ elif button == 'right':
129
+ mouse.click(Button.right)
130
+ elif button == 'middle':
131
+ mouse.click(Button.middle)
132
+
133
+
134
+ @socketio.on('mouse_press')
135
+ def handle_mouse_press(data):
136
+ """处理鼠标按键按下/释放(用于拖动)"""
137
+ button = data.get('button', 'left')
138
+ pressed = data.get('pressed', True)
139
+ if button == 'left':
140
+ if pressed:
141
+ mouse.press(Button.left)
142
+ else:
143
+ mouse.release(Button.left)
144
+ elif button == 'right':
145
+ if pressed:
146
+ mouse.press(Button.right)
147
+ else:
148
+ mouse.release(Button.right)
149
+ elif button == 'middle':
150
+ if pressed:
151
+ mouse.press(Button.middle)
152
+ else:
153
+ mouse.release(Button.middle)
154
+
155
+
156
+ @socketio.on('mouse_scroll')
157
+ def handle_mouse_scroll(data):
158
+ """处理鼠标滚轮"""
159
+ direction = data.get('direction', 'up')
160
+ if direction == 'up':
161
+ mouse.scroll(0, 3)
162
+ else:
163
+ mouse.scroll(0, -3)
164
+
165
+
166
+ def handle_special_key(key):
167
+ """处理特殊按键"""
168
+ key_map = {
169
+ # 基础控制键
170
+ 'Enter': Key.enter,
171
+ 'Backspace': Key.backspace,
172
+ 'Space': Key.space,
173
+ 'Tab': Key.tab,
174
+ 'Escape': Key.esc,
175
+ 'CapsLock': Key.caps_lock,
176
+
177
+ # 修饰键
178
+ 'Ctrl': Key.ctrl,
179
+ 'CtrlRight': Key.ctrl_r,
180
+ 'Alt': Key.alt,
181
+ 'AltRight': Key.alt_r,
182
+ 'Shift': Key.shift,
183
+ 'ShiftRight': Key.shift_r,
184
+ 'Super': Key.cmd,
185
+ 'SuperRight': Key.cmd_r,
186
+ 'Menu': Key.menu,
187
+
188
+ # 方向键
189
+ 'ArrowUp': Key.up,
190
+ 'ArrowDown': Key.down,
191
+ 'ArrowLeft': Key.left,
192
+ 'ArrowRight': Key.right,
193
+
194
+ # 导航键
195
+ 'Insert': Key.insert,
196
+ 'Delete': Key.delete,
197
+ 'Home': Key.home,
198
+ 'End': Key.end,
199
+ 'PageUp': Key.page_up,
200
+ 'PageDown': Key.page_down,
201
+
202
+ # 功能键
203
+ 'F1': Key.f1,
204
+ 'F2': Key.f2,
205
+ 'F3': Key.f3,
206
+ 'F4': Key.f4,
207
+ 'F5': Key.f5,
208
+ 'F6': Key.f6,
209
+ 'F7': Key.f7,
210
+ 'F8': Key.f8,
211
+ 'F9': Key.f9,
212
+ 'F10': Key.f10,
213
+ 'F11': Key.f11,
214
+ 'F12': Key.f12,
215
+
216
+ # 其他
217
+ 'PrintScreen': Key.print_screen,
218
+ 'ScrollLock': Key.scroll_lock,
219
+ 'Pause': Key.pause,
220
+ }
221
+
222
+ if key in key_map:
223
+ keyboard.press(key_map[key])
224
+ keyboard.release(key_map[key])
225
+ return True
226
+ return False
227
+
228
+
229
+ def main():
230
+ """命令行入口"""
231
+ local_ip = get_local_ip()
232
+ port = 5000
233
+
234
+ print("=" * 50)
235
+ print("手机键盘控制电脑 - 服务端已启动")
236
+ print("=" * 50)
237
+ print(f"局域网地址:http://{local_ip}:{port}")
238
+ print(f"\n请在手机浏览器访问上述地址")
239
+ print("按 Ctrl+C 停止服务")
240
+ print("=" * 50)
241
+
242
+ socketio.run(app, host='0.0.0.0', port=port, debug=False, allow_unsafe_werkzeug=True)
243
+
244
+
245
+ if __name__ == '__main__':
246
+ main()