├── .gitignore
├── Client
├── Data
│ ├── config.yaml
│ ├── keyboard.yaml
│ ├── keyboard_hid2code.yaml
│ ├── keyboard_qt2hid.yaml
│ └── keycode.yaml
├── main.py
├── module
│ └── hid_def.py
├── requirements.txt
├── simple_api.py
└── ui
│ ├── device_setup.ui
│ ├── device_setup_dialog.ui
│ ├── images
│ ├── 24
│ │ ├── calculator.png
│ │ ├── fullscreen.png
│ │ ├── import.png
│ │ ├── keyboard-off.png
│ │ ├── keyboard-outline.png
│ │ ├── keyboard-settings-outline.png
│ │ ├── keyboard-variant.png
│ │ ├── keyboard.png
│ │ ├── monitor-multiple.png
│ │ ├── monitor-off.png
│ │ ├── monitor-screenshot.png
│ │ ├── monitor.png
│ │ ├── mouse-off.png
│ │ ├── mouse.png
│ │ ├── notebook-edit.png
│ │ ├── reload.png
│ │ ├── resize.png
│ │ ├── video-input-hdmi.png
│ │ ├── video-off.png
│ │ ├── video.png
│ │ ├── window-close.png
│ │ ├── window-maximize.png
│ │ └── window-minimize.png
│ └── 48
│ │ ├── camera-off.png
│ │ ├── monitor-multiple -b.png
│ │ └── monitor-multiple -l.png
│ ├── main_ui.py
│ ├── main_ui.ui
│ └── shortcut_key.ui
├── Firmware
├── Lib
│ ├── CH549.H
│ ├── DEBUG.C
│ ├── DEBUG.H
│ ├── GPIO.C
│ ├── GPIO.H
│ ├── Timer.C
│ ├── Timer.H
│ ├── UART.C
│ └── UART.H
├── ProJ.uvopt
├── ProJ.uvproj
└── User
│ └── main.C
├── LICENSE
├── PCB
├── BOM_Board1_PCB1_2022-11-08.xlsx
├── Gerber_PCB1_2022-11-08.zip
├── ProProject_KVM-over-USB_2022-11-08.zip
├── README.md
├── SCH_Schematic1_2022-11-08.pdf
└── YuzukiHCC_MS2109_Firmware.bin
├── README.md
└── document
└── images
├── 1.png
├── 2.png
├── 3.png
├── 4.png
└── 5.jpg
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | #lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | pip-wheel-metadata/
24 | share/python-wheels/
25 | *.egg-info/
26 | .installed.cfg
27 | *.egg
28 | MANIFEST
29 |
30 | # PyInstaller
31 | # Usually these files are written by a python script from a template
32 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
33 | *.manifest
34 | *.spec
35 |
36 | # Installer logs
37 | pip-log.txt
38 | pip-delete-this-directory.txt
39 |
40 | # Unit test / coverage reports
41 | htmlcov/
42 | .tox/
43 | .nox/
44 | .coverage
45 | .coverage.*
46 | .cache
47 | nosetests.xml
48 | coverage.xml
49 | *.cover
50 | *.py,cover
51 | .hypothesis/
52 | .pytest_cache/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | target/
76 |
77 | # Jupyter Notebook
78 | .ipynb_checkpoints
79 |
80 | # IPython
81 | profile_default/
82 | ipython_config.py
83 |
84 | # pyenv
85 | .python-version
86 |
87 | # pipenv
88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
91 | # install all needed dependencies.
92 | #Pipfile.lock
93 |
94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
95 | __pypackages__/
96 |
97 | # Celery stuff
98 | celerybeat-schedule
99 | celerybeat.pid
100 |
101 | # SageMath parsed files
102 | *.sage.py
103 |
104 | # Environments
105 | .env
106 | .venv
107 | env/
108 | venv/
109 | venv-linux/
110 | ENV/
111 | env.bak/
112 | venv.bak/
113 |
114 | # Spyder project settings
115 | .spyderproject
116 | .spyproject
117 |
118 | # Rope project settings
119 | .ropeproject
120 |
121 | # mkdocs documentation
122 | /site
123 |
124 | # mypy
125 | .mypy_cache/
126 | .dmypy.json
127 | dmypy.json
128 |
129 | # Pyre type checker
130 | .pyre/
131 |
132 | # --------------------------------C----------------------
133 |
134 | # Prerequisites
135 | *.d
136 |
137 | # Object files
138 | *.o
139 | *.ko
140 | *.obj
141 | *.elf
142 |
143 | # Linker output
144 | *.ilk
145 | *.map
146 | *.exp
147 |
148 | # Precompiled Headers
149 | *.gch
150 | *.pch
151 |
152 | # Libraries
153 | *.lib
154 | *.a
155 | *.la
156 | *.lo
157 |
158 | # Shared objects (inc. Windows DLLs)
159 | *.dll
160 | *.so
161 | *.so.*
162 | *.dylib
163 |
164 | # Executables
165 | *.exe
166 | *.out
167 | *.app
168 | *.i*86
169 | *.x86_64
170 | *.hex
171 |
172 | # Debug files
173 | *.dSYM/
174 | *.su
175 | *.idb
176 | *.pdb
177 |
178 | # Kernel Module Compile Results
179 | *.mod*
180 | *.cmd
181 | .tmp_versions/
182 | modules.order
183 | Module.symvers
184 | Mkfile.old
185 | dkms.conf
186 |
187 | # other
188 | *.bak
189 |
190 | # project
191 | .vscode/
192 | .idea/
193 | .idea/vcs.xml
194 | Objects/
195 | Listings/
196 |
197 | *.uvgui.*
198 |
199 | *.bat
--------------------------------------------------------------------------------
/Client/Data/config.yaml:
--------------------------------------------------------------------------------
1 | 'shortcut_key':
2 | 'shortcut_key_name':
3 | [ "Ctrl+Alt+Del",
4 | "Alt+Tab",
5 | "Ctrl+Shift+Esc",
6 | "Alt+F4",
7 | "Meta+E",
8 | "Meta+R",
9 | "Meta+PrtSc",
10 | "Meta+Break",
11 | "Shift+F10",
12 | "Alt+Space",
13 | ]
14 | 'shortcut_key_hidcode':
15 | [ [ 4,1,5,0,76,0 ], #"Ctrl+Alt+Del",
16 | [ 4,1,4,0,43,0 ], #"Alt+Tab",
17 | [ 4,1,3,0,41,0 ], #"Ctrl+Shift+Esc",
18 | [ 4,1,4,0,61,0 ], #"Alt+F4",
19 | [ 4,1,8,0,8,0 ], #"Meta+E",
20 | [ 4,1,8,0,21,0 ], #"Meta+R",
21 | [ 4,1,8,0,70,0 ], #"Meta+PrtSc"
22 | [ 4,1,8,0,72,0 ], #"Meta+Break",
23 | [ 4,1,2,0,67,0 ], #"Shift+F10",
24 | [ 4,1,4,0,44,0 ], #"Alt+Space",
25 | ]
26 | 'camera_config':
27 | 'connected': False
28 | 'device_No': 1
29 | 'resolution_X': 1360
30 | 'resolution_Y': 768
31 | 'device_name': [ ]
32 | 'config':
33 | 'mouse_jump_frame_count': 20
34 | 'hide_mouse': True
--------------------------------------------------------------------------------
/Client/Data/keyboard.yaml:
--------------------------------------------------------------------------------
1 | "A": "0X04"
2 | "B": "0X05"
3 | "C": "0X06"
4 | "D": "0X07"
5 | "E": "0X08"
6 | "F": "0X09"
7 | "G": "0X0A"
8 | "H": "0X0B"
9 | "I": "0X0C"
10 | "J": "0X0D"
11 | "K": "0X0E"
12 | "L": "0X0F"
13 | "M": "0X10"
14 | "N": "0X11"
15 | "O": "0X12"
16 | "P": "0X13"
17 | "Q": "0X14"
18 | "R": "0X15"
19 | "S": "0X16"
20 | "T": "0X17"
21 | "U": "0X18"
22 | "V": "0X19"
23 | "W": "0X1A"
24 | "X": "0X1B"
25 | "Y": "0X1C"
26 | "Z": "0X1D"
27 |
28 | "1": "0X1E"
29 | "2": "0X1F"
30 | "3": "0X20"
31 | "4": "0X21"
32 | "5": "0X22"
33 | "6": "0X23"
34 | "7": "0X24"
35 | "8": "0X25"
36 | "9": "0X26"
37 | "0": "0X27"
38 | ")": "0X27"
39 | "!": "0X1E"
40 | "@": "0X1F"
41 | "#": "0X20"
42 | "$": "0X21"
43 | "%": "0X22"
44 | "^": "0X23"
45 | "&": "0X24"
46 | "*": "0X25"
47 | "(": "0X26"
48 |
49 | "ENTER": "0X28"
50 | "ESC": "0X29"
51 | "BACKSPACE": "0X2A"
52 | "TAB": "0X2B"
53 | "SPACE": "0X2C"
54 |
55 | "Minus": "0X2D"
56 | "Equal": "0X2E"
57 | "-": "0X2D"
58 | "_": "0X2D"
59 | "=": "0X2E"
60 | "+": "0X2E"
61 |
62 | "LEFT BRACKET": "0X2F"
63 | "RIGHT BRACKET": "0X30"
64 | "BACKSLASH": "0X31"
65 | "[": "0X2F"
66 | "]": "0X30"
67 | "\\": "0X31"
68 | "{": "0X2F"
69 | "}": "0X30"
70 | "|": "0X31"
71 |
72 | "NUMBER": "0X32"
73 | "SEMICOLON": "0X33"
74 | "QUOTE": "0X34"
75 | "`": "0X32"
76 | ";": "0X33"
77 | "'": "0X34"
78 | "~": "0X32"
79 | ":": "0X33"
80 | "\"": "0X34"
81 |
82 | "BACKTICK": "0X35"
83 | "COMMA": "0X36"
84 | "PERIOD": "0X37"
85 | "SLASH": "0X38"
86 | ",": "0X36"
87 | ".": "0X37"
88 | "/": "0X38"
89 | "<": "0X36"
90 | ">": "0X37"
91 | "?": "0X38"
92 |
93 | "CAPSLOCK": "0X39"
94 | "F1": "0X3A"
95 | "F2": "0X3B"
96 | "F3": "0X3C"
97 | "F4": "0X3D"
98 | "F5": "0X3E"
99 | "F6": "0X3F"
100 | "F7": "0X40"
101 | "F8": "0X41"
102 | "F9": "0X42"
103 | "F10": "0X43"
104 | "F11": "0X44"
105 | "F12": "0X45"
106 | "PRINTSCREEN": "0X46"
107 | "SCROLLLOCK": "0X47"
108 | "PAUSE": "0X48"
109 | "INSERT": "0X49"
110 | "HOME": "0X4A"
111 | "PGUP": "0X4B"
112 | "DEL": "0X4C"
113 | "END": "0X4D"
114 | "PGDOWN": "0X4E"
115 | "RIGHT": "0X4F"
116 | "LEFT": "0X50"
117 | "DOWN": "0X51"
118 | "UP": "0X52"
119 | "NUMLOCK": "0X53"
120 | "KEYPAD SLASH": "0X54"
121 | "KEYPAD ASTERISK": "0X55"
122 | "KEYPAD MINUS": "0X56"
123 | "KEYPAD PLUS": "0X57"
124 | "KEYPAD ENTER": "0X58"
125 | "KEYPAD 1": "0X59"
126 | "KEYPAD 2": "0X5A"
127 | "KEYPAD 3": "0X5B"
128 | "KEYPAD 4": "0X5C"
129 | "KEYPAD 5": "0X5D"
130 | "KEYPAD 6": "0X5E"
131 | "KEYPAD 7": "0X5F"
132 | "KEYPAD 8": "0X60"
133 | "KEYPAD 9": "0X61"
134 | "KEYPAD 0": "0X62"
135 | "KEYPAD PERIOD": "0X63"
136 | "ISO SLASH": "0X64"
137 | "APP": "0X65"
138 | "KEYBOARD STATUS": "0X66"
139 | "KEYPAD EQUAL": "0X67"
140 | "F13": "0X68"
141 | "F14": "0X69"
142 | "F15": "0X6A"
143 | "F16": "0X6B"
144 | "F17": "0X6C"
145 | "F18": "0X6D"
146 | "F19": "0X6E"
147 | "F20": "0X6F"
148 | "F21": "0X70"
149 | "F22": "0X71"
150 | "F23": "0X72"
151 | "F24": "0X73"
152 | "EXEC": "0X74"
153 | "HELP": "0X75"
154 | "MENU": "0X76"
155 | "SELECT": "0X77"
156 | "STOP": "0X78"
157 | "AGAIN": "0X79"
158 | "UNDO": "0X7A"
159 | "CUT": "0X7B"
160 | "COPY": "0X7C"
161 | "PASTE": "0X7D"
162 | "FIND": "0X7E"
163 | "MUTE": "0X7F"
164 | "VOLUME UP": "0X80"
165 | "VOLUME DOWN": "0X81"
166 | "LOCKING CAPS LOCK": "0X82"
167 | "LOCKING NUM LOCK": "0X83"
168 | "LOCKING SCROLL LOCK": "0X84"
169 | "KEYPAD COMMA": "0X85"
170 | "KEYPAD EQUAL AS400": "0X86"
171 | "INTERNATIONAL1": "0X87"
172 | "INTERNATIONAL2": "0X88"
173 | "INTERNATIONAL3": "0X89"
174 | "INTERNATIONAL4": "0X8A"
175 | "INTERNATIONAL5": "0X8B"
176 | "INTERNATIONAL6": "0X8C"
177 | "INTERNATIONAL7": "0X8D"
178 | "INTERNATIONAL8": "0X8E"
179 | "INTERNATIONAL9": "0X8F"
180 | "LANG1": "0X90"
181 | "LANG2": "0X91"
182 | "LANG3": "0X92"
183 | "LANG4": "0X93"
184 | "LANG5": "0X94"
185 | "LANG6": "0X95"
186 | "LANG7": "0X96"
187 | "LANG8": "0X97"
188 | "LANG9": "0X98"
189 | "ALTERNATE ERASE": "0X99"
190 | "SYSREQ": "0X9A"
191 | "CANCEL": "0X9B"
192 | "CLEAR": "0X9C"
193 | "PRIOR": "0X9D"
194 | "RETURN": "0X9E"
195 | "SEPARATOR": "0X9F"
196 | "OUT": "0XA0"
197 | "OPER": "0XA1"
198 | "CLEAR AGAIN": "0XA2"
199 | "CRSEL PROPS": "0XA3"
200 | "EXSEL": "0XA4"
201 | "KEYPAD 00": "0XB0"
202 | "KEYPAD 000": "0XB1"
203 | "1000 SEPARATOR": "0XB2"
204 | "DECIMAL SEPARATOR": "0XB3"
205 | "CURRENCY UNIT": "0XB4"
206 | "CURRENCY SUBUNIT": "0XB5"
207 | "KEYPAD LEFT PARENTHESIS": "0XB6"
208 | "KEYPAD RIGHT PARENTHESIS": "0XB7"
209 | "KEYPAD LEFT BRACE": "0XB8"
210 | "KEYPAD RIGHT BRACE": "0XB9"
211 | "KEYPAD TAB": "0XBA"
212 | "KEYPAD BACKSPACE": "0XBB"
213 | "KEYPAD A": "0XBC"
214 | "KEYPAD B": "0XBD"
215 | "KEYPAD C": "0XBE"
216 | "KEYPAD D": "0XBF"
217 | "KEYPAD E": "0XC0"
218 | "KEYPAD F": "0XC1"
219 | "KEYPAD XOR": "0XC2"
220 | "KEYPAD CHEVRON": "0XC3"
221 | "KEYPAD PERCENT": "0XC4"
222 | "KEYPAD LESS THAN": "0XC5"
223 | "KEYPAD GREATER THAN": "0XC6"
224 | "KEYPAD BITAND": "0XC7"
225 | "KEYPAD AND": "0XC8"
226 | "KEYPAD BITOR": "0XC9"
227 | "KEYPAD OR": "0XCA"
228 | "KEYPAD COLON": "0XCB"
229 | "KEYPAD HASH": "0XCC"
230 | "KEYPAD SPACE": "0XCD"
231 | "KEYPAD AT": "0XCE"
232 | "KEYPAD EXCLAMATION": "0XCF"
233 | "KEYPAD MEMORY STORE": "0XD0"
234 | "KEYPAD MEMORY RECALL": "0XD1"
235 | "KEYPAD MEMORY CLEAR": "0XD2"
236 | "KEYPAD MEMORY ADD": "0XD3"
237 | "KEYPAD MEMORY SUBTRACT": "0XD4"
238 | "KEYPAD MEMORY MULTIPLY": "0XD5"
239 | "KEYPAD MEMORY DIVIDE": "0XD6"
240 | "KEYPAD PLUS MINUS": "0XD7"
241 | "KEYPAD CLEAR": "0XD8"
242 | "KEYPAD CLEAR ENTRY": "0XD9"
243 | "KEYPAD BINARY": "0XDA"
244 | "KEYPAD OCTAL": "0XDB"
245 | "KEYPAD DECIMAL": "0XDC"
246 | "KEYPAD HEXIDECIMAL": "0XDD"
247 | "LEFT CONTROL": "0XE0"
248 | "LEFT SHIFT": "0XE1"
249 | "LEFT ALT": "0XE2"
250 | "LEFT GUI": "0XE3"
251 | "RIGHT CONTROL": "0XE4"
252 | "RIGHT SHIFT": "0XE5"
253 | "RIGHT ALT": "0XE6"
254 | "RIGHT GUI": "0XE7"
--------------------------------------------------------------------------------
/Client/Data/keyboard_hid2code.yaml:
--------------------------------------------------------------------------------
1 | 0x35: 41 #text: `
2 | 0x1E: 2 #text: 1
3 | 0x1F: 3 #text: 2
4 | 0x20: 4 #text: 3
5 | 0x21: 5 #text: 4
6 | 0x22: 6 #text: 5
7 | 0x23: 7 #text: 6
8 | 0x24: 8 #text: 7
9 | 0x25: 9 #text: 8
10 | 0x26: 10 #text: 9
11 | 0x27: 11 #text: 0
12 | 0x2d: 12 #text: -
13 | 0x2e: 13 #text: =
14 | 0x2f: 26 #text: [
15 | 0x30: 27 #text: ]
16 | 0x31: 43 #text: \
17 | 0x33: 39 #text: ;
18 | 0x34: 40 #text: '
19 | 0x36: 51 #text: ,
20 | 0x37: 52 #text: .
21 | 0x38: 53 #text: /
--------------------------------------------------------------------------------
/Client/Data/keyboard_qt2hid.yaml:
--------------------------------------------------------------------------------
1 | #HID:Qt_Key
2 | 0x04: 0x41 #"A",
3 | 0x05: 0x42 #"B",
4 | 0x06: 0x43 #"C",
5 | 0x07: 0x44 #"D",
6 | 0x08: 0x45 #"E",
7 | 0x09: 0x46 #"F",
8 | 0x0A: 0x47 #"G",
9 | 0x0B: 0x48 #"H",
10 | 0x0C: 0x49 #"I",
11 | 0x0D: 0x4a #"J",
12 | 0x0E: 0x4b #"K",
13 | 0x0F: 0x4c #"L",
14 | 0x10: 0x4d #"M",
15 | 0x11: 0x4e #"N",
16 | 0x12: 0x4f #"O",
17 | 0x13: 0x50 #"P",
18 | 0x14: 0x51 #"Q",
19 | 0x15: 0x52 #"R",
20 | 0x16: 0x53 #"S",
21 | 0x17: 0x54 #"T",
22 | 0x18: 0x55 #"U",
23 | 0x19: 0x56 #"V",
24 | 0x1A: 0x57 #"W",
25 | 0x1B: 0x58 #"X",
26 | 0x1C: 0x59 #"Y",
27 | 0x1D: 0x5a #"Z",
28 | 0x1E: 0x31 #"1",
29 | 0x1F: 0x32 #"2",
30 | 0x20: 0x33 #"3",
31 | 0x21: 0x34 #"4",
32 | 0x22: 0x35 #"5",
33 | 0x23: 0x36 #"6",
34 | 0x24: 0x37 #"7",
35 | 0x25: 0x38 #"8",
36 | 0x26: 0x39 #"9",
37 | 0x27: 0x30 #"0",
38 | 0x28: 0x01000004 #"ENTER",
39 | 0x29: 0x01000000 #"ESC",
40 | 0x2A: 0x01000003 #"BACKSPACE",
41 | 0x2B: 0x01000001 #"TAB",
42 | 0x2C: 0x01000003 #"SPACE",
43 | 0x3A: 0x01000030 #"F1",
44 | 0x3B: 0x01000031 #"F2",
45 | 0x3C: 0x01000032 #"F3",
46 | 0x3D: 0x01000033 #"F4",
47 | 0x3E: 0x01000034 #"F5",
48 | 0x3F: 0x01000035 #"F6",
49 | 0x40: 0x01000036 #"F7",
50 | 0x41: 0x01000037 #"F8",
51 | 0x42: 0x01000038 #"F9",
52 | 0x43: 0x01000039 #"F10",
53 | 0x44: 0x0100003a #"F11",
54 | 0x45: 0x0100003b #"F12",
55 | 0x2D: 0x2d #"Minus",
56 | 0x2E: 0x3d #"Equal",
57 | 0x2F: 0x5b #"Left Bracket",
58 | 0x30: 0x5d #"Right Bracket",
59 | 0x31: 0x5c #"Backslash",
60 | 0x32: 0x23 #"Number",
61 | 0x33: 0x3b #"`",
62 | 0x34: 0x27 #"'",
63 | 0x35: 0x60 #"Backtick",
64 | 0x36: 0x2c #"Comma",
65 | 0x37: 0x2e #"Period",
66 | 0x38: 0x2f #"Slash",
67 | 0x39: 0x01000024 #"CapsLock",
68 | 0x46: 0x01000009 #"PrintScreen",
69 | 0x47: 0x01000026 #"ScrollLock",
70 | 0x48: 0x01000008 #"Pause",
71 | 0x49: 0x01000006 #"Insert",
72 | 0x4A: 0x01000010 #"Home",
73 | 0x4B: 0x01000016 #"PgUp",
74 | 0x4C: 0x01000007 #"Del",
75 | 0x4D: 0x01000011 #"End",
76 | 0x4E: 0x01000017 #"PgDown",
77 | 0x4F: 0x01000014 #"Right",
78 | 0x50: 0x01000012 #"Left",
79 | 0x51: 0x01000015 #"Down",
80 | 0x52: 0x01000013 #"Up",
81 | 0x53: 0x01000025 #"NumLock",
82 | 0xE0: 0x01000021 #"Left Control",
83 | 0xE1: 0x01000020 #"Left Shift",
84 | 0xE2: 0x01000023 #"Left Alt",
85 | 0xE3: 0x01000022 #"Left GUI",
86 |
87 | #0xE4: 0x01000021 #"Right Control",
88 | #0xE5: 0x01000020 #"Right Shift",
89 | #0xE6: 0x01000023 #"Right Alt",
90 | #0xE7: 0x01000022 #"Right GUI"
91 |
92 | #0X54: , #"Keypad Slash",
93 | #0X55: , #"Keypad Asterisk",
94 | #0X56: , #"Keypad Minus",
95 | #0X57: , #"Keypad Plus",
96 | #0X58: , #"Keypad Enter",
97 | #0X59: , #"Keypad 1",
98 | #0X5A: , #"Keypad 2",
99 | #0X5B: , #"Keypad 3",
100 | #0X5C: , #"Keypad 4",
101 | #0X5D: , #"Keypad 5",
102 | #0X5E: , #"Keypad 6",
103 | #0X5F: , #"Keypad 7",
104 | #0X60: , #"Keypad 8",
105 | #0X61: , #"Keypad 9",
106 | #0X62: , #"Keypad 0",
107 |
108 |
--------------------------------------------------------------------------------
/Client/Data/keycode.yaml:
--------------------------------------------------------------------------------
1 | "ESCAPE": 0x01
2 | "1": 0x02
3 | "2": 0x03
4 | "3": 0x04
5 | "4": 0x05
6 | "5": 0x06
7 | "6": 0x07
8 | "7": 0x08
9 | "8": 0x09
10 | "9": 0x0A
11 | "0": 0x0B
12 | "MINUS": 0x0C # - on main keyboard
13 | "EQUALS": 0x0D
14 | "BACK": 0x0E # backspace
15 | "TAB": 0x0F
16 | "Q": 0x10
17 | "W": 0x11
18 | "E": 0x12
19 | "R": 0x13
20 | "T": 0x14
21 | "Y": 0x15
22 | "U": 0x16
23 | "I": 0x17
24 | "O": 0x18
25 | "P": 0x19
26 | "LBRACKET": 0x1A
27 | "RBRACKET": 0x1B
28 | "RETURN": 0x1C # Enter on main keyboard
29 | "LCONTROL": 0x1D
30 | "A": 0x1E
31 | "S": 0x1F
32 | "D": 0x20
33 | "F": 0x21
34 | "G": 0x22
35 | "H": 0x23
36 | "J": 0x24
37 | "K": 0x25
38 | "L": 0x26
39 | "SEMICOLON": 0x27
40 | "APOSTROPHE": 0x28
41 | "GRAVE": 0x29 # accent grave
42 | "LSHIFT": 0x2A
43 | "BACKSLASH": 0x2B
44 | "Z": 0x2C
45 | "X": 0x2D
46 | "C": 0x2E
47 | "V": 0x2F
48 | "B": 0x30
49 | "N": 0x31
50 | "M": 0x32
51 | "COMMA": 0x33
52 | "PERIOD": 0x34 # . on main keyboard
53 | "SLASH": 0x35 # / on main keyboard
54 | "RSHIFT": 0x36
55 | "MULTIPLY": 0x37 # * on numeric keypad
56 | "LMENU": 0x38 # left Alt
57 | "SPACE": 0x39
58 | "CAPITAL": 0x3A
59 | "F1": 0x3B
60 | "F2": 0x3C
61 | "F3": 0x3D
62 | "F4": 0x3E
63 | "F5": 0x3F
64 | "F6": 0x40
65 | "F7": 0x41
66 | "F8": 0x42
67 | "F9": 0x43
68 | "F10": 0x44
69 | "NUMLOCK": 0x45
70 | "SCROLL": 0x46 # Scroll Lock
71 | "NUMPAD7": 0x47
72 | "NUMPAD8": 0x48
73 | "NUMPAD9": 0x49
74 | "SUBTRACT": 0x4A # - on numeric keypad
75 | "NUMPAD4": 0x4B
76 | "NUMPAD5": 0x4C
77 | "NUMPAD6": 0x4D
78 | "ADD": 0x4E # + on numeric keypad
79 | "NUMPAD1": 0x4F
80 | "NUMPAD2": 0x50
81 | "NUMPAD3": 0x51
82 | "NUMPAD0": 0x52
83 | "DECIMAL": 0x53 # . on numeric keypad
84 | "OEM_102": 0x56 # <> or \| on RT 102-key keyboard (Non-U.S.)
85 | "F11": 0x57
86 | "F12": 0x58
87 | "F13": 0x64 #(NEC PC98)
88 | "F14": 0x65 #(NEC PC98)
89 | "F15": 0x66 #(NEC PC98)
90 | "KANA": 0x70 # (Japanese keyboard)
91 | "ABNT_C1": 0x73 # /? on Brazilian keyboard
92 | "CONVERT": 0x79 # (Japanese keyboard)
93 | "NOCONVERT": 0x7B # (Japanese keyboard)
94 | "YEN": 0x7D # (Japanese keyboard)
95 | "ABNT_C2": 0x7E # Numpad . on Brazilian keyboard
96 | "NUMPADEQUALS": 0x8D # = on numeric keypad (NEC PC98)
97 | "PREVTRACK": 0x90 # Previous Track (DIK_CIRCUMFLEX on Japanese keyboard)
98 | "AT": 0x91 #(NEC PC98)
99 | "COLON": 0x92 #(NEC PC98)
100 | "UNDERLINE": 0x93 #(NEC PC98)
101 | "KANJI": 0x94 # (Japanese keyboard)
102 | "STOP": 0x95 #(NEC PC98)
103 | "AX": 0x96 #(Japan AX)
104 | "UNLABELED": 0x97 #(J3100)
105 | "NEXTTRACK": 0x99 # Next Track
106 | "NUMPADENTER": 0x9C # Enter on numeric keypad
107 | "RCONTROL": 0x9D
108 | "MUTE": 0xA0 # Mute
109 | "CALCULATOR": 0xA1 # Calculator
110 | "PLAYPAUSE": 0xA2 # Play / Pause
111 | "MEDIASTOP": 0xA4 # Media Stop
112 | "VOLUMEDOWN": 0xAE # Volume -
113 | "VOLUMEUP": 0xB0 # Volume +
114 | "WEBHOME": 0xB2 # Web home
115 | "NUMPADCOMMA": 0xB3 # , on numeric keypad (NEC PC98)
116 | "DIVIDE": 0xB5 # / on numeric keypad
117 | "SYSRQ": 0xB7
118 | "RMENU": 0xB8 # right Alt
119 | "PAUSE": 0xC5 # Pause
120 | "HOME": 0xC7 # Home on arrow keypad
121 | "UP": 0xC8 # UpArrow on arrow keypad
122 | "PRIOR": 0xC9 # PgUp on arrow keypad
123 | "LEFT": 0xCB # LeftArrow on arrow keypad
124 | "RIGHT": 0xCD # RightArrow on arrow keypad
125 | "END": 0xCF # End on arrow keypad
126 | "DOWN": 0xD0 # DownArrow on arrow keypad
127 | "NEXT": 0xD1 # PgDn on arrow keypad
128 | "INSERT": 0xD2 # Insert on arrow keypad
129 | "DELETE": 0xD3 # Delete on arrow keypad
130 | "LWIN": 0xDB # Left Windows key
131 | "RWIN": 0xDC # Right Windows key
132 | "APPS": 0xDD # AppMenu key
133 | "POWER": 0xDE # System Power
134 | "SLEEP": 0xDF # System Sleep
135 | "WAKE": 0xE3 # System Wake
136 | "WEBSEARCH": 0xE5 # Web Search
137 | "WEBFAVORITES": 0xE6 # Web Favorites
138 | "WEBREFRESH": 0xE7 # Web Refresh
139 | "WEBSTOP": 0xE8 # Web Stop
140 | "WEBFORWARD": 0xE9 # Web Forward
141 | "WEBBACK": 0xEA # Web Back
142 | "MYCOMPUTER": 0xEB # My Computer
143 | "MAIL": 0xEC # Mail
144 | "MEDIASELECT": 0xED # Media Select
145 |
--------------------------------------------------------------------------------
/Client/main.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys, yaml, re
3 | import time
4 |
5 | from PyQt5 import QtGui
6 | from PyQt5.QtCore import Qt
7 | from PyQt5.QtGui import QPixmap, QIcon, QCursor
8 | from PyQt5.QtMultimedia import QCameraInfo, QCamera, QCameraViewfinderSettings
9 | from PyQt5.QtMultimediaWidgets import QCameraViewfinder
10 | from PyQt5.QtWidgets import QApplication, QMainWindow, QErrorMessage, QLabel, QWidget, QDesktopWidget
11 | from PyQt5.uic import loadUi
12 |
13 | from module import hid_def
14 |
15 | from ui import main_ui
16 |
17 | buffer = [4, 1, 0, 0, 0, 0, 0, 0, 0, 0]
18 | mouse_buffer = [4, 3, 0, 0, 0, 0]
19 | mouse = [0, 0] # x1,y1
20 |
21 |
22 | class MyMainWindow(QMainWindow, main_ui.Ui_MainWindow):
23 | def __init__(self, parent=None):
24 | super(MyMainWindow, self).__init__(parent)
25 | self.setupUi(self)
26 |
27 | self.camera = None
28 |
29 | # 采集卡设备设置窗口
30 | self.device_setup_dialog = loadUi("ui/device_setup_dialog.ui")
31 | self.shortcut_key_dialog = loadUi("ui/shortcut_key.ui")
32 |
33 | # 导入外部数据
34 | with open("./Data/keyboard_qt2hid.yaml", 'r') as load_f:
35 | self.keyboard_qt2hid = yaml.safe_load(load_f)
36 | with open("./Data/keyboard_hid2code.yaml", 'r') as load_f:
37 | self.keyboard_hid2code = yaml.safe_load(load_f)
38 | with open("./Data/keyboard.yaml", 'r') as load_f:
39 | self.keyboard_hidcode = yaml.safe_load(load_f)
40 | with open("./Data/config.yaml", 'r') as load_f:
41 | self.configfile = yaml.safe_load(load_f)
42 | # 加载配置文件
43 | self.camera_config = self.configfile['camera_config']
44 | self.config = self.configfile['config']
45 | self.status = {'fullscreen': False, 'mouse_capture': False, 'mouse_jumpframe': 0}
46 |
47 | # 窗口图标
48 | self.setWindowIcon(QtGui.QIcon('ui/images/24/monitor-multiple.png'))
49 | self.device_setup_dialog.setWindowIcon(QtGui.QIcon('ui/images/24/import.png'))
50 | self.shortcut_key_dialog.setWindowIcon(QtGui.QIcon('ui/images/24/ikeyboard-settings-outline.png'))
51 |
52 | # 状态栏图标
53 | self.statusbar_lable1 = QLabel()
54 | self.statusbar_lable2 = QLabel()
55 | self.statusbar_lable3 = QLabel()
56 | self.statusbar_lable4 = QLabel()
57 | self.statusbar_lable1.setText("CTRL")
58 | self.statusbar_lable2.setText("SHIFT")
59 | self.statusbar_lable3.setText("ALT")
60 | self.statusbar_lable4.setText("META")
61 | self.statusbar_lable1.setStyleSheet('color: grey')
62 | self.statusbar_lable2.setStyleSheet('color: grey')
63 | self.statusbar_lable3.setStyleSheet('color: grey')
64 | self.statusbar_lable4.setStyleSheet('color: grey')
65 | self.statusBar().addPermanentWidget(self.statusbar_lable1)
66 | self.statusBar().addPermanentWidget(self.statusbar_lable2)
67 | self.statusBar().addPermanentWidget(self.statusbar_lable3)
68 | self.statusBar().addPermanentWidget(self.statusbar_lable4)
69 |
70 | self.statusbar_icon1 = QLabel()
71 | self.statusbar_icon2 = QLabel()
72 | self.statusbar_icon1.setPixmap(QPixmap('ui/images/24/video-off.png'))
73 | self.statusbar_icon2.setPixmap(QPixmap('ui/images/24/keyboard-off.png'))
74 | self.statusBar().addPermanentWidget(self.statusbar_icon1)
75 | self.statusBar().addPermanentWidget(self.statusbar_icon2)
76 | self.statusbar_icon1.setToolTip('Video capture card connected')
77 | self.statusbar_icon2.setToolTip('Keyboard Mouse device connected')
78 |
79 | # 菜单栏图标
80 | self.action_video_devices.setIcon(QIcon('ui/images/24/import.png'))
81 | self.action_video_device_connect.setIcon(QIcon('ui/images/24/video.png'))
82 | self.action_video_device_disconnect.setIcon(QIcon('ui/images/24/video-off.png'))
83 | self.actionMinimize.setIcon(QIcon('ui/images/24/window-minimize.png'))
84 | self.actionexit.setIcon(QIcon('ui/images/24/window-close.png'))
85 | self.actionReload_Key_Mouse.setIcon(QIcon('ui/images/24/reload.png'))
86 | self.actionfullscreen.setIcon(QIcon('ui/images/24/fullscreen.png'))
87 | self.actionResize_window.setIcon(QIcon('ui/images/24/resize.png'))
88 | self.actionResetKeyboard.setIcon(QIcon('ui/images/24/reload.png'))
89 | self.actionResetMouse.setIcon(QIcon('ui/images/24/reload.png'))
90 | self.menuShortcut_key.setIcon(QIcon('ui/images/24/keyboard-outline.png'))
91 | self.actionCustomKey.setIcon(QIcon('ui/images/24/keyboard-settings-outline.png'))
92 | self.actionCapture_mouse.setIcon(QIcon('ui/images/24/mouse.png'))
93 | self.actionRelease_mouse.setIcon(QIcon('ui/images/24/mouse-off.png'))
94 | self.actionOn_screen_Keyboard.setIcon(QIcon('ui/images/24/keyboard-variant.png'))
95 | self.actionCalculator.setIcon(QIcon('ui/images/24/calculator.png'))
96 | self.actionSnippingTool.setIcon(QIcon('ui/images/24/monitor-screenshot.png'))
97 | self.actionNotepad.setIcon(QIcon('ui/images/24/notebook-edit.png'))
98 |
99 | # 遍历相机设备
100 | cameras = QCameraInfo()
101 | for i in cameras.availableCameras():
102 | self.camera_config['device_name'].append(i.description())
103 | print(self.camera_config['device_name'])
104 |
105 | # 初始化相机
106 | self.online_webcams = QCameraInfo.availableCameras()
107 | if self.online_webcams:
108 | self.camerafinder = QCameraViewfinder()
109 | self.setCentralWidget(self.camerafinder)
110 | # set the default webcam.
111 | self.get_webcam(self.camera_config['device_No'], self.camera_config['resolution_X'],
112 | self.camera_config['resolution_Y'])
113 | self.camerafinder.show()
114 |
115 | # 快捷键菜单设置快捷键名称
116 | self.actionq1.setText(self.configfile['shortcut_key']['shortcut_key_name'][0])
117 | self.actionq2.setText(self.configfile['shortcut_key']['shortcut_key_name'][1])
118 | self.actionq3.setText(self.configfile['shortcut_key']['shortcut_key_name'][2])
119 | self.actionq4.setText(self.configfile['shortcut_key']['shortcut_key_name'][3])
120 | self.actionq5.setText(self.configfile['shortcut_key']['shortcut_key_name'][4])
121 | self.actionq6.setText(self.configfile['shortcut_key']['shortcut_key_name'][5])
122 | self.actionq7.setText(self.configfile['shortcut_key']['shortcut_key_name'][6])
123 | self.actionq_8.setText(self.configfile['shortcut_key']['shortcut_key_name'][7])
124 | self.actionq9.setText(self.configfile['shortcut_key']['shortcut_key_name'][8])
125 | self.actionq10.setText(self.configfile['shortcut_key']['shortcut_key_name'][9])
126 |
127 | # 按键绑定
128 | self.action_video_device_connect.triggered.connect(lambda: self.set_webcam(True))
129 | self.action_video_device_disconnect.triggered.connect(lambda: self.set_webcam(False))
130 | self.action_video_devices.triggered.connect(self.device_config)
131 | self.actionCustomKey.triggered.connect(self.shortcut_key_func)
132 | self.actionReload_Key_Mouse.triggered.connect(self.load_hid_device)
133 | self.actionMinimize.triggered.connect(self.window_minimized)
134 | self.actionexit.triggered.connect(sys.exit)
135 | self.device_setup_dialog.comboBox.currentIndexChanged.connect(self.update_device_setup_resolutions)
136 | self.actionfullscreen.triggered.connect(self.fullscreen_func)
137 | self.actionResize_window.triggered.connect(self.resize_window_func)
138 | self.actionRelease_mouse.triggered.connect(self.release_mouse)
139 | self.actionCapture_mouse.triggered.connect(self.capture_mouse)
140 | self.actionResetKeyboard.triggered.connect(lambda: self.reset_keymouse(1))
141 | self.actionResetMouse.triggered.connect(lambda: self.reset_keymouse(3))
142 |
143 | self.actionq1.triggered.connect(lambda: self.shortcut_key_action(0))
144 | self.actionq2.triggered.connect(lambda: self.shortcut_key_action(1))
145 | self.actionq3.triggered.connect(lambda: self.shortcut_key_action(2))
146 | self.actionq4.triggered.connect(lambda: self.shortcut_key_action(3))
147 | self.actionq5.triggered.connect(lambda: self.shortcut_key_action(4))
148 | self.actionq6.triggered.connect(lambda: self.shortcut_key_action(5))
149 | self.actionq7.triggered.connect(lambda: self.shortcut_key_action(6))
150 | self.actionq_8.triggered.connect(lambda: self.shortcut_key_action(7))
151 | self.actionq9.triggered.connect(lambda: self.shortcut_key_action(8))
152 | self.actionq10.triggered.connect(lambda: self.shortcut_key_action(9))
153 |
154 | self.actionOn_screen_Keyboard.triggered.connect(lambda: self.tools_actions(0))
155 | self.actionCalculator.triggered.connect(lambda: self.tools_actions(1))
156 | self.actionSnippingTool.triggered.connect(lambda: self.tools_actions(2))
157 | self.actionNotepad.triggered.connect(lambda: self.tools_actions(3))
158 |
159 | # 初始化hid设备
160 | self.load_hid_device()
161 | # 创建指针对象
162 | self.cursor = QCursor()
163 |
164 | # 弹出采集卡设备设置窗口,并打开采集卡设备
165 | def device_config(self):
166 | self.device_setup_dialog.comboBox.clear()
167 |
168 | # 遍历相机设备
169 | cameras = QCameraInfo()
170 | for i in cameras.availableCameras():
171 | self.camera_config['device_name'].append(i.description())
172 | self.device_setup_dialog.comboBox.addItem(i.description())
173 |
174 | # 将设备设置为字典camera_config中指定的设备
175 | self.device_setup_dialog.comboBox.setCurrentIndex(self.camera_config['device_No'])
176 | resolution_str = str(self.camera_config['resolution_X']) + 'x' + str(self.camera_config['resolution_Y'])
177 | print(resolution_str)
178 | self.device_setup_dialog.comboBox_2.setCurrentText(resolution_str)
179 |
180 | # 如果选择设备
181 | info = self.device_setup_dialog.exec()
182 |
183 | if info == 1:
184 | print(self.device_setup_dialog.comboBox.currentIndex())
185 | print(self.device_setup_dialog.comboBox_2.currentText().split('x'))
186 |
187 | self.camera_config['device_No'] = self.device_setup_dialog.comboBox.currentIndex()
188 | self.camera_config['resolution_X'] = int(self.device_setup_dialog.comboBox_2.currentText().split('x')[0])
189 | self.camera_config['resolution_Y'] = int(self.device_setup_dialog.comboBox_2.currentText().split('x')[1])
190 |
191 | print(self.camera_config)
192 |
193 | try:
194 | self.set_webcam(True)
195 | self.resize_window_func()
196 | except Exception as e:
197 | print(e)
198 |
199 | # 获取采集卡分辨率
200 | def update_device_setup_resolutions(self):
201 | self.device_setup_dialog.comboBox_2.clear()
202 | camera_info = QCamera(QCameraInfo.availableCameras()[self.device_setup_dialog.comboBox.currentIndex()])
203 | camera_info.load()
204 | for i in camera_info.supportedViewfinderResolutions():
205 | resolutions_str = str(i.width()) + 'x' + str(i.height())
206 | self.device_setup_dialog.comboBox_2.addItem(resolutions_str)
207 | print(camera_info.supportedViewfinderResolutions())
208 | camera_info.unload()
209 |
210 | # 初始化指定配置视频设备
211 | def get_webcam(self, i, x, y):
212 | self.camera = QCamera(self.online_webcams[i])
213 | # self.camera = QCamera()
214 | self.camera.setViewfinder(self.camerafinder)
215 | self.camera.setCaptureMode(QCamera.CaptureStillImage)
216 | self.camera.error.connect(lambda: self.alert(self.camera.errorString()))
217 | view_finder_settings = QCameraViewfinderSettings()
218 | view_finder_settings.setResolution(x, y)
219 | self.camera.setViewfinderSettings(view_finder_settings)
220 |
221 | if not self.status['fullscreen']:
222 | self.resize(x, y + 60)
223 | # self.camera.start()
224 |
225 | # 视频设备错误提示
226 | def alert(self, s):
227 | """
228 | This handle errors and displaying alerts.
229 | """
230 | err = QErrorMessage(self)
231 | err.showMessage(s)
232 | self.device_event_handle("video_error")
233 | print(s)
234 | print(err)
235 |
236 | # 启用和禁用视频设备
237 | def set_webcam(self, s):
238 | if s:
239 | self.device_event_handle("video_ok")
240 | self.get_webcam(self.camera_config['device_No'], self.camera_config['resolution_X'],
241 | self.camera_config['resolution_Y'])
242 | self.camera.start()
243 | # print("[debug]video device connected")
244 | self.camerafinder.setMouseTracking(True)
245 | # self.camera_config['connected'] = True
246 |
247 | else:
248 | self.device_event_handle("video_close")
249 | self.camera.stop()
250 | # print("video device disconnect")
251 | self.camerafinder.setMouseTracking(False)
252 | # self.camera_config['connected'] = False
253 |
254 | # 当相机关闭时显示图标
255 | # try:
256 | # self.setCentralWidget(self.image_label)
257 | # self.image_label.setPixmap(self.camera_off_icon)
258 | # self.image_label.setAlignment(Qt.AlignCenter)
259 | # except Exception as e:
260 | # print(e)
261 | # sys.exit(app.exec_())
262 |
263 | # 鼠标按下事件
264 | def mousePressEvent(self, event):
265 | if not self.status['mouse_capture']:
266 | return
267 | if event.button() == Qt.LeftButton:
268 | mouse_buffer[2] = mouse_buffer[2] | 1
269 | elif event.button() == Qt.RightButton:
270 | mouse_buffer[2] = mouse_buffer[2] | 2
271 | elif event.button() == Qt.MidButton:
272 | mouse_buffer[2] = mouse_buffer[2] | 4
273 |
274 | hidinfo = hid_def.hid_report(hid_def.vendor_id, hid_def.usage_page, mouse_buffer, False)
275 | if hidinfo == 1 or hidinfo == 4:
276 | self.device_event_handle("hid_error")
277 |
278 | # 鼠标松开事件
279 | def mouseReleaseEvent(self, event):
280 | if not self.status['mouse_capture']:
281 | return
282 | if event.button() == Qt.LeftButton and mouse_buffer[2] & 1:
283 | mouse_buffer[2] = mouse_buffer[2] ^ 1
284 | elif event.button() == Qt.RightButton and mouse_buffer[2] & 2:
285 | mouse_buffer[2] = mouse_buffer[2] ^ 2
286 | elif event.button() == Qt.MidButton and mouse_buffer[2] & 4:
287 | mouse_buffer[2] = mouse_buffer[2] ^ 4
288 |
289 | if mouse_buffer[2] < 0 or mouse_buffer[2] > 7:
290 | mouse_buffer[2] = 0
291 | hidinfo = hid_def.hid_report(hid_def.vendor_id, hid_def.usage_page, mouse_buffer, False)
292 | if hidinfo == 1 or hidinfo == 4:
293 | self.device_event_handle("hid_error")
294 |
295 | # 鼠标滚动事件
296 | def wheelEvent(self, event):
297 | if not self.status['mouse_capture']:
298 | return
299 | if event.angleDelta().y() == 120:
300 | mouse_buffer[5] = 0x01
301 | elif event.angleDelta().y() == -120:
302 | mouse_buffer[5] = 0xff
303 | else:
304 | mouse_buffer[5] = 0
305 | hidinfo = hid_def.hid_report(hid_def.vendor_id, hid_def.usage_page, mouse_buffer, False)
306 | if hidinfo == 1 or hidinfo == 4:
307 | self.device_event_handle("hid_error")
308 | mouse_buffer[5] = 0
309 |
310 | # 鼠标移动事件
311 | def mouseMoveEvent(self, event):
312 | if not self.status['mouse_capture']:
313 | return
314 | if self.status['mouse_jumpframe'] != 0:
315 | print("jump")
316 | self.status['mouse_jumpframe'] -= 1
317 | return
318 | # l1 = self.x() + 1
319 | # l2 = self.y() + 30
320 | # l3 = l1 + self.camerafinder.geometry().width()
321 | # l4 = l2 + self.camerafinder.geometry().height() + 30
322 | # 限制鼠标移动边界
323 | # win32api.ClipCursor((l1, l2, l3, l4))
324 |
325 | if event.x() < 100 or event.x() > self.width() - 100:
326 | x = int(self.x() + self.width() / 2)
327 | y = int(self.y() + self.height() / 2)
328 | self.cursor.setPos(x, y)
329 | # win32api.SetCursorPos((x, y))
330 | self.status['mouse_jumpframe'] = self.config['mouse_jump_frame_count']
331 | return
332 | if event.y() < 100 or event.y() > self.height() - 100:
333 | x = int(self.x() + self.width() / 2)
334 | y = int(self.y() + self.height() / 2)
335 | self.cursor.setPos(x, y)
336 | # win32api.SetCursorPos((x, y))
337 | self.status['mouse_jumpframe'] = self.config['mouse_jump_frame_count']
338 | return
339 |
340 | if mouse[0] == 0 and mouse[1] == 1:
341 | mouse[0] = event.x()
342 | mouse[1] = event.y()
343 | return
344 | else:
345 | mouse_buffer[3] = (event.x() - mouse[0]) & 0xff
346 | mouse_buffer[4] = (event.y() - mouse[1]) & 0xff
347 |
348 | hidinfo = hid_def.hid_report(hid_def.vendor_id, hid_def.usage_page, mouse_buffer, False)
349 | if hidinfo == 1 or hidinfo == 4:
350 | self.device_event_handle("hid_error")
351 |
352 | mouse_buffer[3], mouse_buffer[4] = 0, 0
353 | mouse[0] = event.x()
354 | mouse[1] = event.y()
355 |
356 | # 键盘按下事件
357 | def keyPressEvent(self, event):
358 | if event.nativeScanCode() == 285:
359 | self.release_mouse()
360 | if event.isAutoRepeat():
361 | return
362 | key = event.key()
363 | mapcode = [k for (k, v) in self.keyboard_qt2hid.items() if v == key]
364 | scancode2hid = [k for (k, v) in self.keyboard_hid2code.items() if v == event.nativeScanCode()]
365 |
366 | if mapcode:
367 | buffer[4] = mapcode[0]
368 | if scancode2hid:
369 | buffer[4] = scancode2hid[0]
370 |
371 | if key == Qt.Key_Control: # Ctrl 键被按下
372 | # print('"Control" pressed')
373 | # self.statusBar().showMessage('"Control" pressed')
374 | buffer[2] = buffer[2] | 1
375 | elif key == Qt.Key_Shift: # Shift 键被按下
376 | # print('"Shift" pressed')
377 | # self.statusBar().showMessage('"Shift" pressed')
378 | buffer[2] = buffer[2] | 2
379 | elif key == Qt.Key_Alt: # Alt 键被按下
380 | # print('"Alt" pressed')
381 | # self.statusBar().showMessage('"Alt" pressed')
382 | buffer[2] = buffer[2] | 4
383 | elif key == Qt.Key_Meta: # Meta 键被按下
384 | # print('"Meta" pressed')
385 | # self.statusBar().showMessage('"Meta" pressed')
386 | buffer[2] = buffer[2] | 8
387 | elif key == Qt.Key_Space:
388 | buffer[4] = 0x2c
389 |
390 | if buffer[2] < 0 or buffer[2] > 16:
391 | buffer[2] = 0
392 |
393 | hidinfo = hid_def.hid_report(hid_def.vendor_id, hid_def.usage_page, buffer, False)
394 | if hidinfo == 1 or hidinfo == 4:
395 | self.device_event_handle("hid_error")
396 | self.shortcut_status(buffer)
397 |
398 | '''
399 | 其它常用按键:
400 | Qt.Key_Escape,Qt.Key_Tab,Qt.Key_Backspace,Qt.Key_Return,Qt.Key_Enter,
401 | Qt.Key_Insert,Qt.Key_Delet###.Key_9,Qt.Key_Colon,Qt.Key_Semicolon,Qt.Key_Equal
402 | ...
403 | '''
404 |
405 | # 键盘松开事件
406 | def keyReleaseEvent(self, event):
407 | if event.isAutoRepeat():
408 | return
409 |
410 | key = event.key()
411 | mapcode = [k for (k, v) in self.keyboard_qt2hid.items() if v == key]
412 | scancode2hid = [k for (k, v) in self.keyboard_hid2code.items() if v == event.nativeScanCode()]
413 |
414 | if mapcode or key == Qt.Key_Space or scancode2hid:
415 | buffer[4] = 0
416 |
417 | if key == Qt.Key_Control: # Ctrl 键被释放
418 | # print('"Control" Release')
419 | # self.statusBar().showMessage('"Control" Release')
420 | if buffer[2] & 1:
421 | buffer[2] = buffer[2] ^ 1
422 | elif key == Qt.Key_Shift: # Shift 键被释放
423 | # print('"Shift" Release')
424 | # self.statusBar().showMessage('"Shift" Release')
425 | if buffer[2] & 2:
426 | buffer[2] = buffer[2] ^ 2
427 | elif key == Qt.Key_Alt: # Alt 键被释放
428 | # print('"Alt" Release')
429 | # self.statusBar().showMessage('"Alt" Release')
430 | if buffer[2] & 4:
431 | buffer[2] = buffer[2] ^ 4
432 | elif key == Qt.Key_Meta: # Meta 键被释放
433 | # print('"Meta" pressed')
434 | # self.statusBar().showMessage('"Meta" Release')
435 | if buffer[2] & 8:
436 | buffer[2] = buffer[2] ^ 8
437 |
438 | # print(buffer_release,buffer)
439 | if buffer[2] < 0 or buffer[2] > 16:
440 | buffer[2] = 0
441 |
442 | hidinfo = hid_def.hid_report(hid_def.vendor_id, hid_def.usage_page, buffer, False)
443 | if hidinfo == 1 or hidinfo == 4:
444 | self.device_event_handle("hid_error")
445 |
446 | self.shortcut_status(buffer)
447 |
448 | # 捕获鼠标功能
449 | def capture_mouse(self):
450 | if self.config['hide_mouse']:
451 | self.camerafinder.setCursor(Qt.BlankCursor)
452 | self.setMouseTracking(True)
453 | self.camerafinder.setMouseTracking(True)
454 | self.status['mouse_capture'] = True
455 |
456 | x = int(self.x() + self.width() / 2)
457 | y = int(self.y() + self.height() / 2)
458 | self.cursor.setPos(x, y)
459 |
460 | self.statusBar().showMessage("Press the RIGHT CTRL key to release the mouse")
461 |
462 | # 释放鼠标功能
463 | def release_mouse(self):
464 | self.camerafinder.setCursor(Qt.BitmapCursor)
465 | self.setMouseTracking(False)
466 | self.camerafinder.setMouseTracking(False)
467 | # win32api.ClipCursor((0, 0, 0, 0))
468 | self.status['mouse_capture'] = False
469 |
470 | # 全屏幕切换
471 | def fullscreen_func(self):
472 | self.status['fullscreen'] = ~ self.status['fullscreen']
473 | if self.status['fullscreen']:
474 | self.showFullScreen()
475 | self.actionfullscreen.setChecked(True)
476 | else:
477 | self.showNormal()
478 | self.actionfullscreen.setChecked(False)
479 |
480 | # 通过视频设备分辨率调整窗口大小
481 | def resize_window_func(self):
482 | self.resize(self.camera_config['resolution_X'], self.camera_config['resolution_Y'] + 60)
483 | qr = self.frameGeometry()
484 | cp = QDesktopWidget().availableGeometry().center()
485 | qr.moveCenter(cp)
486 | self.move(qr.topLeft())
487 |
488 | # 最小化窗口
489 | def window_minimized(self):
490 | self.showMinimized()
491 |
492 | # 重置键盘鼠标
493 | def reset_keymouse(self, s):
494 | if s == 1: # keyboard
495 | for i in range(2, len(buffer)):
496 | buffer[i] = 0
497 | print(buffer)
498 | hidinfo = hid_def.hid_report(hid_def.vendor_id, hid_def.usage_page, buffer, False)
499 | if hidinfo == 1 or hidinfo == 4:
500 | self.device_event_handle("hid_error")
501 | elif hidinfo == 0:
502 | self.device_event_handle("hid_ok")
503 | self.shortcut_status(buffer)
504 |
505 | elif s == 3: # mouse
506 | for i in range(2, len(mouse_buffer)):
507 | mouse_buffer[i] = 0
508 | print(mouse_buffer)
509 | hidinfo = hid_def.hid_report(hid_def.vendor_id, hid_def.usage_page, mouse_buffer, False)
510 | if hidinfo == 1 or hidinfo == 4:
511 | self.device_event_handle("hid_error")
512 | elif hidinfo == 0:
513 | self.device_event_handle("hid_ok")
514 |
515 | # 初始化hid设备
516 | def load_hid_device(self):
517 | hid_code = hid_def.init_usb(hid_def.vendor_id, hid_def.usage_page)
518 | if hid_code == 0:
519 | self.device_event_handle("hid_init_ok")
520 | else:
521 | self.device_event_handle("hid_init_error")
522 |
523 | # 自定义组合键窗口
524 | def shortcut_key_func(self):
525 | self.shortcut_key_dialog.pushButton_ctrl.clicked.connect(lambda: self.shortcut_key_handle(1))
526 | self.shortcut_key_dialog.pushButton_alt.clicked.connect(lambda: self.shortcut_key_handle(4))
527 | self.shortcut_key_dialog.pushButton_shift.clicked.connect(lambda: self.shortcut_key_handle(2))
528 | self.shortcut_key_dialog.pushButton_meta.clicked.connect(lambda: self.shortcut_key_handle(8))
529 | self.shortcut_key_dialog.pushButton_tab.clicked.connect(lambda: self.shortcut_key_handle(0x2b))
530 | self.shortcut_key_dialog.pushButton_prtsc.clicked.connect(lambda: self.shortcut_key_handle(0x46))
531 |
532 | self.shortcut_key_dialog.keySequenceEdit.keySequenceChanged.connect(lambda: self.shortcut_key_handle(0xff))
533 |
534 | info = self.shortcut_key_dialog.exec()
535 |
536 | if info == 1:
537 | hid_def.hid_report(hid_def.vendor_id, hid_def.usage_page, buffer, False)
538 | for i in range(2, len(buffer)):
539 | buffer[i] = 0
540 | time.sleep(0.1)
541 | hidinfo = hid_def.hid_report(hid_def.vendor_id, hid_def.usage_page, buffer, False)
542 | if hidinfo == 1 or hidinfo == 4:
543 | self.device_event_handle("hid_error")
544 |
545 | # 自定义组合键窗口按钮对应功能
546 | def shortcut_key_handle(self, s):
547 | if s == 0xff:
548 | if self.shortcut_key_dialog.keySequenceEdit.keySequence().count() == 0: # 去除多个复合键
549 | keysequence = ""
550 | elif self.shortcut_key_dialog.keySequenceEdit.keySequence().count() == 1:
551 | keysequence = self.shortcut_key_dialog.keySequenceEdit.keySequence().toString()
552 | else:
553 | keysequence = self.shortcut_key_dialog.keySequenceEdit.keySequence().toString().split(",")
554 | self.shortcut_key_dialog.keySequenceEdit.setKeySequence(keysequence[0])
555 | keysequence = keysequence[0]
556 | if keysequence == '':
557 | return
558 | shift_symbol = [")", "!", "@", "#", "$", "%", "^", "&", "*", "(", "~", "_", "+", "{", "}", "|", ":", "\"",
559 | "<", ">", "?"]
560 | if [s for s in shift_symbol if keysequence in s]:
561 | keysequence = "Shift+" + keysequence
562 |
563 | if len(re.findall("\+", keysequence)) == 0: # 没有匹配到+号,不是组合键
564 | self.shortcut_key_dialog.keySequenceEdit.setKeySequence(keysequence)
565 | else:
566 | if keysequence != '+':
567 | keysequence_list = keysequence.split("+").copy() # 将复合键转换为功能键
568 | if [s for s in keysequence_list if "Ctrl" in s]:
569 | self.shortcut_key_dialog.pushButton_ctrl.setChecked(True)
570 | buffer[2] = buffer[2] | 1
571 | else:
572 | self.shortcut_key_dialog.pushButton_ctrl.setChecked(False)
573 |
574 | if [s for s in keysequence_list if "Alt" in s]:
575 | self.shortcut_key_dialog.pushButton_alt.setChecked(True)
576 | buffer[2] = buffer[2] | 4
577 | else:
578 | self.shortcut_key_dialog.pushButton_alt.setChecked(False)
579 |
580 | if [s for s in keysequence_list if "Shift" in s]:
581 | self.shortcut_key_dialog.pushButton_shift.setChecked(True)
582 | buffer[2] = buffer[2] | 2
583 | else:
584 | self.shortcut_key_dialog.pushButton_shift.setChecked(False)
585 |
586 | self.shortcut_key_dialog.keySequenceEdit.setKeySequence(keysequence_list[-1])
587 | keysequence = keysequence_list[-1]
588 | try:
589 | mapcode = self.keyboard_hidcode[keysequence.upper()]
590 | except Exception as e:
591 | print(e)
592 | self.shortcut_key_dialog.label.setText("Hid query error")
593 | return
594 |
595 | if not mapcode:
596 | self.shortcut_key_dialog.label.setText("Hid query error")
597 | else:
598 | self.shortcut_key_dialog.label.setText("")
599 | buffer[4] = int(mapcode, 16) # 功能位
600 |
601 | if self.shortcut_key_dialog.pushButton_ctrl.isChecked() and s == 1:
602 | buffer[2] = buffer[2] | 1
603 | elif (self.shortcut_key_dialog.pushButton_ctrl.isChecked() is False) and s == 1:
604 | buffer[2] = buffer[2] & 1 and buffer[2] ^ 1
605 |
606 | if self.shortcut_key_dialog.pushButton_alt.isChecked() and s == 4:
607 | buffer[2] = buffer[2] | 4
608 | elif (self.shortcut_key_dialog.pushButton_alt.isChecked() is False) and s == 4:
609 | buffer[2] = buffer[2] & 4 and buffer[2] ^ 4
610 |
611 | if self.shortcut_key_dialog.pushButton_shift.isChecked() and s == 2:
612 | buffer[2] = buffer[2] | 2
613 | elif (self.shortcut_key_dialog.pushButton_shift.isChecked() is False) and s == 2:
614 | buffer[2] = buffer[2] & 2 and buffer[2] ^ 2
615 |
616 | if self.shortcut_key_dialog.pushButton_meta.isChecked() and s == 8:
617 | buffer[2] = buffer[2] | 8
618 | elif (self.shortcut_key_dialog.pushButton_meta.isChecked() is False) and s == 8:
619 | buffer[2] = buffer[2] & 8 and buffer[2] ^ 8
620 |
621 | if self.shortcut_key_dialog.pushButton_tab.isChecked() and s == 0x2b:
622 | buffer[8] = 0x2b
623 | elif (self.shortcut_key_dialog.pushButton_tab.isChecked() is False) and s == 0x2b:
624 | buffer[8] = 0
625 |
626 | if self.shortcut_key_dialog.pushButton_prtsc.isChecked() and s == 0x46:
627 | buffer[9] = 0x46
628 | elif (self.shortcut_key_dialog.pushButton_prtsc.isChecked() is False) and s == 0x46:
629 | buffer[9] = 0
630 |
631 | # print(buffer)
632 |
633 | # 菜单快捷键发送hid报文
634 | def shortcut_key_action(self, s):
635 | if -1 < s < 10:
636 | hid_def.hid_report(hid_def.vendor_id, hid_def.usage_page,
637 | self.configfile['shortcut_key']['shortcut_key_hidcode'][s], False)
638 | time.sleep(0.1)
639 | hidinfo = hid_def.hid_report(hid_def.vendor_id, hid_def.usage_page, [4, 1, 0, 0, 0, 0], False)
640 | if hidinfo == 1 or hidinfo == 4:
641 | self.device_event_handle("hid_error")
642 |
643 | # 设备事件处理
644 | def device_event_handle(self, s):
645 | if s == "hid_error":
646 | self.statusBar().showMessage("Keyboard Mouse connect error")
647 | self.statusbar_icon2.setPixmap(QPixmap('ui/images/24/keyboard-off.png'))
648 | self.statusbar_icon2.setToolTip('Keyboard Mouse disconnect')
649 | elif s == "video_error":
650 | self.statusBar().showMessage("Video device error")
651 | self.statusbar_icon1.setPixmap(QPixmap('ui/images/24/video-off.png'))
652 | self.statusbar_icon1.setToolTip('Video capture card disconnect')
653 | elif s == "video_close":
654 | self.statusBar().showMessage("Video device close")
655 | self.statusbar_icon1.setPixmap(QPixmap('ui/images/24/video-off.png'))
656 | self.statusbar_icon1.setToolTip('Video capture card disconnect')
657 | elif s == "hid_init_error":
658 | self.statusBar().showMessage("Keyboard Mouse initialization error")
659 | self.statusbar_icon2.setPixmap(QPixmap('ui/images/24/keyboard-off.png'))
660 | self.statusbar_icon2.setToolTip('Keyboard Mouse initialization error')
661 |
662 | if s == "hid_init_ok":
663 | self.statusBar().showMessage("Keyboard Mouse initialization done")
664 | self.statusbar_icon2.setPixmap(QPixmap('ui/images/24/keyboard.png'))
665 | self.statusbar_icon2.setToolTip('Keyboard Mouse initialization done')
666 | elif s == "hid_ok":
667 | self.statusbar_icon2.setPixmap(QPixmap('ui/images/24/keyboard.png'))
668 | self.statusBar().addPermanentWidget(self.statusbar_icon2)
669 | self.statusbar_icon2.setToolTip('Keyboard Mouse device connected')
670 | elif s == "video_ok":
671 | self.statusBar().showMessage("Video device connected")
672 | self.statusbar_icon1.setPixmap(QPixmap('ui/images/24/video.png'))
673 | self.statusbar_icon1.setToolTip('Video capture card connected')
674 |
675 | # 菜单小工具
676 | def tools_actions(self, s):
677 | if s == 0:
678 | os.popen('osk')
679 | elif s == 1:
680 | os.popen('calc')
681 | elif s == 2:
682 | os.popen('SnippingTool')
683 | elif s == 3:
684 | os.popen('notepad')
685 |
686 | # 状态栏显示组合键状态
687 | def shortcut_status(self, s):
688 | if s[2] & 1:
689 | self.statusbar_lable1.setStyleSheet('color: black')
690 | else:
691 | self.statusbar_lable1.setStyleSheet('color: grey')
692 |
693 | if s[2] & 2:
694 | self.statusbar_lable2.setStyleSheet('color: black')
695 | else:
696 | self.statusbar_lable2.setStyleSheet('color: grey')
697 |
698 | if s[2] & 4:
699 | self.statusbar_lable3.setStyleSheet('color: black')
700 | else:
701 | self.statusbar_lable3.setStyleSheet('color: grey')
702 |
703 | if s[2] & 8:
704 | self.statusbar_lable4.setStyleSheet('color: black')
705 | else:
706 | self.statusbar_lable4.setStyleSheet('color: grey')
707 |
708 |
709 | if __name__ == '__main__':
710 | app = QApplication(sys.argv)
711 | myWin = MyMainWindow()
712 | myWin.show()
713 | sys.exit(app.exec_())
714 |
--------------------------------------------------------------------------------
/Client/module/hid_def.py:
--------------------------------------------------------------------------------
1 | import hid
2 | import time
3 |
4 | vendor_id = 0x2B86
5 | usage_page = 0xFFB1
6 | product_id = 0xE6E0
7 |
8 |
9 | # 初始化HID设备
10 | def init_usb(vendor_id, usage_page):
11 | global h
12 | h = hid.device()
13 | hid_enumerate = hid.enumerate()
14 | device_path = 0
15 | for i in range(len(hid_enumerate)):
16 | if (hid_enumerate[i]['usage_page'] == usage_page and hid_enumerate[i]['vendor_id'] == vendor_id):
17 | # if (hid_enumerate[i]['usage_page'] == usage_page and hid_enumerate[i]['vendor_id'] == vendor_id and hid_enumerate[i]['product_id'] == product_id ):
18 | device_path = hid_enumerate[i]['path']
19 | if (device_path == 0): return "Device not found"
20 | h.open_path(device_path)
21 | h.set_nonblocking(1) # enable non-blocking mode
22 | return 0
23 |
24 |
25 | # 读写HID设备
26 | def hid_report(vendor_id, usage_page, buffer, rw_mode=True):
27 | print("<", buffer)
28 | try:
29 | h.write(buffer)
30 | except (OSError, ValueError):
31 | print("写入设备错误")
32 | return 1
33 | except NameError:
34 | print("未初始化设备")
35 | return 4
36 | if rw_mode: # 读取回复
37 | time_start = time.time()
38 | while 1:
39 | try:
40 | d = h.read(64)
41 | except (OSError, ValueError):
42 | print("读取数据错误")
43 | return 2
44 | if d:
45 | print(">", d)
46 | break
47 | if time.time() - time_start > 3:
48 | print("超时未回应")
49 | d = 3
50 | break
51 | else:
52 | d = 0
53 | return d
54 |
--------------------------------------------------------------------------------
/Client/requirements.txt:
--------------------------------------------------------------------------------
1 | click==7.1.2
2 | hidapi==0.12.0.post2
3 | Nuitka==1.1.7
4 | PyQt5==5.15.4
5 | pyqt5-plugins==5.15.4.2.2
6 | PyQt5-Qt5==5.15.2
7 | PyQt5-sip==12.11.0
8 | PyQt5-stubs==5.15.6.0
9 | pyqt5-tools==5.15.4.3.2
10 | python-dotenv==0.21.0
11 | pywin32==304
12 | PyYAML==6.0
13 | qt5-applications==5.15.2.2.2
14 | qt5-tools==5.15.2.1.2
15 |
--------------------------------------------------------------------------------
/Client/simple_api.py:
--------------------------------------------------------------------------------
1 | import json
2 |
3 | from flask import Flask, request
4 | from flask import jsonify
5 |
6 | import hid
7 | import time
8 |
9 | vendor_id_s = 0x2b86
10 | usage_page_s = 0xffb1
11 | # vendor_id = 11142
12 | # usage_page = 65457
13 |
14 |
15 | def init_usb(vendor_id, usage_page):
16 | global h
17 | h = hid.device()
18 | hid_enumerate = hid.enumerate()
19 | device_path = 0
20 | # print(hid_enumerate)
21 | for i in range(len(hid_enumerate)):
22 | if (hid_enumerate[i]['usage_page'] == usage_page and hid_enumerate[i]['vendor_id'] == vendor_id):
23 | device_path = hid_enumerate[i]['path']
24 | if (device_path == 0): return "Device not found"
25 | h.open_path(device_path)
26 | h.set_nonblocking(1) # enable non-blocking mode
27 |
28 |
29 | def read_report(vendor_id, usage_page, buffer):
30 | print("------")
31 | print("<", buffer)
32 | time_start = time.time()
33 | try:
34 | h.write(buffer)
35 | except (OSError, ValueError):
36 | print("写入设备错误")
37 | return 1
38 | except NameError:
39 | print("未初始化设备")
40 | return 4
41 | while 1:
42 | try:
43 | d = h.read(64)
44 | except (OSError, ValueError):
45 | print("读取数据错误")
46 | return 2
47 | if d:
48 | print(">", d)
49 | break
50 | if time.time() - time_start > 3:
51 | d = 3
52 | break
53 | print("------")
54 | return d
55 |
56 |
57 | # 新建一个应用
58 | app = Flask(__name__)
59 |
60 |
61 | # 路由(请求处理)
62 | @app.route('/', methods=['GET'])
63 | def hello():
64 | return jsonify({"msg": "hello world!"})
65 |
66 |
67 | # 初始化设备
68 | @app.route('/device_init', methods=['POST'])
69 | def device_init():
70 | global vendor_id_s
71 | global usage_page_s
72 | print(request.data.decode())
73 | data = json.loads(request.data.decode())
74 | try:
75 | vendor_id = data['vendor_id']
76 | usage_page = data['usage_page']
77 | except KeyError:
78 | vendor_id = vendor_id_s
79 | usage_page = usage_page_s
80 |
81 | # print(vendor_id, usage_page)
82 | report = init_usb(vendor_id, usage_page)
83 |
84 | if report == "Device not found":
85 | return jsonify({"msg": "device not found"})
86 | else:
87 | vendor_id_s = vendor_id
88 | usage_page_s = usage_page
89 | return jsonify({"msg": "ok"})
90 |
91 |
92 | # 关闭设备
93 | @app.route('/device_close', methods=['GET'])
94 | def device_close():
95 | try:
96 | h.close()
97 | except:
98 | return jsonify({"msg": "close error"})
99 | return jsonify({"msg": "closed"})
100 |
101 |
102 | # 写入数据
103 | @app.route('/hid_report', methods=['POST'])
104 | def hid_report():
105 | data = json.loads(request.data.decode())
106 | try:
107 | buffer = data['report']
108 | except KeyError:
109 | return jsonify({"msg": "report not found"})
110 |
111 | try:
112 | vendor_id = data['vendor_id']
113 | usage_page = data['usage_page']
114 | except KeyError:
115 | vendor_id = vendor_id_s
116 | usage_page = usage_page_s
117 |
118 | if not isinstance(buffer, list):
119 | return jsonify({"msg": "report is not list. example: [4, 3]"})
120 |
121 | print(vendor_id, usage_page, buffer)
122 |
123 | report = read_report(vendor_id, usage_page, buffer)
124 |
125 | if report == 1:
126 | return jsonify({"msg": "write error"})
127 | elif report == 2:
128 | return jsonify({"msg": "read error"})
129 | elif report == 3:
130 | return jsonify({"msg": "timeout"})
131 | elif report == 4:
132 | return jsonify({"msg": "check initialized device"})
133 | else:
134 | return jsonify({"msg": "ok"}, {"report": report})
135 |
136 |
137 | if __name__ == '__main__':
138 | # 运行参数
139 | app.run(host='0.0.0.0', port=8001, debug=True)
140 | h.close()
141 |
--------------------------------------------------------------------------------
/Client/ui/device_setup.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Form
4 |
5 |
6 |
7 | 0
8 | 0
9 | 244
10 | 75
11 |
12 |
13 |
14 | Form
15 |
16 |
17 | -
18 |
19 |
20 | -
21 |
22 |
23 | -
24 |
25 |
26 | TextLabel
27 |
28 |
29 |
30 | -
31 |
32 |
33 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok
34 |
35 |
36 |
37 | -
38 |
39 |
40 | TextLabel
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | buttonBox
50 | accepted()
51 | Form
52 | close()
53 |
54 |
55 | 144
56 | 60
57 |
58 |
59 | 121
60 | 37
61 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/Client/ui/device_setup_dialog.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 | Qt::NonModal
7 |
8 |
9 |
10 | 0
11 | 0
12 | 300
13 | 91
14 |
15 |
16 |
17 |
18 | 16777215
19 | 91
20 |
21 |
22 |
23 | Device setup
24 |
25 |
26 | Qt::LeftToRight
27 |
28 |
29 | -
30 |
31 |
32 | Resolution
33 |
34 |
35 |
36 | -
37 |
38 |
39 | Device
40 |
41 |
42 |
43 | -
44 |
45 |
46 | -
47 |
48 |
49 | false
50 |
51 |
52 |
53 | -
54 |
55 |
56 | Qt::Horizontal
57 |
58 |
59 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | buttonBox
69 | accepted()
70 | Dialog
71 | accept()
72 |
73 |
74 | 248
75 | 254
76 |
77 |
78 | 157
79 | 274
80 |
81 |
82 |
83 |
84 | buttonBox
85 | rejected()
86 | Dialog
87 | reject()
88 |
89 |
90 | 316
91 | 260
92 |
93 |
94 | 286
95 | 274
96 |
97 |
98 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/Client/ui/images/24/calculator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/Client/ui/images/24/calculator.png
--------------------------------------------------------------------------------
/Client/ui/images/24/fullscreen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/Client/ui/images/24/fullscreen.png
--------------------------------------------------------------------------------
/Client/ui/images/24/import.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/Client/ui/images/24/import.png
--------------------------------------------------------------------------------
/Client/ui/images/24/keyboard-off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/Client/ui/images/24/keyboard-off.png
--------------------------------------------------------------------------------
/Client/ui/images/24/keyboard-outline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/Client/ui/images/24/keyboard-outline.png
--------------------------------------------------------------------------------
/Client/ui/images/24/keyboard-settings-outline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/Client/ui/images/24/keyboard-settings-outline.png
--------------------------------------------------------------------------------
/Client/ui/images/24/keyboard-variant.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/Client/ui/images/24/keyboard-variant.png
--------------------------------------------------------------------------------
/Client/ui/images/24/keyboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/Client/ui/images/24/keyboard.png
--------------------------------------------------------------------------------
/Client/ui/images/24/monitor-multiple.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/Client/ui/images/24/monitor-multiple.png
--------------------------------------------------------------------------------
/Client/ui/images/24/monitor-off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/Client/ui/images/24/monitor-off.png
--------------------------------------------------------------------------------
/Client/ui/images/24/monitor-screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/Client/ui/images/24/monitor-screenshot.png
--------------------------------------------------------------------------------
/Client/ui/images/24/monitor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/Client/ui/images/24/monitor.png
--------------------------------------------------------------------------------
/Client/ui/images/24/mouse-off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/Client/ui/images/24/mouse-off.png
--------------------------------------------------------------------------------
/Client/ui/images/24/mouse.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/Client/ui/images/24/mouse.png
--------------------------------------------------------------------------------
/Client/ui/images/24/notebook-edit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/Client/ui/images/24/notebook-edit.png
--------------------------------------------------------------------------------
/Client/ui/images/24/reload.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/Client/ui/images/24/reload.png
--------------------------------------------------------------------------------
/Client/ui/images/24/resize.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/Client/ui/images/24/resize.png
--------------------------------------------------------------------------------
/Client/ui/images/24/video-input-hdmi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/Client/ui/images/24/video-input-hdmi.png
--------------------------------------------------------------------------------
/Client/ui/images/24/video-off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/Client/ui/images/24/video-off.png
--------------------------------------------------------------------------------
/Client/ui/images/24/video.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/Client/ui/images/24/video.png
--------------------------------------------------------------------------------
/Client/ui/images/24/window-close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/Client/ui/images/24/window-close.png
--------------------------------------------------------------------------------
/Client/ui/images/24/window-maximize.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/Client/ui/images/24/window-maximize.png
--------------------------------------------------------------------------------
/Client/ui/images/24/window-minimize.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/Client/ui/images/24/window-minimize.png
--------------------------------------------------------------------------------
/Client/ui/images/48/camera-off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/Client/ui/images/48/camera-off.png
--------------------------------------------------------------------------------
/Client/ui/images/48/monitor-multiple -b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/Client/ui/images/48/monitor-multiple -b.png
--------------------------------------------------------------------------------
/Client/ui/images/48/monitor-multiple -l.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/Client/ui/images/48/monitor-multiple -l.png
--------------------------------------------------------------------------------
/Client/ui/main_ui.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'main_ui.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.15.4
6 | #
7 | # WARNING: Any manual changes made to this file will be lost when pyuic5 is
8 | # run again. Do not edit this file unless you know what you are doing.
9 |
10 |
11 | from PyQt5 import QtCore, QtGui, QtWidgets
12 |
13 |
14 | class Ui_MainWindow(object):
15 | def setupUi(self, MainWindow):
16 | MainWindow.setObjectName("MainWindow")
17 | MainWindow.resize(640, 480)
18 | self.centralwidget = QtWidgets.QWidget(MainWindow)
19 | self.centralwidget.setObjectName("centralwidget")
20 | MainWindow.setCentralWidget(self.centralwidget)
21 | self.menubar = QtWidgets.QMenuBar(MainWindow)
22 | self.menubar.setGeometry(QtCore.QRect(0, 0, 640, 18))
23 | self.menubar.setObjectName("menubar")
24 | self.menu_video_menu = QtWidgets.QMenu(self.menubar)
25 | self.menu_video_menu.setObjectName("menu_video_menu")
26 | self.menuView = QtWidgets.QMenu(self.menubar)
27 | self.menuView.setObjectName("menuView")
28 | self.menuKeyboard = QtWidgets.QMenu(self.menubar)
29 | self.menuKeyboard.setObjectName("menuKeyboard")
30 | self.menuShortcut_key = QtWidgets.QMenu(self.menuKeyboard)
31 | self.menuShortcut_key.setObjectName("menuShortcut_key")
32 | self.menuMouse = QtWidgets.QMenu(self.menubar)
33 | self.menuMouse.setObjectName("menuMouse")
34 | self.menuTools = QtWidgets.QMenu(self.menubar)
35 | self.menuTools.setObjectName("menuTools")
36 | MainWindow.setMenuBar(self.menubar)
37 | self.statusbar = QtWidgets.QStatusBar(MainWindow)
38 | self.statusbar.setObjectName("statusbar")
39 | MainWindow.setStatusBar(self.statusbar)
40 | self.action_video_devices = QtWidgets.QAction(MainWindow)
41 | self.action_video_devices.setShortcut("")
42 | self.action_video_devices.setObjectName("action_video_devices")
43 | self.action_video_device_connect = QtWidgets.QAction(MainWindow)
44 | self.action_video_device_connect.setObjectName("action_video_device_connect")
45 | self.action_video_device_disconnect = QtWidgets.QAction(MainWindow)
46 | self.action_video_device_disconnect.setObjectName("action_video_device_disconnect")
47 | self.actionexit = QtWidgets.QAction(MainWindow)
48 | self.actionexit.setObjectName("actionexit")
49 | self.actionfullscreen = QtWidgets.QAction(MainWindow)
50 | self.actionfullscreen.setCheckable(True)
51 | self.actionfullscreen.setChecked(False)
52 | self.actionfullscreen.setShortcutVisibleInContextMenu(False)
53 | self.actionfullscreen.setObjectName("actionfullscreen")
54 | self.actionScreen_recording = QtWidgets.QAction(MainWindow)
55 | self.actionScreen_recording.setObjectName("actionScreen_recording")
56 | self.actionResize_window = QtWidgets.QAction(MainWindow)
57 | self.actionResize_window.setObjectName("actionResize_window")
58 | self.actionResetKeyboard = QtWidgets.QAction(MainWindow)
59 | self.actionResetKeyboard.setObjectName("actionResetKeyboard")
60 | self.actionResetMouse = QtWidgets.QAction(MainWindow)
61 | self.actionResetMouse.setObjectName("actionResetMouse")
62 | self.action_quickkey_1 = QtWidgets.QAction(MainWindow)
63 | self.action_quickkey_1.setObjectName("action_quickkey_1")
64 | self.action_quickkey_2 = QtWidgets.QAction(MainWindow)
65 | self.action_quickkey_2.setObjectName("action_quickkey_2")
66 | self.actionMinimize = QtWidgets.QAction(MainWindow)
67 | self.actionMinimize.setObjectName("actionMinimize")
68 | self.actionReload_Key_Mouse = QtWidgets.QAction(MainWindow)
69 | self.actionReload_Key_Mouse.setObjectName("actionReload_Key_Mouse")
70 | self.actionRelease_mouse = QtWidgets.QAction(MainWindow)
71 | self.actionRelease_mouse.setObjectName("actionRelease_mouse")
72 | self.actionDisplay_System_Mouse = QtWidgets.QAction(MainWindow)
73 | self.actionDisplay_System_Mouse.setObjectName("actionDisplay_System_Mouse")
74 | self.actionCapture_mouse = QtWidgets.QAction(MainWindow)
75 | self.actionCapture_mouse.setObjectName("actionCapture_mouse")
76 | self.actionCustomKey = QtWidgets.QAction(MainWindow)
77 | self.actionCustomKey.setObjectName("actionCustomKey")
78 | self.actionq1 = QtWidgets.QAction(MainWindow)
79 | self.actionq1.setObjectName("actionq1")
80 | self.actionq2 = QtWidgets.QAction(MainWindow)
81 | self.actionq2.setObjectName("actionq2")
82 | self.actionq3 = QtWidgets.QAction(MainWindow)
83 | self.actionq3.setObjectName("actionq3")
84 | self.actionq4 = QtWidgets.QAction(MainWindow)
85 | self.actionq4.setObjectName("actionq4")
86 | self.actionq5 = QtWidgets.QAction(MainWindow)
87 | self.actionq5.setObjectName("actionq5")
88 | self.actionq6 = QtWidgets.QAction(MainWindow)
89 | self.actionq6.setObjectName("actionq6")
90 | self.actionq7 = QtWidgets.QAction(MainWindow)
91 | self.actionq7.setObjectName("actionq7")
92 | self.actionq8 = QtWidgets.QAction(MainWindow)
93 | self.actionq8.setObjectName("actionq8")
94 | self.actionq_8 = QtWidgets.QAction(MainWindow)
95 | self.actionq_8.setObjectName("actionq_8")
96 | self.actionq9 = QtWidgets.QAction(MainWindow)
97 | self.actionq9.setObjectName("actionq9")
98 | self.actionq10 = QtWidgets.QAction(MainWindow)
99 | self.actionq10.setObjectName("actionq10")
100 | self.actionOn_screen_Keyboard = QtWidgets.QAction(MainWindow)
101 | self.actionOn_screen_Keyboard.setObjectName("actionOn_screen_Keyboard")
102 | self.actionCalculator = QtWidgets.QAction(MainWindow)
103 | self.actionCalculator.setObjectName("actionCalculator")
104 | self.actionSnippingTool = QtWidgets.QAction(MainWindow)
105 | self.actionSnippingTool.setObjectName("actionSnippingTool")
106 | self.actionNotepad = QtWidgets.QAction(MainWindow)
107 | self.actionNotepad.setObjectName("actionNotepad")
108 | self.menu_video_menu.addAction(self.action_video_devices)
109 | self.menu_video_menu.addAction(self.action_video_device_connect)
110 | self.menu_video_menu.addAction(self.action_video_device_disconnect)
111 | self.menu_video_menu.addSeparator()
112 | self.menu_video_menu.addAction(self.actionReload_Key_Mouse)
113 | self.menu_video_menu.addSeparator()
114 | self.menu_video_menu.addAction(self.actionMinimize)
115 | self.menu_video_menu.addAction(self.actionexit)
116 | self.menuView.addAction(self.actionfullscreen)
117 | self.menuView.addAction(self.actionResize_window)
118 | self.menuView.addSeparator()
119 | self.menuShortcut_key.addAction(self.actionq1)
120 | self.menuShortcut_key.addAction(self.actionq2)
121 | self.menuShortcut_key.addAction(self.actionq3)
122 | self.menuShortcut_key.addAction(self.actionq4)
123 | self.menuShortcut_key.addAction(self.actionq5)
124 | self.menuShortcut_key.addAction(self.actionq6)
125 | self.menuShortcut_key.addAction(self.actionq7)
126 | self.menuShortcut_key.addAction(self.actionq_8)
127 | self.menuShortcut_key.addAction(self.actionq9)
128 | self.menuShortcut_key.addAction(self.actionq10)
129 | self.menuKeyboard.addAction(self.actionResetKeyboard)
130 | self.menuKeyboard.addSeparator()
131 | self.menuKeyboard.addAction(self.menuShortcut_key.menuAction())
132 | self.menuKeyboard.addAction(self.actionCustomKey)
133 | self.menuMouse.addAction(self.actionResetMouse)
134 | self.menuMouse.addSeparator()
135 | self.menuMouse.addAction(self.actionCapture_mouse)
136 | self.menuMouse.addAction(self.actionRelease_mouse)
137 | self.menuTools.addAction(self.actionOn_screen_Keyboard)
138 | self.menuTools.addAction(self.actionCalculator)
139 | self.menuTools.addAction(self.actionSnippingTool)
140 | self.menuTools.addAction(self.actionNotepad)
141 | self.menubar.addAction(self.menu_video_menu.menuAction())
142 | self.menubar.addAction(self.menuView.menuAction())
143 | self.menubar.addAction(self.menuKeyboard.menuAction())
144 | self.menubar.addAction(self.menuMouse.menuAction())
145 | self.menubar.addAction(self.menuTools.menuAction())
146 |
147 | self.retranslateUi(MainWindow)
148 | QtCore.QMetaObject.connectSlotsByName(MainWindow)
149 |
150 | def retranslateUi(self, MainWindow):
151 | _translate = QtCore.QCoreApplication.translate
152 | MainWindow.setWindowTitle(_translate("MainWindow", "Simple USB KVM"))
153 | self.menu_video_menu.setTitle(_translate("MainWindow", "Device"))
154 | self.menuView.setTitle(_translate("MainWindow", "Video"))
155 | self.menuKeyboard.setTitle(_translate("MainWindow", "Keyboard"))
156 | self.menuShortcut_key.setTitle(_translate("MainWindow", "Shortcut key"))
157 | self.menuMouse.setTitle(_translate("MainWindow", "Mouse"))
158 | self.menuTools.setTitle(_translate("MainWindow", "Tools"))
159 | self.action_video_devices.setText(_translate("MainWindow", "Video devices"))
160 | self.action_video_device_connect.setText(_translate("MainWindow", "Connect"))
161 | self.action_video_device_disconnect.setText(_translate("MainWindow", "Disconnect"))
162 | self.actionexit.setText(_translate("MainWindow", "Exit"))
163 | self.actionfullscreen.setText(_translate("MainWindow", "Full screen"))
164 | self.actionScreen_recording.setText(_translate("MainWindow", "Screen recording"))
165 | self.actionResize_window.setText(_translate("MainWindow", "Resize window"))
166 | self.actionResetKeyboard.setText(_translate("MainWindow", "Reset"))
167 | self.actionResetMouse.setText(_translate("MainWindow", "Reset"))
168 | self.action_quickkey_1.setText(_translate("MainWindow", "Ctrl+Alt+Del"))
169 | self.action_quickkey_2.setText(_translate("MainWindow", "Alt+Tab"))
170 | self.actionMinimize.setText(_translate("MainWindow", "Minimize"))
171 | self.actionReload_Key_Mouse.setText(_translate("MainWindow", "Reload Key/Mouse"))
172 | self.actionRelease_mouse.setText(_translate("MainWindow", "Release mouse"))
173 | self.actionDisplay_System_Mouse.setText(_translate("MainWindow", "Display system mouse"))
174 | self.actionCapture_mouse.setText(_translate("MainWindow", "Capture mouse"))
175 | self.actionCustomKey.setText(_translate("MainWindow", "Custom key"))
176 | self.actionq1.setText(_translate("MainWindow", "q1"))
177 | self.actionq2.setText(_translate("MainWindow", "q2"))
178 | self.actionq3.setText(_translate("MainWindow", "q3"))
179 | self.actionq4.setText(_translate("MainWindow", "q4"))
180 | self.actionq5.setText(_translate("MainWindow", "q5"))
181 | self.actionq6.setText(_translate("MainWindow", "q6"))
182 | self.actionq7.setText(_translate("MainWindow", "q7"))
183 | self.actionq8.setText(_translate("MainWindow", "q8"))
184 | self.actionq_8.setText(_translate("MainWindow", "q8"))
185 | self.actionq9.setText(_translate("MainWindow", "q9"))
186 | self.actionq10.setText(_translate("MainWindow", "q10"))
187 | self.actionOn_screen_Keyboard.setText(_translate("MainWindow", "On-screen Keyboard"))
188 | self.actionCalculator.setText(_translate("MainWindow", "Calculator"))
189 | self.actionSnippingTool.setText(_translate("MainWindow", "SnippingTool"))
190 | self.actionNotepad.setText(_translate("MainWindow", "Notepad"))
191 |
--------------------------------------------------------------------------------
/Client/ui/main_ui.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | MainWindow
4 |
5 |
6 |
7 | 0
8 | 0
9 | 640
10 | 480
11 |
12 |
13 |
14 | Simple USB KVM
15 |
16 |
17 |
95 |
96 |
97 |
98 | Video devices
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | Connect
107 |
108 |
109 |
110 |
111 | Disconnect
112 |
113 |
114 |
115 |
116 | Exit
117 |
118 |
119 |
120 |
121 | true
122 |
123 |
124 | false
125 |
126 |
127 | Full screen
128 |
129 |
130 | false
131 |
132 |
133 |
134 |
135 | Screen recording
136 |
137 |
138 |
139 |
140 | Resize window
141 |
142 |
143 |
144 |
145 | Reset
146 |
147 |
148 |
149 |
150 | Reset
151 |
152 |
153 |
154 |
155 | Ctrl+Alt+Del
156 |
157 |
158 |
159 |
160 | Alt+Tab
161 |
162 |
163 |
164 |
165 | Minimize
166 |
167 |
168 |
169 |
170 | Reload Key/Mouse
171 |
172 |
173 |
174 |
175 | Release mouse
176 |
177 |
178 |
179 |
180 | Display system mouse
181 |
182 |
183 |
184 |
185 | Capture mouse
186 |
187 |
188 |
189 |
190 | Custom key
191 |
192 |
193 |
194 |
195 | q1
196 |
197 |
198 |
199 |
200 | q2
201 |
202 |
203 |
204 |
205 | q3
206 |
207 |
208 |
209 |
210 | q4
211 |
212 |
213 |
214 |
215 | q5
216 |
217 |
218 |
219 |
220 | q6
221 |
222 |
223 |
224 |
225 | q7
226 |
227 |
228 |
229 |
230 | q8
231 |
232 |
233 |
234 |
235 | q8
236 |
237 |
238 |
239 |
240 | q9
241 |
242 |
243 |
244 |
245 | q10
246 |
247 |
248 |
249 |
250 | On-screen Keyboard
251 |
252 |
253 |
254 |
255 | Calculator
256 |
257 |
258 |
259 |
260 | SnippingTool
261 |
262 |
263 |
264 |
265 | Notepad
266 |
267 |
268 |
269 |
270 |
271 |
272 |
--------------------------------------------------------------------------------
/Client/ui/shortcut_key.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 252
10 | 107
11 |
12 |
13 |
14 | Custom Key
15 |
16 |
17 | -
18 |
19 |
20 | Prt Sc
21 |
22 |
23 | true
24 |
25 |
26 |
27 | -
28 |
29 |
30 | Qt::Horizontal
31 |
32 |
33 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok
34 |
35 |
36 |
37 | -
38 |
39 |
40 | Ctrl
41 |
42 |
43 | true
44 |
45 |
46 | false
47 |
48 |
49 |
50 | -
51 |
52 |
53 | Tab
54 |
55 |
56 | true
57 |
58 |
59 |
60 | -
61 |
62 |
63 | -
64 |
65 |
66 | Shift
67 |
68 |
69 | true
70 |
71 |
72 |
73 | -
74 |
75 |
76 | Meta
77 |
78 |
79 | true
80 |
81 |
82 |
83 | -
84 |
85 |
86 | Alt
87 |
88 |
89 | true
90 |
91 |
92 |
93 | -
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 | buttonBox
106 | accepted()
107 | Dialog
108 | accept()
109 |
110 |
111 | 248
112 | 254
113 |
114 |
115 | 157
116 | 274
117 |
118 |
119 |
120 |
121 | buttonBox
122 | rejected()
123 | Dialog
124 | reject()
125 |
126 |
127 | 316
128 | 260
129 |
130 |
131 | 286
132 | 274
133 |
134 |
135 |
136 |
137 |
138 |
--------------------------------------------------------------------------------
/Firmware/Lib/DEBUG.C:
--------------------------------------------------------------------------------
1 | /********************************** (C) COPYRIGHT *******************************
2 | * File Name : DEBUG.C
3 | * Author : WCH
4 | * Version : V1.0
5 | * Date : 2018/09/20
6 | * Description : CH5XX DEBUG Interface
7 | (1)、主频设置;
8 | (2)、us\ms基本延时函数;
9 | (3)、串口0输出打印信息,波特率可调;
10 | (4)、看门狗初始化和赋值函数;
11 | *******************************************************************************/
12 |
13 | #include "CH549.H"
14 | #include "DEBUG.H"
15 |
16 | /*******************************************************************************
17 | * Function Name : CfgFsys( )
18 | * Description : CH5XX时钟选择和配置函数,默认使用内部晶振24MHz,如果定义了FREQ_SYS可以
19 | 根据PLL_CFG和CLOCK_CFG配置得到,公式如下:
20 | Fsys = (Fosc * ( PLL_CFG & MASK_PLL_MULT ))/(CLOCK_CFG & MASK_SYS_CK_DIV);
21 | 具体时钟需要自己配置
22 | * Input : None
23 | * Output : None
24 | * Return : None
25 | *******************************************************************************/
26 | void CfgFsys( )
27 | {
28 | #if OSC_EN_XT
29 | SAFE_MOD = 0x55;
30 | SAFE_MOD = 0xAA;
31 | CLOCK_CFG |= bOSC_EN_XT; //使能外部晶振
32 | CLOCK_CFG &= ~bOSC_EN_INT; //关闭内部晶振
33 | #else
34 | SAFE_MOD = 0x55;
35 | SAFE_MOD = 0xAA;
36 | CLOCK_CFG |= bOSC_EN_INT; //使能内部晶振
37 | CLOCK_CFG &= ~bOSC_EN_XT; //关闭外部晶振
38 | #endif
39 | SAFE_MOD = 0x55;
40 | SAFE_MOD = 0xAA;
41 | #if FREQ_SYS == 48000000
42 | CLOCK_CFG = CLOCK_CFG & ~ MASK_SYS_CK_SEL | 0x07; // 48MHz
43 | #endif
44 | #if FREQ_SYS == 32000000
45 | CLOCK_CFG = CLOCK_CFG & ~ MASK_SYS_CK_SEL | 0x06; // 32MHz
46 | #endif
47 | #if FREQ_SYS == 24000000
48 | CLOCK_CFG = CLOCK_CFG & ~ MASK_SYS_CK_SEL | 0x05; // 24MHz
49 | #endif
50 | #if FREQ_SYS == 16000000
51 | CLOCK_CFG = CLOCK_CFG & ~ MASK_SYS_CK_SEL | 0x04; // 16MHz
52 | #endif
53 | #if FREQ_SYS == 12000000
54 | CLOCK_CFG = CLOCK_CFG & ~ MASK_SYS_CK_SEL | 0x03; // 12MHz
55 | #endif
56 | #if FREQ_SYS == 3000000
57 | CLOCK_CFG = CLOCK_CFG & ~ MASK_SYS_CK_SEL | 0x02; // 3MHz
58 | #endif
59 | #if FREQ_SYS == 750000
60 | CLOCK_CFG = CLOCK_CFG & ~ MASK_SYS_CK_SEL | 0x01; // 750KHz
61 | #endif
62 | #if FREQ_SYS == 187500
63 | CLOCK_CFG = CLOCK_CFG & ~ MASK_SYS_CK_SEL | 0x00; // 187.5KHz
64 | #endif
65 | SAFE_MOD = 0x00;
66 | }
67 |
68 | /*******************************************************************************
69 | * Function Name : mDelayus(UNIT16 n)
70 | * Description : us延时函数
71 | * Input : UNIT16 n
72 | * Output : None
73 | * Return : None
74 | *******************************************************************************/
75 | void mDelayuS( UINT16 n ) // 以uS为单位延时
76 | {
77 | while ( n ) // total = 12~13 Fsys cycles, 1uS @Fsys=12MHz
78 | {
79 | ++ SAFE_MOD; // 2 Fsys cycles, for higher Fsys, add operation here
80 | #ifdef FREQ_SYS
81 | #if FREQ_SYS >= 14000000
82 | ++ SAFE_MOD;
83 | #endif
84 | #if FREQ_SYS >= 16000000
85 | ++ SAFE_MOD;
86 | #endif
87 | #if FREQ_SYS >= 18000000
88 | ++ SAFE_MOD;
89 | #endif
90 | #if FREQ_SYS >= 20000000
91 | ++ SAFE_MOD;
92 | #endif
93 | #if FREQ_SYS >= 22000000
94 | ++ SAFE_MOD;
95 | #endif
96 | #if FREQ_SYS >= 24000000
97 | ++ SAFE_MOD;
98 | #endif
99 | #if FREQ_SYS >= 26000000
100 | ++ SAFE_MOD;
101 | #endif
102 | #if FREQ_SYS >= 28000000
103 | ++ SAFE_MOD;
104 | #endif
105 | #if FREQ_SYS >= 30000000
106 | ++ SAFE_MOD;
107 | #endif
108 | #if FREQ_SYS >= 32000000
109 | ++ SAFE_MOD;
110 | #endif
111 | #if FREQ_SYS >= 34000000
112 | ++ SAFE_MOD;
113 | #endif
114 | #if FREQ_SYS >= 36000000
115 | ++ SAFE_MOD;
116 | #endif
117 | #if FREQ_SYS >= 38000000
118 | ++ SAFE_MOD;
119 | #endif
120 | #if FREQ_SYS >= 40000000
121 | ++ SAFE_MOD;
122 | #endif
123 | #if FREQ_SYS >= 42000000
124 | ++ SAFE_MOD;
125 | #endif
126 | #if FREQ_SYS >= 44000000
127 | ++ SAFE_MOD;
128 | #endif
129 | #if FREQ_SYS >= 46000000
130 | ++ SAFE_MOD;
131 | #endif
132 | #if FREQ_SYS >= 48000000
133 | ++ SAFE_MOD;
134 | #endif
135 | #if FREQ_SYS >= 50000000
136 | ++ SAFE_MOD;
137 | #endif
138 | #if FREQ_SYS >= 52000000
139 | ++ SAFE_MOD;
140 | #endif
141 | #if FREQ_SYS >= 54000000
142 | ++ SAFE_MOD;
143 | #endif
144 | #if FREQ_SYS >= 56000000
145 | ++ SAFE_MOD;
146 | #endif
147 | #endif
148 | -- n;
149 | }
150 | }
151 |
152 | /*******************************************************************************
153 | * Function Name : mDelayms(UNIT16 n)
154 | * Description : ms延时函数
155 | * Input : UNIT16 n
156 | * Output : None
157 | * Return : None
158 | *******************************************************************************/
159 | void mDelaymS( UINT16 n ) // 以mS为单位延时
160 | {
161 | while ( n )
162 | {
163 | mDelayuS( 1000 );
164 | -- n;
165 | }
166 | }
167 |
168 | /*******************************************************************************
169 | * Function Name : CH549UART0Alter()
170 | * Description : CH549串口0引脚映射,串口映射到P0.2(R)和P0.3(T)
171 | * Input : None
172 | * Output : None
173 | * Return : None
174 | *******************************************************************************/
175 | void CH549UART0Alter()
176 | {
177 | P0_MOD_OC |= (3 << 2); //准双向模式
178 | P0_DIR_PU |= (3 << 2);
179 | PIN_FUNC |= bUART0_PIN_X; //开启引脚复用功能
180 | }
181 |
182 | /*******************************************************************************
183 | * Function Name : mInitSTDIO()
184 | * Description : CH559串口0初始化,默认使用T1作UART0的波特率发生器,也可以使用T2
185 | 作为波特率发生器
186 | * Input : None
187 | * Output : None+
188 | * Return : None
189 | *******************************************************************************/
190 | void mInitSTDIO( )
191 | {
192 | UINT32 x;
193 | UINT8 x2;
194 |
195 | SM0 = 0;
196 | SM1 = 1;
197 | SM2 = 0; //串口0使用模式1
198 | //使用Timer1作为波特率发生器
199 | RCLK = 0; //UART0接收时钟
200 | TCLK = 0; //UART0发送时钟
201 | PCON |= SMOD;
202 | x = 10 * FREQ_SYS / UART0BUAD / 16; //如果更改主频,注意x的值不要溢出
203 | x2 = x % 10;
204 | x /= 10;
205 |
206 | if ( x2 >= 5 ) x ++; //四舍五入
207 |
208 | TMOD = TMOD & ~ bT1_GATE & ~ bT1_CT & ~ MASK_T1_MOD | bT1_M1; //0X20,Timer1作为8位自动重载定时器
209 | T2MOD = T2MOD | bTMR_CLK | bT1_CLK; //Timer1时钟选择
210 | TH1 = 0 - x; //12MHz晶振,buad/12为实际需设置波特率
211 | TR1 = 1; //启动定时器1
212 | TI = 1;
213 | REN = 1; //串口0接收使能
214 |
215 | // #ifdef UART0_INTERRUPT
216 | // ES = 1; //串口0中断使能
217 | // #endif
218 | }
219 |
220 | /*******************************************************************************
221 | * Function Name : CH549SoftReset()
222 | * Description : CH549软复位
223 | * Input : None
224 | * Output : None
225 | * Return : None
226 | *******************************************************************************/
227 | void CH549SoftReset( )
228 | {
229 | SAFE_MOD = 0x55;
230 | SAFE_MOD = 0xAA;
231 | GLOBAL_CFG |= bSW_RESET;
232 | }
233 | /*******************************************************************************
234 | * Function Name : CH549WDTModeSelect(UINT8 mode)
235 | * Description : CH549看门狗模式选择
236 | * 8位计数器,溢出周期(秒): (131072/FREQ_SYS)*(256-WDOG_COUNT)
237 | * Input : UINT8 mode
238 | 0 timer
239 | 1 watchDog
240 | * Output : None
241 | * Return : None
242 | *******************************************************************************/
243 | void CH549WDTModeSelect(UINT8 mode)
244 | {
245 | SAFE_MOD = 0x55;
246 | SAFE_MOD = 0xaa; //进入安全模式
247 |
248 | if(mode)
249 | {
250 | GLOBAL_CFG |= bWDOG_EN; //启动看门狗复位
251 | }
252 | else GLOBAL_CFG &= ~bWDOG_EN; //启动看门狗仅仅作为定时器
253 |
254 | SAFE_MOD = 0x00; //退出安全模式
255 | WDOG_COUNT = 0; //看门狗赋初值
256 | }
257 |
258 | /*******************************************************************************
259 | * Function Name : CH549WDTFeed(UINT8 tim)
260 | * Description : CH549看门狗定时时间设置
261 | * Input : UINT8 tim 看门狗复位时间设置
262 | 00H(12MHz)=2.8s 00H(24MHz)=1.4s
263 | 80H(12MHz)=1.4s 80H(24MHz)=0.7s
264 | * Output : None
265 | * Return : None
266 | *******************************************************************************/
267 | void CH549WDTFeed(UINT8 tim)
268 | {
269 | WDOG_COUNT = tim; //看门狗计数器赋值
270 | }
271 |
272 |
273 |
274 | /*******************************************************************************
275 | * Function Name : CH549UART0RcvByte()
276 | * Description : CH549UART0接收一个字节
277 | * Input : None
278 | * Output : None
279 | * Return : SBUF
280 | *******************************************************************************/
281 | UINT8 CH549UART0RcvByte( )
282 | {
283 | while(RI == 0); //查询接收,中断方式可不用
284 | RI = 0;
285 | return SBUF;
286 | }
287 |
288 | /*******************************************************************************
289 | * Function Name : CH549UART0SendByte(UINT8 SendDat)
290 | * Description : CH549UART0发送一个字节
291 | * Input : UINT8 SendDat;要发送的数据
292 | * Output : None
293 | * Return : None
294 | *******************************************************************************/
295 | void CH549UART0SendByte(char SendDat)
296 | {
297 | SBUF = SendDat;
298 | while(TI!=1); //等待发送成功
299 | TI = 0; //清除发送完成中断
300 | }
301 | //重写putchar函数
302 | //printf函数是调用putchar实现字符数据传送的
303 | char putchar(char c)
304 | {
305 | CH549UART0SendByte(c);
306 | return c;
307 | }
--------------------------------------------------------------------------------
/Firmware/Lib/DEBUG.H:
--------------------------------------------------------------------------------
1 | /* 调试 */
2 | /* 提供printf子程序和延时函数 */
3 |
4 | #ifndef __DEBUG_H__
5 | #define __DEBUG_H__
6 |
7 | #include
8 | #include
9 |
10 | //定义函数返回值
11 | #ifndef SUCCESS
12 | #define SUCCESS 1
13 | #endif
14 | #ifndef FAIL
15 | #define FAIL 0
16 | #endif
17 |
18 | //定义定时器起始
19 | #ifndef START
20 | #define START 1
21 | #endif
22 | #ifndef STOP
23 | #define STOP 0
24 | #endif
25 |
26 | #ifndef DE_PRINTF //调试开关
27 | #define DE_PRINTF 1
28 | #endif
29 |
30 | //#define FREQ_SYS 24000000 //系统主频24MHz
31 | #define FREQ_SYS 48000000 //系统主频48MHz
32 | #define OSC_EN_XT 0 //外部晶振使能,默认开启内部晶振
33 |
34 | #ifndef UART0BUAD
35 | #define UART0BUAD 115200
36 | #endif
37 |
38 |
39 | #define UART0_INTERRUPT 0 //定义是否开启串口0中断
40 |
41 |
42 | void CfgFsys( ); // CH549时钟选择和配置
43 | void mDelayuS( UINT16 n ); // 以uS为单位延时
44 | void mDelaymS( UINT16 n ); // 以mS为单位延时
45 | void CH559UART0Alter(); // CH549串口0引脚映射到P0.2/P0.3
46 | void mInitSTDIO( ); // T1作为波特率发生器
47 | void CH549SoftReset( ); // CH549软复位
48 | void CH549WDTModeSelect(UINT8 mode); // 看门狗模式选择
49 | void CH549WDTFeed(UINT8 tim); // 喂狗
50 |
51 | extern UINT8 CH549UART0RcvByte( ); //UART0接收一个字节
52 | extern void CH549UART0SendByte(UINT8 SendDat); //UART-发送一个字节
53 |
54 |
55 |
56 | #endif
57 |
--------------------------------------------------------------------------------
/Firmware/Lib/GPIO.C:
--------------------------------------------------------------------------------
1 | /********************************** (C) COPYRIGHT *******************************
2 | * File Name : GPIO.C
3 | * Author : WCH
4 | * Version : V1.0
5 | * Date : 2018/08/09
6 | * Description : CH549 GPIO相关函数
7 | *******************************************************************************/
8 | #include "GPIO.H"
9 | #pragma NOAREGS
10 | /*******************************************************************************
11 | * Function Name : GPIO_Init(UINT8 PORTx,UINT8 PINx,UINT8 MODEx)
12 | * Description : GPIO端口初始化函数
13 | * Input : PORTx:0~4
14 | * PINx:位域,每个位对应该Port的一个引脚
15 | * MODEx:
16 | * 0:高阻输入模式,引脚没有上拉电阻
17 | * 1:推挽输出模式,具有对称驱动能力,可以输出或者吸收较大电流
18 | * 2:开漏输出,支持高阻输入,引脚没有上拉电阻
19 | * 3:准双向模式(标准 8051),开漏输出,支持输入,引脚有上拉电阻(默认模式)
20 | * Output : None
21 | * Return : None
22 | *******************************************************************************/
23 | void GPIO_Init(UINT8 PORTx, UINT8 PINx, UINT8 MODEx)
24 | {
25 | UINT8 Px_DIR_PU, Px_MOD_OC;
26 |
27 | switch(PORTx) //读出初始值
28 | {
29 | case PORT0:
30 | Px_MOD_OC = P0_MOD_OC;
31 | Px_DIR_PU = P0_DIR_PU;
32 | break;
33 |
34 | case PORT1:
35 | Px_MOD_OC = P1_MOD_OC;
36 | Px_DIR_PU = P1_DIR_PU;
37 | break;
38 |
39 | case PORT2:
40 | Px_MOD_OC = P2_MOD_OC;
41 | Px_DIR_PU = P2_DIR_PU;
42 | break;
43 |
44 | case PORT3:
45 | Px_MOD_OC = P3_MOD_OC;
46 | Px_DIR_PU = P3_DIR_PU;
47 | break;
48 |
49 | case PORT4:
50 | Px_MOD_OC = P4_MOD_OC;
51 | Px_DIR_PU = P4_DIR_PU;
52 | break;
53 |
54 | default :
55 | break;
56 | }
57 |
58 | switch(MODEx)
59 | {
60 | case MODE0: //高阻输入模式,引脚没有上拉电阻
61 | Px_MOD_OC &= ~PINx;
62 | Px_DIR_PU &= ~PINx;
63 | break;
64 |
65 | case MODE1: //推挽输出模式,具有对称驱动能力,可以输出或者吸收较大电流
66 | Px_MOD_OC &= ~PINx;
67 | Px_DIR_PU |= PINx;
68 | break;
69 |
70 | case MODE2: //开漏输出,支持高阻输入,引脚没有上拉电阻
71 | Px_MOD_OC |= PINx;
72 | Px_DIR_PU &= ~PINx;
73 | break;
74 |
75 | case MODE3: //准双向模式(标准 8051),开漏输出,支持输入,引脚有上拉电阻
76 | Px_MOD_OC |= PINx;
77 | Px_DIR_PU |= PINx;
78 | break;
79 |
80 | default :
81 | break;
82 | }
83 |
84 | switch(PORTx) //回写
85 | {
86 | case PORT0:
87 | P0_MOD_OC = Px_MOD_OC;
88 | P0_DIR_PU = Px_DIR_PU;
89 | break;
90 |
91 | case PORT1:
92 | P1_MOD_OC = Px_MOD_OC;
93 | P1_DIR_PU = Px_DIR_PU;
94 | break;
95 |
96 | case PORT2:
97 | P2_MOD_OC = Px_MOD_OC;
98 | P2_DIR_PU = Px_DIR_PU;
99 | break;
100 |
101 | case PORT3:
102 | P3_MOD_OC = Px_MOD_OC;
103 | P3_DIR_PU = Px_DIR_PU;
104 | break;
105 |
106 | case PORT4:
107 | P4_MOD_OC = Px_MOD_OC;
108 | P4_DIR_PU = Px_DIR_PU;
109 | break;
110 |
111 | default :
112 | break;
113 | }
114 | }
115 | /*******************************************************************************
116 | * Function Name : GPIO_INT_Init
117 | * Description : 可设置 RXD1_L、P15_L、P14_L、P03_L、P57_H、P46_L、RXD0_L 扩展引脚的外部中断
118 | * 同时还包含兼容C51的 INT1_L、INT0_L 的外部中断触发
119 | * (RXD1_L、RXD0_L具体是哪个引脚取决于引脚是否映射)
120 | * Input : IntSrc:共9个外部中断,按位域表示,具体定义见GPIO.H
121 | * Mode:0:电平模式 1:边沿模式 (注意扩展引脚的中断模式是统一配置的)
122 | * NewState:0:关闭对应外部中断使能 1:开启对应外部中断
123 | * Output : None
124 | * Return : None
125 | *******************************************************************************/
126 | void GPIO_INT_Init( UINT16 IntSrc, UINT8 Mode, UINT8 NewState )
127 | {
128 | /* 中断触发模式设置 */
129 | if(Mode == INT_EDGE) //边沿触发模式
130 | {
131 | if(IntSrc & 0x7F) //存在扩展中断
132 | {
133 | GPIO_IE |= bIE_IO_EDGE;
134 | }
135 |
136 | if(IntSrc & INT_INT0_L) //存在外部中断0
137 | {
138 | IT0 = 1;
139 | }
140 |
141 | if(IntSrc & INT_INT1_L) //存在外部中断1
142 | {
143 | IT1 = 1;
144 | }
145 | }
146 | else //电平触发模式
147 | {
148 | if(IntSrc & 0x7F) //存在扩展中断
149 | {
150 | GPIO_IE &= ~bIE_IO_EDGE;
151 | }
152 |
153 | if(IntSrc & INT_INT0_L) //存在外部中断0
154 | {
155 | IT0 = 1;
156 | }
157 |
158 | if(IntSrc & INT_INT1_L) //存在外部中断1
159 | {
160 | IT1 = 1;
161 | }
162 | }
163 |
164 | /* 中断使能状态 */
165 | if(NewState == Enable) //开启外部中断
166 | {
167 | GPIO_IE |= ((UINT8)IntSrc & 0x7F);
168 |
169 | if(IntSrc & INT_INT0_L) //存在外部中断0
170 | {
171 | EX0 = 1;
172 | }
173 |
174 | if(IntSrc & INT_INT1_L) //存在外部中断1
175 | {
176 | EX1 = 1;
177 | }
178 |
179 | if(GPIO_IE & 0x7F)
180 | {
181 | IE_GPIO = 1; //开启扩展GPIO中断
182 | }
183 |
184 | EA = 1; //开启总中断
185 | }
186 | else //关闭对应外部中断
187 | {
188 | GPIO_IE &= ~((UINT8)IntSrc & 0x7F);
189 |
190 | if(IntSrc & INT_INT0_L) //存在外部中断0
191 | {
192 | EX0 = 0;
193 | }
194 |
195 | if(IntSrc & INT_INT1_L) //存在外部中断1
196 | {
197 | EX1 = 0;
198 | }
199 |
200 | if((GPIO_IE & 0x7F) == 0)
201 | {
202 | IE_GPIO = 0; //关闭扩展GPIO中断
203 | }
204 | }
205 | }
206 | /*******************************************************************************
207 | * Function Name : GPIO_ISR
208 | * Description : RXD1、P15、P14、P03、P57、P46、RXD0 引脚外部中断服务函数
209 | * Input : None
210 | * Output : None
211 | * Return : None
212 | *******************************************************************************/
213 | void GPIO_EXT_ISR(void) interrupt INT_NO_GPIO
214 | {
215 | if(AIN11 == 0)
216 | {
217 | mDelaymS(10);
218 | printf("P03 Falling\n");
219 | }
220 |
221 | if(AIN5 == 0)
222 | {
223 | mDelaymS(10);
224 | printf("P15 Falling\n");
225 | }
226 |
227 |
228 | }
229 | /*******************************************************************************
230 | * Function Name : GPIO_STD0_ISR
231 | * Description : INT0(P32) 引脚外部中断服务函数
232 | * Input : None
233 | * Output : None
234 | * Return : None
235 | *******************************************************************************/
236 | void GPIO_STD0_ISR(void) interrupt INT_NO_INT0
237 | {
238 | mDelaymS(10);
239 | printf("P32 Falling\n");
240 |
241 | }
242 | /*******************************************************************************
243 | * Function Name : GPIO_STD1_ISR
244 | * Description : INT1(P33) 引脚外部中断服务函数
245 | * Input : None
246 | * Output : None
247 | * Return : None
248 | *******************************************************************************/
249 | void GPIO_STD1_ISR(void) interrupt INT_NO_INT1
250 | {
251 | mDelaymS(10);
252 | printf("P33 Falling\n");
253 |
254 | }
255 |
--------------------------------------------------------------------------------
/Firmware/Lib/GPIO.H:
--------------------------------------------------------------------------------
1 | #ifndef __GPIO_H__
2 | #define __GPIO_H__
3 | #include "CH549.H"
4 | #include "DEBUG.H"
5 | /****************** GPIO_Init 参数定义 ******************/
6 | /* 端口定义 */
7 | #define PORT0 0x00
8 | #define PORT1 0x01
9 | #define PORT2 0x02
10 | #define PORT3 0x03
11 | #define PORT4 0x04
12 | /* 引脚定义(可以组合) */
13 | #define PIN0 0x01
14 | #define PIN1 0x02
15 | #define PIN2 0x04
16 | #define PIN3 0x08
17 | #define PIN4 0x10
18 | #define PIN5 0x20
19 | #define PIN6 0x40
20 | #define PIN7 0x80
21 | /* 模式定义 */
22 | #define MODE0 0x00 //高阻输入模式,引脚没有上拉电阻
23 | #define MODE1 0x01 //推挽输出模式,具有对称驱动能力,可以输出或者吸收较大电流
24 | #define MODE2 0x02 //开漏输出,支持高阻输入,引脚没有上拉电阻
25 | #define MODE3 0x03 //准双向模式(标准 8051),开漏输出,支持输入,引脚有上拉电阻(默认模式)
26 | /****************** GPIO_INT_Init 参数定义 ********************/
27 | /* IntSrc 外部中断(可组合) */
28 | #define INT_RXD0_L 0x0001
29 | #define INT_P46_L 0x0002
30 | #define INT_P57_H 0x0004 //唯一一个高电平(上升沿)有效中断
31 | #define INT_P03_L 0x0008
32 | #define INT_P14_L 0x0010
33 | #define INT_P15_L 0x0020
34 | #define INT_RXD1_L 0x0040
35 | #define INT_INT0_L 0x0080
36 | #define INT_INT1_L 0x0100
37 | /* 中断触发模式 */
38 | #define INT_LEVEL 0x00 //电平模式
39 | #define INT_EDGE 0x01 //边沿模式
40 | /* 中断状态 */
41 | #define Disable 0x00 //中断无效
42 | #define Enable 0x01 //中断使能
43 | /****************** 外部调用子函数 ****************************/
44 | extern void GPIO_Init(UINT8 PORTx, UINT8 PINx, UINT8 MODEx); //GPIO初始化
45 | extern void GPIO_INT_Init( UINT16 IntSrc, UINT8 Mode, UINT8 NewState ); //外部中断初始化
46 | #endif
47 |
--------------------------------------------------------------------------------
/Firmware/Lib/Timer.C:
--------------------------------------------------------------------------------
1 | /********************************** (C) COPYRIGHT *******************************
2 | * File Name : Timer.C
3 | * Author : WCH
4 | * Version : V1.0
5 | * Date : 2018/08/21
6 | * Description : CH549 Time 初始化、定时器、计数器赋值、T2捕捉功能开启函数等
7 | 定时器中断函数
8 | *******************************************************************************/
9 | #include "Timer.H"
10 | #pragma NOAREGS
11 | #ifdef T2_CAP
12 | UINT16 Cap2[2] = {0};
13 | UINT16 Cap1[2] = {0};
14 | UINT16 Cap0[2] = {0};
15 | #endif
16 | /*******************************************************************************
17 | * Function Name : mTimer_x_ModInit(UINT8 x ,UINT8 mode)
18 | * Description : CH549定时计数器x模式设置
19 | * Input : UINT8 mode,Timer模式选择
20 | 0:模式0,13位定时器,TLn的高3位无效
21 | 1:模式1,16位定时器
22 | 2:模式2,8位自动重装定时器
23 | 3:模式3,两个8位定时器 Timer0
24 | 3:模式3,Timer1停止
25 | * Output : None
26 | * Return : 成功 SUCCESS
27 | 失败 FAIL
28 | *******************************************************************************/
29 | UINT8 mTimer_x_ModInit(UINT8 x ,UINT8 mode)
30 | {
31 | if(x == 0)
32 | {
33 | TMOD = TMOD & 0xf0 | mode;
34 | }
35 | else if(x == 1)
36 | {
37 | TMOD = TMOD & 0x0f | (mode<<4);
38 | }
39 | else if(x == 2)
40 | {
41 | RCLK = 0; //16位自动重载定时器
42 | TCLK = 0;
43 | CP_RL2 = 0;
44 | }
45 | else
46 | {
47 | return FAIL;
48 | }
49 | return SUCCESS;
50 | }
51 | /*******************************************************************************
52 | * Function Name : mTimer_x_SetData(UINT8 x,UINT16 dat)
53 | * Description : CH549Timer0 TH0和TL0赋值
54 | * Input : UINT16 dat;定时器赋值
55 | * Output : None
56 | * Return : None
57 | *******************************************************************************/
58 | void mTimer_x_SetData(UINT8 x,UINT16 dat)
59 | {
60 | UINT16 tmp;
61 | tmp = 65536 - dat;
62 | if(x == 0)
63 | {
64 | TL0 = tmp & 0xff;
65 | TH0 = (tmp>>8) & 0xff;
66 | }
67 | else if(x == 1)
68 | {
69 | TL1 = tmp & 0xff;
70 | TH1 = (tmp>>8) & 0xff;
71 | }
72 | else if(x == 2)
73 | {
74 | RCAP2L = TL2 = tmp & 0xff; //16位自动重载定时器
75 | RCAP2H = TH2 = (tmp>>8) & 0xff;
76 | }
77 | }
78 | /*******************************************************************************
79 | * Function Name : CAP2Init(UINT8 mode)
80 | * Description : CH549定时计数器2 T2EX引脚捕捉功能初始化(CAP2 P11)
81 | UINT8 mode,边沿捕捉模式选择
82 | 0:T2ex从下降沿到下一个下降沿
83 | 1:T2ex任意边沿之间
84 | 3:T2ex从上升沿到下一个上升沿
85 | * Input : None
86 | * Output : None
87 | * Return : None
88 | *******************************************************************************/
89 | void CAP2Init(UINT8 mode)
90 | {
91 | RCLK = 0;
92 | TCLK = 0;
93 | C_T2 = 0;
94 | EXEN2 = 1;
95 | CP_RL2 = 1; //启动T2ex的捕捉功能
96 | T2MOD |= mode << 2; //边沿捕捉模式选择
97 | }
98 | /*******************************************************************************
99 | * Function Name : CAP1Init(UINT8 mode)
100 | * Description : CH549定时计数器2 T2引脚捕捉功能初始化T2(CAP1 P10)
101 | UINT8 mode,边沿捕捉模式选择
102 | 0:T2ex从下降沿到下一个下降沿
103 | 1:T2ex任意边沿之间
104 | 3:T2ex从上升沿到下一个上升沿
105 | * Input : None
106 | * Output : None
107 | * Return : None
108 | *******************************************************************************/
109 | void CAP1Init(UINT8 mode)
110 | {
111 | RCLK = 0;
112 | TCLK = 0;
113 | CP_RL2 = 1;
114 | C_T2 = 0;
115 | T2MOD = T2MOD & ~T2OE | (mode << 2) | bT2_CAP1_EN; //使能T2引脚捕捉功能,边沿捕捉模式选择
116 | }
117 | /*******************************************************************************
118 | * Function Name : CAP0Init(UINT8 mode)
119 | * Description : CH549定时计数器2 CAP0引脚捕捉功能初始化(CAP0 P36)
120 | UINT8 mode,边沿捕捉模式选择
121 | 0:T2ex从下降沿到下一个下降沿
122 | 1:T2ex任意边沿之间
123 | 3:T2ex从上升沿到下一个上升沿
124 | * Input : None
125 | * Output : None
126 | * Return : None
127 | *******************************************************************************/
128 | void CAP0Init(UINT8 mode)
129 | {
130 | RCLK = 0;
131 | TCLK = 0;
132 | CP_RL2 = 1;
133 | C_T2 = 0;
134 | T2MOD |= mode << 2; //边沿捕捉模式选择
135 | T2CON2 = bT2_CAP0_EN;
136 | }
137 | #ifdef T0_INT
138 | /*******************************************************************************
139 | * Function Name : mTimer0Interrupt()
140 | * Description : CH549定时计数器0定时计数器中断处理函数 1ms中断
141 | *******************************************************************************/
142 | void mTimer0Interrupt( void ) interrupt INT_NO_TMR0 using 1 //timer0中断服务程序,使用寄存器组1
143 | {
144 | mTimer_x_SetData(0,2000); //模式1 需重新给TH0和TL0赋值
145 | SCK = ~SCK; //大约1ms
146 | }
147 | #endif
148 | #ifdef T1_INT
149 | /*******************************************************************************
150 | * Function Name : mTimer1Interrupt()
151 | * Description : CH549定时计数器1定时计数器中断处理函数 100us中断
152 | *******************************************************************************/
153 | void mTimer1Interrupt( void ) interrupt INT_NO_TMR1 using 2 //timer1中断服务程序,使用寄存器组2
154 | {
155 | //方式2时,Timer1自动重装
156 | static UINT16 tmr1 = 0;
157 | tmr1++;
158 | if(tmr1 == 2000) //100us*2000 = 200ms
159 | {
160 | tmr1 = 0;
161 | SCK = ~SCK;
162 | }
163 | }
164 | #endif
165 | /*******************************************************************************
166 | * Function Name : mTimer2Interrupt()
167 | * Description : CH549定时计数器0定时计数器中断处理函数
168 | *******************************************************************************/
169 | void mTimer2Interrupt( void ) interrupt INT_NO_TMR2 using 3 //timer2中断服务程序,使用寄存器组3
170 | {
171 | #ifdef T2_INT
172 | static UINT8 tmr2 = 0;
173 | if(TF2)
174 | {
175 | TF2 = 0; //清空定时器2溢出中断,需手动请
176 | tmr2++;
177 | if(tmr2 == 100) //200ms时间到
178 | {
179 | tmr2 = 0;
180 | SCK = ~SCK; //P17电平指示监控
181 | }
182 | }
183 | #endif
184 |
185 | #ifdef T2_CAP
186 | if(EXF2) //T2ex电平变化中断中断标志
187 | {
188 | Cap2[0] = RCAP2; //T2EX
189 | printf("CAP2 %04x\n",Cap2[0]-Cap2[1]);
190 | Cap2[1] = Cap2[0];
191 | EXF2 = 0; //清空T2ex捕捉中断标志
192 | }
193 | if(CAP1F) //T2电平捕捉中断标志
194 | {
195 | Cap1[0] = T2CAP1; //T2;
196 | printf("CAP1 %04x\n",Cap1[0]-Cap1[1]);
197 | Cap1[1] = Cap1[0];
198 | CAP1F = 0; //清空T2捕捉中断标志
199 | }
200 | if(T2CON2&bT2_CAP0F)
201 | {
202 | Cap0[0] = T2CAP0;
203 | printf("CAP0 %04x\n",Cap0[0]-Cap0[1]);
204 | Cap0[1] = Cap0[0];
205 | T2CON2 &= ~bT2_CAP0F;
206 | }
207 | #endif
208 |
209 | }
210 |
--------------------------------------------------------------------------------
/Firmware/Lib/Timer.H:
--------------------------------------------------------------------------------
1 | #ifndef __TIMER_H__
2 | #define __TIMER_H__
3 | #include "CH549.H"
4 | #include "DEBUG.H"
5 | #define T0_INT 1
6 | //#define T1_INT 1
7 | //#define T2_INT 1
8 | #define T2_CAP 1
9 | /******************* CH549 Timer0相关 ************************/
10 | //bTMR_CLK同时影响Timer0&1&2,使用时要注意 (除定时使用标准时钟)
11 | #define mTimer0Clk12DivFsys( ) (T2MOD &= ~bT0_CLK) //定时器,时钟=Fsys/12 T0标准时钟
12 | #define mTimer0ClkFsys( ) (T2MOD |= bTMR_CLK | bT0_CLK) //定时器,时钟=Fsys
13 | #define mTimer0Clk4DivFsys( ) (T2MOD &= ~bTMR_CLK;T2MOD |= bT0_CLK) //定时器,时钟=Fsys/4(此时需同步调整DEBUG.C的mInitSTDIO)
14 | #define mTimer0CountClk( ) (TMOD |= bT0_CT) //选择工作在计数器模式(T0引脚(P34)的下降沿有效)
15 | #define mTimer0RunCTL( SS ) (TR0 = SS ? START : STOP) //CH549 Timer0 开始(SS=1)/结束(SS=0)
16 | /***** CH549 Timer1相关(DEBUG.C的mInitSTDIO使用T1模式2) *****/
17 | #define mTimer1Clk12DivFsys( ) (T2MOD &= ~bT1_CLK) //定时器,时钟=Fsys/12 T1标准时钟
18 | #define mTimer1ClkFsys( ) (T2MOD |= bTMR_CLK | bT1_CLK) //定时器,时钟=Fsys
19 | #define mTimer1Clk4DivFsys( ) (T2MOD &= ~bTMR_CLK;T2MOD |= bT1_CLK) //定时器,时钟=Fsys/4
20 | #define mTimer1CountClk( ) (TMOD |= bT1_CT) //选择工作在计数器模式(T1引脚(P35)的下降沿有效)
21 | #define mTimer1RunCTL( SS ) (TR1 = SS ? START : STOP) //CH549 Timer1 开始(SS=1)/结束(SS=0)
22 | /******************* CH549 Timer2相关 ************************/
23 | #define mTimer2Clk12DivFsys( ) {T2MOD &= ~ bT2_CLK;C_T2 = 0;} //定时器,时钟=Fsys/12 T2标准时钟
24 | #define mTimer2ClkFsys( ) {T2MOD |= (bTMR_CLK | bT2_CLK);C_T2=0;} //定时器,时钟=Fsys
25 | #define mTimer2Clk4DivFsys( ) {T2MOD &= ~bTMR_CLK;T2MOD |= bT2_CLK;C_T2 = 0;}//定时器,时钟=Fsys/4(此时需同步调整DEBUG.C的mInitSTDIO)
26 | #define mTimer2CountClk( ) {C_T2 = 1;} //选择工作在计数器模式(T2引脚(P10)的下降沿有效)
27 | #define mTimer2RunCTL( SS ) {TR2 = SS ? START : STOP;} //CH549 Timer2 开始(SS=1)/结束(SS=0)
28 | #define mTimer2OutCTL( ) (T2MOD |= T2OE) //T2输出 频率TF2/2
29 | #define CAP1Alter( ) (PIN_FUNC |= bT2_PIN_X;) //CAP1由P10 映射到P14
30 | #define CAP2Alter( ) (PIN_FUNC |= bT2EX_PIN_X;) //CAP2由P11 映射RST
31 | /*******************************************************************************
32 | * Function Name : mTimer_x_ModInit(UINT8 x ,UINT8 mode)
33 | * Description : CH549定时计数器x模式设置
34 | * Input : UINT8 mode,Timer模式选择
35 | 0:模式0,13位定时器,TLn的高3位无效
36 | 1:模式1,16位定时器
37 | 2:模式2,8位自动重装定时器
38 | 3:模式3,两个8位定时器 Timer0
39 | 3:模式3,Timer1停止
40 | UINT8 x 定时器 0 1 2
41 | * Output : None
42 | * Return : 成功 SUCCESS
43 | 失败 FAIL
44 | *******************************************************************************/
45 | UINT8 mTimer_x_ModInit(UINT8 x ,UINT8 mode);
46 | /*******************************************************************************
47 | * Function Name : mTimer_x_SetData(UINT8 x,UINT16 dat)
48 | * Description : CH549Timer
49 | * Input : UINT16 dat;定时器赋值
50 | UINT8 x 定时器 0 1 2
51 | * Output : None
52 | * Return : None
53 | *******************************************************************************/
54 | void mTimer_x_SetData(UINT8 x,UINT16 dat);
55 | /*******************************************************************************
56 | * Function Name : CAP2Init(UINT8 mode)
57 | * Description : CH549定时计数器2 T2EX引脚捕捉功能初始化(CAP2 P11)
58 | UINT8 mode,边沿捕捉模式选择
59 | 0:T2ex从下降沿到下一个下降沿
60 | 1:T2ex任意边沿之间
61 | 3:T2ex从上升沿到下一个上升沿
62 | * Input : None
63 | * Output : None
64 | * Return : None
65 | *******************************************************************************/
66 | void CAP2Init(UINT8 mode);
67 | /*******************************************************************************
68 | * Function Name : CAP1Init(UINT8 mode)
69 | * Description : CH549定时计数器2 T2引脚捕捉功能初始化T2(CAP1 P10)
70 | UINT8 mode,边沿捕捉模式选择
71 | 0:T2ex从下降沿到下一个下降沿
72 | 1:T2ex任意边沿之间
73 | 3:T2ex从上升沿到下一个上升沿
74 | * Input : None
75 | * Output : None
76 | * Return : None
77 | *******************************************************************************/
78 | void CAP1Init(UINT8 mode);
79 | /*******************************************************************************
80 | * Function Name : CAP0Init(UINT8 mode)
81 | * Description : CH549定时计数器2 CAP0引脚捕捉功能初始化(CAP0 P36)
82 | UINT8 mode,边沿捕捉模式选择
83 | 0:T2ex从下降沿到下一个下降沿
84 | 1:T2ex任意边沿之间
85 | 3:T2ex从上升沿到下一个上升沿
86 | * Input : None
87 | * Output : None
88 | * Return : None
89 | *******************************************************************************/
90 | void CAP0Init(UINT8 mode);
91 | #endif
92 |
--------------------------------------------------------------------------------
/Firmware/Lib/UART.C:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/Firmware/Lib/UART.C
--------------------------------------------------------------------------------
/Firmware/Lib/UART.H:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/Firmware/Lib/UART.H
--------------------------------------------------------------------------------
/Firmware/ProJ.uvopt:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 1.0
5 |
6 | ### uVision Project, (C) Keil Software
7 |
8 |
9 | *.c
10 | *.s*; *.src; *.a*
11 | *.obj; *.o
12 | *.lib
13 | *.txt; *.h; *.inc; *.md
14 | *.plm
15 | *.cpp; *.cc; *.cxx
16 | 0
17 |
18 |
19 |
20 | 0
21 | 0
22 |
23 |
24 |
25 | Target 1
26 | 0x0
27 | MCS-51
28 |
29 | 48000000
30 |
31 | 1
32 | 1
33 | 1
34 | 0
35 | 0
36 |
37 |
38 | 0
39 | 65535
40 | 0
41 | 0
42 | 0
43 |
44 |
45 | 120
46 | 65
47 | 8
48 | .\Listings\
49 |
50 |
51 | 1
52 | 1
53 | 1
54 | 0
55 | 1
56 | 1
57 | 0
58 | 1
59 | 0
60 | 0
61 | 0
62 | 0
63 |
64 |
65 | 1
66 | 1
67 | 1
68 | 1
69 | 1
70 | 1
71 | 1
72 | 0
73 | 0
74 |
75 |
76 | 1
77 | 0
78 | 1
79 |
80 | 0
81 |
82 | 1
83 | 0
84 | 1
85 | 1
86 | 1
87 | 1
88 | 1
89 | 1
90 | 1
91 | 1
92 | 0
93 | 1
94 | 1
95 | 1
96 | 0
97 | 1
98 | 1
99 | 1
100 | 1
101 | 0
102 | 0
103 | 1
104 | 0
105 | 0
106 | -1
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 | 0
122 |
123 |
124 | 0
125 | 1
126 | 0
127 | 0
128 | 0
129 | 0
130 | 0
131 | 0
132 | 0
133 | 0
134 | 0
135 | 0
136 | 0
137 | 0
138 | 0
139 | 0
140 | 0
141 | 0
142 | 0
143 | 0
144 | 0
145 | 0
146 | 0
147 | 0
148 |
149 |
150 |
151 | 0
152 | 0
153 | 0
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 | User
167 | 1
168 | 0
169 | 0
170 | 0
171 |
172 | 1
173 | 1
174 | 1
175 | 0
176 | 0
177 | 0
178 | .\User\main.C
179 | main.C
180 | 0
181 | 0
182 |
183 |
184 |
185 |
186 | Lib
187 | 1
188 | 0
189 | 0
190 | 0
191 |
192 | 2
193 | 2
194 | 1
195 | 0
196 | 0
197 | 0
198 | .\Lib\DEBUG.C
199 | DEBUG.C
200 | 0
201 | 0
202 |
203 |
204 | 2
205 | 3
206 | 1
207 | 0
208 | 0
209 | 0
210 | .\Lib\GPIO.C
211 | GPIO.C
212 | 0
213 | 0
214 |
215 |
216 | 2
217 | 4
218 | 1
219 | 0
220 | 0
221 | 0
222 | .\Lib\Timer.C
223 | Timer.C
224 | 0
225 | 0
226 |
227 |
228 |
229 |
230 |
--------------------------------------------------------------------------------
/Firmware/ProJ.uvproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 1.1
5 |
6 | ### uVision Project, (C) Keil Software
7 |
8 |
9 |
10 | Target 1
11 | 0x0
12 | MCS-51
13 | 0
14 |
15 |
16 | CH549
17 | WCH
18 | IRAM(0-0xFF) XRAM(0-0x3FFF) IROM(0-0x3FFF) CLOCK(48000000)
19 |
20 | "LIB\STARTUP.A51" ("Standard 8051 Startup Code")
21 |
22 | 0
23 | CH549.H
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | 0
35 | 0
36 |
37 |
38 |
39 | WCH\
40 | WCH\
41 |
42 | 0
43 | 0
44 | 0
45 | 0
46 | 1
47 |
48 | .\Objects\
49 | ProJ
50 | 1
51 | 0
52 | 1
53 | 1
54 | 1
55 | .\Listings\
56 | 0
57 | 0
58 | 0
59 |
60 | 0
61 | 0
62 |
63 |
64 | 0
65 | 0
66 | 0
67 | 0
68 |
69 |
70 | 0
71 | 0
72 |
73 |
74 | 0
75 | 0
76 | 0
77 | 0
78 |
79 |
80 | 0
81 | 0
82 |
83 |
84 | 0
85 | 0
86 | 0
87 | 0
88 |
89 | 0
90 |
91 |
92 |
93 | 0
94 | 0
95 | 0
96 | 0
97 | 0
98 | 1
99 | 0
100 | 0
101 | 0
102 | 0
103 | 3
104 |
105 |
106 | 1
107 | 65535
108 |
109 |
110 | S8051.DLL
111 |
112 | DP51.DLL
113 | -pDR8051
114 | S8051.DLL
115 |
116 | TP51.DLL
117 | -p51
118 |
119 |
120 |
121 | 0
122 | 0
123 | 0
124 | 0
125 | 16
126 |
127 |
128 | 1
129 | 1
130 | 1
131 | 1
132 | 1
133 | 1
134 | 1
135 | 1
136 | 0
137 | 1
138 |
139 |
140 | 0
141 | 1
142 | 0
143 | 1
144 | 1
145 | 1
146 | 0
147 | 1
148 | 1
149 | 1
150 |
151 | 0
152 | -1
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 | 0
172 | 0
173 | 0
174 | 0
175 | 0
176 | -1
177 |
178 | 0
179 |
180 | "" ()
181 |
182 |
183 |
184 |
185 | 0
186 |
187 |
188 |
189 | 2
190 | 0
191 | 2
192 | 0
193 | 0
194 | 0
195 | 0
196 | 0
197 | 0
198 | 1
199 | 1
200 | 1
201 | 0
202 | 0
203 | 0
204 | 0
205 | 0
206 | 0
207 | 0
208 | 0
209 | 0
210 | 0
211 | 0
212 | 0
213 | 0
214 | 0
215 | 0
216 | 0
217 | 0
218 | 0
219 | 0
220 | 0
221 | 0
222 | 0
223 | 0
224 | 0
225 | 0
226 | 0
227 | 0
228 | 0
229 | 0
230 | 0
231 | 0
232 |
233 |
234 | 0
235 | 0x0
236 | 0xffff
237 |
238 |
239 | 0
240 | 0x0
241 | 0x0
242 |
243 |
244 | 0
245 | 0x0
246 | 0x0
247 |
248 |
249 | 0
250 | 0x0
251 | 0x0
252 |
253 |
254 | 0
255 | 0x0
256 | 0x0
257 |
258 |
259 | 0
260 | 0x0
261 | 0x0
262 |
263 |
264 | 0
265 | 0x0
266 | 0x0
267 |
268 |
269 | 0
270 | 0x0
271 | 0x0
272 |
273 |
274 | 1
275 | 0x0
276 | 0x4000
277 |
278 |
279 | 0
280 | 0x0
281 | 0x100
282 |
283 |
284 | 0
285 | 0x0
286 | 0x4000
287 |
288 |
289 | 0
290 | 0x0
291 | 0x0
292 |
293 |
294 | 0
295 | 0x0
296 | 0x0
297 |
298 |
299 | 0
300 | 0x0
301 | 0x0
302 |
303 |
304 | 0
305 | 0x0
306 | 0x0
307 |
308 |
309 |
310 |
311 | 0
312 | 0
313 | 1
314 | 0
315 | 1
316 | 3
317 | 8
318 | 2
319 | 1
320 | 1
321 | 0
322 | 0
323 |
324 |
325 |
326 |
327 | .\Lib
328 |
329 |
330 |
331 | 0
332 | 1
333 | 0
334 | 0
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 | 0
344 | 0
345 | 1
346 | 0
347 | 2
348 | 1
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 | User
378 |
379 |
380 | main.C
381 | 1
382 | .\User\main.C
383 |
384 |
385 |
386 |
387 | Lib
388 |
389 |
390 | DEBUG.C
391 | 1
392 | .\Lib\DEBUG.C
393 |
394 |
395 | GPIO.C
396 | 1
397 | .\Lib\GPIO.C
398 |
399 |
400 | Timer.C
401 | 1
402 | .\Lib\Timer.C
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
--------------------------------------------------------------------------------
/Firmware/User/main.C:
--------------------------------------------------------------------------------
1 | /********************************** (i) information
2 | ******************************** File Name : main.C Author : E Version
3 | *: V1.0 Date : 2022/09/22 Description :
4 | *USB键盘鼠标收发程序,串口传输HID报文
5 | *******************************************************************************/
6 | #include "CH549.H"
7 | #include "DEBUG.H"
8 | #include "GPIO.H"
9 |
10 | #define Fullspeed
11 |
12 | #ifdef Fullspeed
13 | #define THIS_ENDP0_SIZE 64
14 | #else
15 | #define THIS_ENDP0_SIZE 8 //低速USB,中断传输、控制传输最大包长度为8
16 | #endif
17 |
18 | UINT8X Ep0Buffer[THIS_ENDP0_SIZE +
19 | 2] _at_ 0x0000; //端点0 OUT&IN缓冲区,必须是偶地址
20 | UINT8X Ep2Buffer[2 * MAX_PACKET_SIZE + 4] _at_ THIS_ENDP0_SIZE +
21 | 2; //端点2 IN&OUT缓冲区,必须是偶地址
22 | UINT8 SetupReq, Ready, UsbConfig;
23 | UINT16 SetupLen;
24 | PUINT8 pDescr; // USB配置标志
25 | USB_SETUP_REQ SetupReqBuf; //暂存Setup包
26 | #define UsbSetupBuf ((PUSB_SETUP_REQ)Ep0Buffer)
27 | #pragma NOAREGS
28 |
29 | /*字符串描述符 略*/
30 | /*HID类报表描述符*/
31 | UINT8C HIDRepDesc[] =
32 | {
33 |
34 | /* keyboared */
35 | 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
36 | 0x09, 0x06, // USAGE (Keyboard)
37 | 0xa1, 0x01, // COLLECTION (Application)
38 | 0x85, 0x01, // Report ID (1)
39 | 0x05, 0x07, // USAGE_PAGE (Keyboard)
40 | 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
41 | 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
42 | 0x15, 0x00, // LOGICAL_MINIMUM (0)
43 | 0x25, 0x01, // LOGICAL_MAXIMUM (1)
44 | 0x75, 0x01, // REPORT_SIZE (1)
45 | 0x95, 0x08, // REPORT_COUNT (8)
46 | 0x81, 0x02, // INPUT (Data,Var,Abs)
47 | 0x95, 0x01, // REPORT_COUNT (1)
48 | 0x75, 0x08, // REPORT_SIZE (8)
49 | 0x81, 0x03, // INPUT (Cnst,Var,Abs)
50 | 0x95, 0x05, // REPORT_COUNT (5)
51 | 0x75, 0x01, // REPORT_SIZE (1)
52 | 0x05, 0x08, // USAGE_PAGE (LEDs)
53 | 0x19, 0x01, // USAGE_MINIMUM (Num Lock)
54 | 0x29, 0x05, // USAGE_MAXIMUM (Kana)
55 | 0x91, 0x02, // OUTPUT (Data,Var,Abs)
56 | 0x95, 0x01, // REPORT_COUNT (1)
57 | 0x75, 0x03, // REPORT_SIZE (3)
58 | 0x91, 0x03, // OUTPUT (Cnst,Var,Abs)
59 | 0x95, 0x06, // REPORT_COUNT (6)
60 | 0x75, 0x08, // REPORT_SIZE (8)
61 | 0x15, 0x00, // LOGICAL_MINIMUM (0)
62 | 0x25, 0xFF, // LOGICAL_MAXIMUM (255)
63 | 0x05, 0x07, // USAGE_PAGE (Keyboard)
64 | 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
65 | 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
66 | 0x81, 0x00, // INPUT (Data,Ary,Abs)
67 | 0xc0, // END_COLLECTION /* 65 */
68 |
69 | /* consumer */
70 | 0x05, 0x0c, // USAGE_PAGE (Consumer Devices)
71 | 0x09, 0x01, // USAGE (Consumer Control)
72 | 0xa1, 0x01, // COLLECTION (Application)
73 | 0x85, 0x02, // REPORT_ID (2)
74 | 0x19, 0x00, // USAGE_MINIMUM (Unassigned)
75 | 0x2a, 0x3c, 0x03, // USAGE_MAXIMUM
76 | 0x15, 0x00, // LOGICAL_MINIMUM (0)
77 | 0x26, 0x3c, 0x03, // LOGICAL_MAXIMUM (828)
78 | 0x95, 0x01, // REPORT_COUNT (1)
79 | 0x75, 0x10, // REPORT_SIZE (16)
80 | 0x81, 0x00, // INPUT (Data,Ary,Abs)
81 | 0xc0, // END_COLLECTION /* 25 */
82 |
83 | /* mouse */
84 | 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
85 | 0x09, 0x02, // USAGE (Mouse)
86 | 0xa1, 0x01, // COLLECTION (Application)
87 | 0x85, 0x03, // REPORT_ID (3)
88 | 0x09, 0x01, // USAGE (Pointer)
89 | 0xa1, 0x00, // COLLECTION (Physical)
90 | 0x05, 0x09, // USAGE_PAGE (Button)
91 | 0x19, 0x01, // USAGE_MINIMUM (Button 1)
92 | 0x29, 0x03, // USAGE_MAXIMUM (Button 3)
93 | 0x15, 0x00, // LOGICAL_MINIMUM (0)
94 | 0x25, 0x01, // LOGICAL_MAXIMUM (1)
95 | 0x95, 0x03, // REPORT_COUNT (3)
96 | 0x75, 0x01, // REPORT_SIZE (1)
97 | 0x81, 0x02, // INPUT (Data,Var,Abs)
98 | 0x95, 0x01, // REPORT_COUNT (1)
99 | 0x75, 0x05, // REPORT_SIZE (5)
100 | 0x81, 0x03, // INPUT (Cnst,Var,Abs)
101 | 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
102 | 0x09, 0x30, // USAGE (X)
103 | 0x09, 0x31, // USAGE (Y)
104 | 0x09, 0x38, // Usage (Wheel)
105 | 0x15, 0x81, // LOGICAL_MINIMUM (-127)
106 | 0x25, 0x7f, // LOGICAL_MAXIMUM (127)
107 | 0x75, 0x08, // REPORT_SIZE (8)
108 | 0x95, 0x03, // REPORT_COUNT (3)
109 | 0x81, 0x06, // INPUT (Data,Var,Rel)
110 | 0xc0, // END_COLLECTION
111 | 0xc0, // END_COLLECTION
112 | /*
113 |
114 |
115 | /* Vendor */
116 | 0x06, 0xB1, 0xFF, // Usage Page (Vendor-Defined 178)
117 | 0x09, 0x01, // Usage (Vendor-Defined 1)
118 | 0xA1, 0x01, // Collection (Application)
119 |
120 | 0x85, 0x04, // REPORT_ID (4)
121 | 0x09, 0x04, // Usage (Vendor-Defined 4)
122 | 0x15, 0x00, // Logical Minimum (0)
123 | 0x26, 0xFF, 0x00, // Logical Maximum (255)
124 | 0x75, 0x08, // Report Size (8)
125 | 0x95, 0x20, // Report Count (10)
126 | 0x91, 0x02, // Output (Data,Var,Abs,NWrp,Lin,Pref,NNul,NVol,Bit)
127 |
128 | 0x09, 0x01, // Usage (0x01)
129 | 0x25, 0x00, // Logical Maximum (0)
130 | 0x26, 0xFF, 0x00, // Logical Maximum (255)
131 | 0x75, 0x08, // Report Size (10)
132 | 0x95, 0x20, // Report Count (32)
133 | 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null
134 | // Position)
135 |
136 | 0xC0, // End Collection /* 37 */
137 |
138 | };
139 |
140 | /*设备描述符*/
141 | UINT8C DevDesc[] =
142 | {
143 | 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, THIS_ENDP0_SIZE,
144 | // 0x86, 0x1A, 0xE0, 0xE6, 0x00, 0x00, 0x01, 0x02,
145 | // //0x86, 0x1A,VID 0xE0, 0xE6,PID
146 | 0x86, 0x2B, 0xE0, 0xE6, 0x00, 0x00, 0x01, 0x02, 0x00, 0x01
147 | };
148 | UINT8C CfgDesc[] =
149 | {
150 | 0x09, 0x02, 0x29, 0x00, 0x01, 0x01, 0x04, 0xA0, 0x32, //配置描述符
151 | 0x09, 0x04, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x05, //接口描述符
152 | // 0x09, 0x21, 0x00, 0x01, 0x00, 0x01, 0x22, 0x22, 0x00, //HID类描述符
153 | // wDescriptorLength = 0x22
154 | 0x09, 0x21, 0x01, 0x01, 0x21, 0x01, 0x22, sizeof(HIDRepDesc) & 0xFF,
155 | sizeof(HIDRepDesc) >> 8, // HID类描述符 修改wDescriptorLength 长度为0x10B
156 |
157 | #ifdef Fullspeed
158 | 0x07, 0x05, 0x82, 0x03, THIS_ENDP0_SIZE, 0x00,
159 | 0x01, //端点描述符(全速间隔时间改成1ms)
160 | 0x07, 0x05, 0x02, 0x03, THIS_ENDP0_SIZE, 0x00, 0x01, //端点描述符
161 | #else
162 | 0x07, 0x05, 0x82, 0x03, THIS_ENDP0_SIZE, 0x00,
163 | 0x0A, //端点描述符(低速间隔时间最小10ms)
164 | 0x07, 0x05, 0x02, 0x03, THIS_ENDP0_SIZE, 0x00, 0x0A, //端点描述符
165 | #endif
166 | };
167 |
168 | // 语言描述符
169 | UINT8C MyLangDescr[] = {0x04, 0x03, 0x09, 0x04};
170 | // 厂家信息
171 | UINT8C
172 | MyManuInfo[] = {0x30, 0x03, 'M', 0, 'o', 0, 'y', 0, 'u', 0, ' ', 0, 'a', 0,
173 | 't', 0, ' ', 0, 'w', 0, 'o', 0, 'r', 0, 'k', 0, ' ', 0,
174 | 'T', 0, 'e', 0, 'c', 0, 'h', 0, 'n', 0, 'o', 0, 'l', 0,
175 | 'o', 0, 'g', 0, 'y', 0
176 | }; // MoYu at work Technology
177 | // 产品信息
178 | UINT8C MyProdInfo[] =
179 | {
180 | 0x1C, 0x03, 'K', 0, 'V', 0, 'M', 0, ' ', 0, 'o', 0, 'v', 0,
181 | 'e', 0, 'r', 0, ' ', 0, 'U', 0, 'S', 0, 'B', 0, ' ', 0,
182 | }; //字符串描述符 13*2bit + 2bit
183 |
184 | sbit MODE_PORT_0 = P3 ^ 4;
185 | BOOL MODE_STATUS = 0;
186 |
187 | UINT8X i = 0;
188 |
189 | UINT8X HID_OUT_report[33] = {0}; //接收到的上位机数据
190 | BOOL HID_OUT_report_FLAG = 0; //接收到上位机FLAG
191 |
192 | UINT8X SendHID[33] = {0}; //发送HID报文数组
193 | UINT8X UserEp2Buf[64];//用户数据定义
194 | UINT8 Endp2Busy = 0;
195 |
196 | #define S_RECEVIER_SIZE 32
197 | UINT8X RevBuffer[S_RECEVIER_SIZE];
198 | UINT8 revDataCount = 0;
199 | UINT8 revTempLength = 0;
200 | /*******************************************************************************
201 | * Function Name : USBDeviceInit()
202 | * Description : USB设备模式配置,设备模式启动,收发端点配置,中断开启
203 | * Input : None
204 | * Output : None
205 | * Return : None
206 | *******************************************************************************/
207 | void USBDeviceInit()
208 | {
209 | IE_USB = 0;
210 | USB_CTRL = 0x00; // 先设定USB设备模式
211 | UDEV_CTRL = bUD_PD_DIS; // 禁止DP/DM下拉电阻
212 | #ifndef Fullspeed
213 | UDEV_CTRL |= bUD_LOW_SPEED; //选择低速1.5M模式
214 | USB_CTRL |= bUC_LOW_SPEED;
215 | #else
216 | UDEV_CTRL &= ~bUD_LOW_SPEED; //选择全速12M模式,默认方式
217 | USB_CTRL &= ~bUC_LOW_SPEED;
218 | #endif
219 | UEP2_T_LEN = 0; //预使用发送长度一定要清空
220 | UEP2_DMA = Ep2Buffer; //端点2数据传输地址
221 | UEP2_3_MOD |= bUEP2_TX_EN | bUEP2_RX_EN; //端点2发送接收使能
222 | UEP2_3_MOD &= ~bUEP2_BUF_MOD; //端点2收发各64字节缓冲区
223 | UEP2_CTRL =
224 | bUEP_AUTO_TOG | UEP_T_RES_NAK |
225 | UEP_R_RES_ACK; //端点2自动翻转同步标志位,IN事务返回NAK,OUT返回ACK
226 | UEP0_DMA = Ep0Buffer; //端点0数据传输地址
227 | UEP4_1_MOD &= ~(bUEP4_RX_EN | bUEP4_TX_EN); //端点0单64字节收发缓冲区
228 | UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; // OUT事务返回ACK,IN事务返回NAK
229 | USB_DEV_AD = 0x00;
230 | USB_CTRL |=
231 | bUC_DEV_PU_EN | bUC_INT_BUSY |
232 | bUC_DMA_EN; // 启动USB设备及DMA,在中断期间中断标志未清除前自动返回NAK
233 | UDEV_CTRL |= bUD_PORT_EN; // 允许USB端口
234 | USB_INT_FG = 0xFF; // 清中断标志
235 | USB_INT_EN = bUIE_SUSPEND | bUIE_TRANSFER | bUIE_BUS_RST;
236 | IE_USB = 1;
237 | }
238 | /*******************************************************************************
239 | * Function Name : Enp2BlukIn()
240 | * Description : USB设备模式端点2的批量上传
241 | * Input : None
242 | * Output : None
243 | * Return : None
244 | *******************************************************************************/
245 | void Enp2BlukIn(UINT8 *buf, UINT8 len)
246 | {
247 | memcpy(Ep2Buffer + MAX_PACKET_SIZE, buf, len); //加载上传数据
248 | UEP2_T_LEN = len; //上传最大包长度
249 | UEP2_CTRL =
250 | UEP2_CTRL & ~MASK_UEP_T_RES | UEP_T_RES_ACK; //有数据时上传数据并应答ACK
251 | }
252 | /*******************************************************************************
253 | * Function Name : DeviceInterrupt()
254 | * Description : CH559USB中断处理函数
255 | *******************************************************************************/
256 | void DeviceInterrupt(void) interrupt INT_NO_USB
257 | using 1 // USB中断服务程序,使用寄存器组1
258 | {
259 | UINT8 i;
260 | UINT16 len;
261 |
262 | if (UIF_TRANSFER) // USB传输完成标志
263 | {
264 | switch (USB_INT_ST & (MASK_UIS_TOKEN | MASK_UIS_ENDP))
265 | {
266 | case UIS_TOKEN_IN | 2: // endpoint 2# 端点批量上传
267 | UEP2_T_LEN = 0; //预使用发送长度一定要清空
268 | // UEP1_CTRL ^= bUEP_T_TOG; //如果不设置自动翻转则需要手动翻转
269 | Endp2Busy = 0;
270 | UEP2_CTRL = UEP2_CTRL & ~MASK_UEP_T_RES | UEP_T_RES_NAK; //默认应答NAK
271 | break;
272 |
273 | case UIS_TOKEN_OUT | 2: // endpoint 2# 端点批量下传
274 | if (U_TOG_OK) // 不同步的数据包将丢弃
275 | {
276 |
277 | len = USB_RX_LEN; //接收数据长度,数据从Ep2Buffer首地址开始存放
278 | #ifdef DE_PRINTF
279 | // printf("[HID]OUT ");
280 | #endif
281 |
282 | for (i = 0; i < len; i++)
283 | {
284 | #ifdef DE_PRINTF
285 | // printf("0x%02x ", (UINT16)Ep2Buffer[i]); //遍历OUT数据
286 | #endif
287 |
288 | HID_OUT_report[i] = Ep2Buffer[i]; //赋值到HID_OUT_report
289 |
290 | // Ep2Buffer[MAX_PACKET_SIZE + i] = Ep2Buffer[i] ^ 0xFF; //
291 | // OUT数据取反到IN由计算机验证
292 | }
293 |
294 | HID_OUT_report_FLAG = 1;
295 |
296 | #ifdef DE_PRINTF
297 | // printf("len=%u\r\n", len);
298 | #endif
299 |
300 | // UEP2_T_LEN = len;
301 | // UEP2_CTRL = UEP2_CTRL & ~MASK_UEP_T_RES |
302 | // UEP_T_RES_ACK; // 允许上传
303 | }
304 |
305 | break;
306 |
307 | case UIS_TOKEN_SETUP | 0: // SETUP事务
308 | UEP0_CTRL = UEP0_CTRL & (~MASK_UEP_T_RES) |
309 | UEP_T_RES_NAK; //预置NAK,防止stall之后不及时清除响应方式
310 | len = USB_RX_LEN;
311 |
312 | if (len == (sizeof(USB_SETUP_REQ)))
313 | {
314 | SetupLen = ((UINT16)UsbSetupBuf->wLengthH << 8) + UsbSetupBuf->wLengthL;
315 | len = 0; // 默认为成功并且上传0长度
316 | SetupReq = UsbSetupBuf->bRequest;
317 |
318 | if ((UsbSetupBuf->bRequestType & USB_REQ_TYP_MASK) !=
319 | USB_REQ_TYP_STANDARD) /*HID类命令*/
320 | {
321 | Ready = 1; // HID类命令一般代表usb枚举完成的标志
322 |
323 | switch (SetupReq)
324 | {
325 | // Ready = 1;
326 | // //HID类命令一般代表usb枚举完成的标志
327 |
328 | case 0x01: // GetReport
329 | pDescr = UserEp2Buf; //控制端点上传输据
330 |
331 | if (SetupLen >= THIS_ENDP0_SIZE) //大于端点0大小,需要特殊处理
332 | {
333 | len = THIS_ENDP0_SIZE;
334 | }
335 | else
336 | {
337 | len = SetupLen;
338 | }
339 |
340 | break;
341 |
342 | case 0x02: // GetIdle
343 | break;
344 |
345 | case 0x03: // GetProtocol
346 | break;
347 |
348 | case 0x09: // SetReport
349 | break;
350 |
351 | case 0x0A: // SetIdle
352 | break;
353 |
354 | case 0x0B: // SetProtocol
355 | break;
356 |
357 | default:
358 | len = 0xFFFF; /*命令不支持*/
359 | break;
360 | }
361 |
362 | if (SetupLen > len)
363 | {
364 | SetupLen = len; //限制总长度
365 | }
366 |
367 | len = SetupLen >= THIS_ENDP0_SIZE ? THIS_ENDP0_SIZE
368 | : SetupLen; //本次传输长度
369 | memcpy(Ep0Buffer, pDescr, len); //加载上传数据
370 | SetupLen -= len;
371 | pDescr += len;
372 | }
373 | else //标准请求
374 | {
375 | switch (SetupReq) //请求码
376 | {
377 | case USB_GET_DESCRIPTOR:
378 | switch (UsbSetupBuf->wValueH)
379 | {
380 | case 1: //设备描述符
381 | pDescr = DevDesc; //把设备描述符送到要发送的缓冲区
382 | len = sizeof(DevDesc);
383 | break;
384 |
385 | case 2: //配置描述符
386 | pDescr = CfgDesc; //把设备描述符送到要发送的缓冲区
387 | len = sizeof(CfgDesc);
388 | break;
389 |
390 | case 3:
391 | switch (UsbSetupBuf->wValueL)
392 | {
393 | case 1:
394 | pDescr = (PUINT8)(&MyManuInfo[0]);
395 | len = sizeof(MyManuInfo);
396 | break;
397 |
398 | case 2:
399 | pDescr = (PUINT8)(&MyProdInfo[0]);
400 | len = sizeof(MyProdInfo);
401 | break;
402 |
403 | case 0:
404 | pDescr = (PUINT8)(&MyLangDescr[0]);
405 | len = sizeof(MyLangDescr);
406 | break;
407 |
408 | default:
409 | len = 0xFFFF; // 不支持的字符串描述符
410 | break;
411 | }
412 |
413 | break;
414 |
415 | case 0x22: //报表描述符
416 | pDescr = HIDRepDesc; //数据准备上传
417 | len = sizeof(HIDRepDesc);
418 | break;
419 |
420 | default:
421 | len = 0xFFFF; //不支持的命令或者出错
422 | break;
423 | }
424 |
425 | if (SetupLen > len)
426 | {
427 | SetupLen = len; //限制总长度
428 | }
429 |
430 | len = SetupLen >= THIS_ENDP0_SIZE ? THIS_ENDP0_SIZE
431 | : SetupLen; //本次传输长度
432 | memcpy(Ep0Buffer, pDescr, len); //加载上传数据
433 | SetupLen -= len;
434 | pDescr += len;
435 | break;
436 |
437 | case USB_SET_ADDRESS:
438 | SetupLen = UsbSetupBuf->wValueL; //暂存USB设备地址
439 | break;
440 |
441 | case USB_GET_CONFIGURATION:
442 | Ep0Buffer[0] = UsbConfig;
443 |
444 | if (SetupLen >= 1)
445 | {
446 | len = 1;
447 | }
448 |
449 | break;
450 |
451 | case USB_SET_CONFIGURATION:
452 | UsbConfig = UsbSetupBuf->wValueL;
453 |
454 | if (UsbConfig)
455 | {
456 | Ready = 1; // set config命令一般代表usb枚举完成的标志
457 | }
458 |
459 | break;
460 |
461 | case 0x0A:
462 | break;
463 |
464 | case USB_CLEAR_FEATURE: // Clear Feature
465 | if ((UsbSetupBuf->bRequestType & USB_REQ_RECIP_MASK) ==
466 | USB_REQ_RECIP_ENDP) // 端点
467 | {
468 | switch (UsbSetupBuf->wIndexL)
469 | {
470 | case 0x82:
471 | UEP2_CTRL =
472 | UEP2_CTRL & ~(bUEP_T_TOG | MASK_UEP_T_RES) | UEP_T_RES_NAK;
473 | break;
474 |
475 | case 0x81:
476 | UEP1_CTRL =
477 | UEP1_CTRL & ~(bUEP_T_TOG | MASK_UEP_T_RES) | UEP_T_RES_NAK;
478 | break;
479 |
480 | case 0x02:
481 | UEP2_CTRL =
482 | UEP2_CTRL & ~(bUEP_R_TOG | MASK_UEP_R_RES) | UEP_R_RES_ACK;
483 | break;
484 |
485 | default:
486 | len = 0xFFFF; // 不支持的端点
487 | break;
488 | }
489 | }
490 | else
491 | {
492 | len = 0xFFFF; // 不是端点不支持
493 | }
494 |
495 | break;
496 |
497 | case USB_SET_FEATURE: /* Set Feature */
498 | if ((UsbSetupBuf->bRequestType & 0x1F) == 0x00) /* 设置设备 */
499 | {
500 | if ((((UINT16)UsbSetupBuf->wValueH << 8) |
501 | UsbSetupBuf->wValueL) == 0x01)
502 | {
503 | if (CfgDesc[7] & 0x20)
504 | {
505 | /* 设置唤醒使能标志 */
506 | }
507 | else
508 | {
509 | len = 0xFFFF; /* 操作失败 */
510 | }
511 | }
512 | else
513 | {
514 | len = 0xFFFF; /* 操作失败 */
515 | }
516 | }
517 | else if ((UsbSetupBuf->bRequestType & 0x1F) ==
518 | 0x02) /* 设置端点 */
519 | {
520 | if ((((UINT16)UsbSetupBuf->wValueH << 8) |
521 | UsbSetupBuf->wValueL) == 0x00)
522 | {
523 | switch (((UINT16)UsbSetupBuf->wIndexH << 8) |
524 | UsbSetupBuf->wIndexL)
525 | {
526 | case 0x82:
527 | UEP2_CTRL = UEP2_CTRL & (~bUEP_T_TOG) |
528 | UEP_T_RES_STALL; /* 设置端点2 IN STALL */
529 | break;
530 |
531 | case 0x02:
532 | UEP2_CTRL = UEP2_CTRL & (~bUEP_R_TOG) |
533 | UEP_R_RES_STALL; /* 设置端点2 OUT Stall */
534 | break;
535 |
536 | case 0x81:
537 | UEP1_CTRL = UEP1_CTRL & (~bUEP_T_TOG) |
538 | UEP_T_RES_STALL; /* 设置端点1 IN STALL */
539 | break;
540 |
541 | default:
542 | len = 0xFFFF; /* 操作失败 */
543 | break;
544 | }
545 | }
546 | else
547 | {
548 | len = 0xFFFF; /* 操作失败 */
549 | }
550 | }
551 | else
552 | {
553 | len = 0xFFFF; /* 操作失败 */
554 | }
555 |
556 | break;
557 |
558 | case USB_GET_STATUS:
559 | Ep0Buffer[0] = 0x00;
560 | Ep0Buffer[1] = 0x00;
561 |
562 | if (SetupLen >= 2)
563 | {
564 | len = 2;
565 | }
566 | else
567 | {
568 | len = SetupLen;
569 | }
570 |
571 | break;
572 |
573 | default:
574 | len = 0xFFFF; //操作失败
575 | break;
576 | }
577 | }
578 | }
579 | else
580 | {
581 | len = 0xFFFF; //包长度错误
582 | }
583 |
584 | if (len == 0xFFFF)
585 | {
586 | SetupReq = 0xFF;
587 | UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_STALL |
588 | UEP_T_RES_STALL; // STALL
589 | }
590 | else if (len <= THIS_ENDP0_SIZE) //上传数据或者状态阶段返回0长度包
591 | {
592 | UEP0_T_LEN = len;
593 | UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK |
594 | UEP_T_RES_ACK; //默认数据包是DATA1,返回应答ACK
595 | }
596 | else
597 | {
598 | UEP0_T_LEN =
599 | 0; //虽然尚未到状态阶段,但是提前预置上传0长度数据包以防主机提前进入状态阶段
600 | UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK |
601 | UEP_T_RES_ACK; //默认数据包是DATA1,返回应答ACK
602 | }
603 |
604 | break;
605 |
606 | case UIS_TOKEN_IN | 0: // endpoint0 IN
607 | switch (SetupReq)
608 | {
609 | case USB_GET_DESCRIPTOR:
610 | case HID_GET_REPORT:
611 | len = SetupLen >= THIS_ENDP0_SIZE ? THIS_ENDP0_SIZE
612 | : SetupLen; //本次传输长度
613 | memcpy(Ep0Buffer, pDescr, len); //加载上传数据
614 | SetupLen -= len;
615 | pDescr += len;
616 | UEP0_T_LEN = len;
617 | UEP0_CTRL ^= bUEP_T_TOG; //同步标志位翻转
618 | break;
619 |
620 | case USB_SET_ADDRESS:
621 | USB_DEV_AD = USB_DEV_AD & bUDA_GP_BIT | SetupLen;
622 | UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
623 | break;
624 |
625 | default:
626 | UEP0_T_LEN = 0; //状态阶段完成中断或者是强制上传0长度数据包结束控制传输
627 | UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
628 | break;
629 | }
630 |
631 | break;
632 |
633 | case UIS_TOKEN_OUT | 0: // endpoint0 OUT
634 | len = USB_RX_LEN;
635 | UEP0_CTRL ^= bUEP_R_TOG; //同步标志位翻转
636 | break;
637 |
638 | default:
639 | break;
640 | }
641 |
642 | UIF_TRANSFER = 0; //写0清空中断
643 | }
644 | else if (UIF_BUS_RST) //设备模式USB总线复位中断
645 | {
646 | UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
647 | UEP2_CTRL = bUEP_AUTO_TOG | UEP_R_RES_ACK | UEP_T_RES_NAK;
648 | USB_DEV_AD = 0x00;
649 | UIF_SUSPEND = 0;
650 | UIF_TRANSFER = 0;
651 | Endp2Busy = 0;
652 | Ready = 0;
653 | UIF_BUS_RST = 0; //清中断标志
654 | }
655 | else if (UIF_SUSPEND) // USB总线挂起/唤醒完成
656 | {
657 | UIF_SUSPEND = 0;
658 |
659 | if (USB_MIS_ST & bUMS_SUSPEND) //挂起
660 | {
661 | #ifdef DE_PRINTF
662 | printf("[USB]sleep...\r\n"); //睡眠状态
663 | #endif
664 | // while ( XBUS_AUX & bUART0_TX )
665 | // {
666 | // ; //等待发送完成
667 | // }
668 | // SAFE_MOD = 0x55;
669 | // SAFE_MOD = 0xAA;
670 | // WAKE_CTRL = bWA K_BY_USB | bWAK_RXD0_LO;
671 | // //USB或者RXD0有信号时可被唤醒 PCON |= PD; //睡眠 SAFE_MOD =
672 | // 0x55; SAFE_MOD = 0xAA; WAKE_CTRL = 0x00;
673 | }
674 | else // 唤醒
675 | {
676 | #ifdef DE_PRINTF
677 | printf("[USB]Wake up!\r\n");
678 | #endif
679 | }
680 | }
681 | else //意外的中断,不可能发生的情况
682 | {
683 | USB_INT_FG = 0xFF; //清中断标志
684 | #ifdef DE_PRINTF
685 | printf("[USB]UnknownInt \r\n");
686 | #endif
687 | }
688 | }
689 |
690 | void REPORT_HANDLE(void)
691 | {
692 |
693 | HID_OUT_report_FLAG = 0;
694 |
695 | if (HID_OUT_report[0] == 4) //将HID报文转发到串口
696 | {
697 |
698 | CH549UART0SendByte(0xf0); //使用0xf0作为起始符
699 | for (i = 0; i < sizeof(HID_OUT_report); i++)
700 | {
701 | CH549UART0SendByte(HID_OUT_report[i]); //遍历OUT数据
702 | }
703 | CH549UART0SendByte(0xf1);//使用0xf1作为终止符
704 |
705 | }
706 |
707 | if (HID_OUT_report[0] == 4 && HID_OUT_report[1] == 4) //自定义功能
708 | {
709 |
710 | if (HID_OUT_report[1] == 1) // reset
711 | {
712 | #ifdef DE_PRINTF
713 | printf("[SYS]Reset\r\n");
714 | #endif
715 | CH549SoftReset();
716 | }
717 | else if (HID_OUT_report[1] == 2) // reload
718 | {
719 | #ifdef DE_PRINTF
720 | printf("[SYS]CONFIG RELOADED\r\n");
721 | #endif
722 | }
723 | }
724 | }
725 | void main()
726 | {
727 | #if (UART0_INTERRUPT == 0)
728 | UINT8 dat;
729 | #endif
730 | CfgFsys(); // CH549时钟选择配置
731 | mDelaymS(10); //修改主频等待内部晶振稳定,必加
732 | mInitSTDIO(); //串口0初始化
733 | #ifdef DE_PRINTF
734 | printf("[SYS]CLOCK_CFG=0x%02x\r\n", (UINT16)CLOCK_CFG);
735 | printf("[SYS]PowerOn ... Ver1.1\r\n");
736 | #endif
737 | USBDeviceInit(); // USB设备模式初始化
738 | EA = 1; //允许单片机中断
739 |
740 | GPIO_Init(PORT3, PIN4, MODE3); // P3.4上拉输入,用于主从检测
741 | mDelaymS(600); //等待USB中断完成
742 |
743 | if (MODE_PORT_0)
744 | {
745 | #ifdef DE_PRINTF
746 | printf("[SYS]Slave Mode\r\n");
747 | #endif
748 | MODE_STATUS = 0;
749 | printf("<=1\r\n"); //串口发送在线消息
750 |
751 | }
752 | else
753 | {
754 | #ifdef DE_PRINTF
755 | printf("[SYS]Master Mode\r\n");
756 | #endif
757 | MODE_STATUS = 1;
758 | }
759 |
760 | while (1)
761 | {
762 | #if (UART0_INTERRUPT == 0) //检测是否为非中断模式
763 |
764 | if (RI)
765 | {
766 | dat = SBUF;
767 | RI = 0;
768 |
769 | if (dat != 0xf1) // 以0xf1做为接收字符串结束标志
770 | {
771 | RevBuffer[revDataCount] = dat;
772 | revDataCount++;
773 | }
774 | else
775 | {
776 | // printf("%s\n", &RevBuffer[0]);
777 | revTempLength = revDataCount;
778 | revDataCount = 0;
779 |
780 | if (RevBuffer[0] == '<' && RevBuffer[1] == '=') //检测到从设备上线
781 | {
782 | #ifdef DE_PRINTF
783 | printf("[UART]Slave Online");
784 | #endif
785 |
786 | }
787 |
788 | if (RevBuffer[0] == 0xf0 && MODE_STATUS == 0) //从设备接收HID报文,并发送到USB
789 | {
790 | for (i = 0; i < sizeof(RevBuffer); i++)
791 | {
792 | SendHID[i] = RevBuffer[i + 2];
793 | }
794 |
795 | Enp2BlukIn(SendHID, sizeof(SendHID));
796 | }
797 |
798 | }
799 | }
800 |
801 | #endif
802 |
803 | if (HID_OUT_report_FLAG)
804 | {
805 | REPORT_HANDLE();
806 | }
807 | }
808 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Jancgk
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.
22 |
--------------------------------------------------------------------------------
/PCB/BOM_Board1_PCB1_2022-11-08.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/PCB/BOM_Board1_PCB1_2022-11-08.xlsx
--------------------------------------------------------------------------------
/PCB/Gerber_PCB1_2022-11-08.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/PCB/Gerber_PCB1_2022-11-08.zip
--------------------------------------------------------------------------------
/PCB/ProProject_KVM-over-USB_2022-11-08.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/PCB/ProProject_KVM-over-USB_2022-11-08.zip
--------------------------------------------------------------------------------
/PCB/README.md:
--------------------------------------------------------------------------------
1 | 您也可以使用立创EDA对原理图和PCB进行在线查看和编辑
2 |
3 | https://oshwhub.com/jancgk/kvm-over-usb
--------------------------------------------------------------------------------
/PCB/SCH_Schematic1_2022-11-08.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/PCB/SCH_Schematic1_2022-11-08.pdf
--------------------------------------------------------------------------------
/PCB/YuzukiHCC_MS2109_Firmware.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/PCB/YuzukiHCC_MS2109_Firmware.bin
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ⚠️此项目已停止更新⚠️
2 |
3 | 后续项目开发转移至->[KVM-Card-Mini](https://github.com/Jackadminx/KVM-Card-Mini)
4 |
5 | # KVM-Card
6 | 🖥️ Simple KVM Console to USB
7 |
8 |
9 |
10 | 实现一个简单的 KVM (Keyboard Video Mouse)功能,通过上位机程序实现对客户端的屏幕监控(HDMI)和键鼠控制(USB)
11 | ~~捡垃圾必备~~
12 | 
13 | >图片来自网络
14 |
15 | ## 简单硬件分析
16 |
17 | 
18 | - 两颗CH549实现数据传送和USB键鼠功能(技术太菜搞不定双USB的STM32,所以选了这个方案)。
19 | - MS2109实现视频采集卡功能,在上位机显示被控端屏幕。
20 | - SL2.1A将采集卡、USB串口、CH549的USB连接到一起。
21 | - CH340G USB转串口可不安装,用于软件调试。
22 |
23 | ## 控制端软件
24 | 简单的KVM客户端
25 | 
26 |
27 | 
28 |
29 | - 实现屏幕显示(支持输出切换分辨率)
30 | - 客户端键盘控制、自定义快捷键
31 | - 客户端鼠标捕捉和控制,捕获鼠标后按下键盘右CTRL键释放,操作逻辑类似于VirtualBox(
32 |
33 | ## 固件刷入
34 | ### CH549
35 | 按住Flash键并将USB插入即可刷入固件
36 | 使用[WCHISPTool](https://www.wch.cn/downloads/WCHISPTool_Setup_exe.html)刷入固件
37 | 两颗CH549都需要刷入固件,固件自动识别主从
38 | 
39 |
40 | ### MS2109
41 |
42 | 配套的AT24C16 EEPROM可以直接买套片,或者用EEPROM编程器烧录。
43 | 可以使用烧录夹在板子断电状态进行烧录。
44 |
45 | MS2109的固件来自 [Yuzuki HCC HDMI](https://oshwhub.com/gloomyghost/yuzuki-hcc) 项目,可通过HEX文件编辑器编辑固件实现修改设备名。
46 |
47 | ## 感谢
48 | https://oshwhub.com/gloomyghost/yuzuki-hcc
49 |
50 | https://materialdesignicons.com/icon/
51 |
52 | https://www.riverbankcomputing.com/software/pyqt/
53 |
54 | https://github.com/apmorton/pyhidapi
55 |
56 | https://www2.keil.com/mdk5
57 |
58 | 和其他开源项目
59 |
--------------------------------------------------------------------------------
/document/images/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/document/images/1.png
--------------------------------------------------------------------------------
/document/images/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/document/images/2.png
--------------------------------------------------------------------------------
/document/images/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/document/images/3.png
--------------------------------------------------------------------------------
/document/images/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/document/images/4.png
--------------------------------------------------------------------------------
/document/images/5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jackadminx/KVM-Card/9ab797d7761f4947798d1615dd8b41611b949efc/document/images/5.jpg
--------------------------------------------------------------------------------