|
| 1 | +import sys |
| 2 | +import subprocess |
| 3 | +import threading |
| 4 | +import requests |
| 5 | +from PyQt5.QtWidgets import QWidget, QApplication, QVBoxLayout, QHBoxLayout, QPushButton, QLabel |
| 6 | +from PyQt5.QtGui import QCursor, QPixmap |
| 7 | +from PyQt5.QtGui import QFont |
| 8 | +from PyQt5.QtCore import Qt, QTimer |
| 9 | + |
| 10 | + |
| 11 | +# Google Input Tools API |
| 12 | +API_URL = 'https://inputtools.google.com/request?text={text}&itc={itc}&num={num}' |
| 13 | +solagn = "Giving voice to the deaf community(为聋哑人社群发声)" |
| 14 | + |
| 15 | + |
| 16 | +def input_method_conversion(query, num=10): |
| 17 | + url = API_URL.format(text=query, itc='zh-t-i0-pinyin', num=num) |
| 18 | + try: |
| 19 | + response = requests.post(url) |
| 20 | + if response.status_code == 200: |
| 21 | + print(response.json()[1][0][1]) |
| 22 | + data = response.json()[1][0][1] |
| 23 | + return data |
| 24 | + else: |
| 25 | + return None |
| 26 | + except Exception as e: |
| 27 | + print(e) |
| 28 | + return None |
| 29 | + |
| 30 | + |
| 31 | +def get_platform(): |
| 32 | + platforms = { |
| 33 | + 'linux1': 'Linux', |
| 34 | + 'linux2': 'Linux', |
| 35 | + 'darwin': 'OS X', |
| 36 | + 'win32': 'Windows' |
| 37 | + } |
| 38 | + if sys.platform not in platforms: |
| 39 | + return sys.platform |
| 40 | + |
| 41 | + return platforms[sys.platform] |
| 42 | + |
| 43 | + |
| 44 | +def speak(text): |
| 45 | + platform = get_platform() |
| 46 | + if platform == 'Windows': |
| 47 | + subprocess.call( |
| 48 | + ['powershell', 'Add-Type –AssemblyName System.Speech; (New-Object System.Speech.Synthesis.SpeechSynthesizer).Speak("{0}")'.format(text)]) |
| 49 | + elif platform == 'Linux': |
| 50 | + subprocess.call(['espeak', text]) |
| 51 | + elif platform == 'OS X': |
| 52 | + subprocess.call(['say', text]) |
| 53 | + |
| 54 | + |
| 55 | +class Keyboard(QWidget): |
| 56 | + def __init__(self): |
| 57 | + super().__init__() |
| 58 | + |
| 59 | + self.setWindowTitle( |
| 60 | + "TalkToWorld中文语音键盘 Giving voice to the deaf community") |
| 61 | + self.layout = QVBoxLayout() |
| 62 | + self.setLayout(self.layout) |
| 63 | + |
| 64 | + # 创建显示区域 |
| 65 | + self.label = QLabel() |
| 66 | + self.label.setAlignment(Qt.AlignCenter) |
| 67 | + self.label.setStyleSheet("background-color: white;") |
| 68 | + self.label.setFont(QFont("Arial", 32)) |
| 69 | + self.label.setStyleSheet( |
| 70 | + "background-color:rgb(227, 227, 227); border-radius:10px; padding: 10px;") |
| 71 | + self.layout.addWidget(self.label) |
| 72 | + |
| 73 | + self.label.setText(solagn) |
| 74 | + |
| 75 | + def blink(): |
| 76 | + self.label.setStyleSheet( |
| 77 | + "color:green") |
| 78 | + QTimer.singleShot(100, lambda: self.label.setStyleSheet( |
| 79 | + "color:blue")) |
| 80 | + |
| 81 | + timer = QTimer() |
| 82 | + timer.timeout.connect(blink) |
| 83 | + timer.start(100) |
| 84 | + |
| 85 | + QTimer.singleShot(4000, lambda: (timer.stop(), self.label.setText(""))) |
| 86 | + |
| 87 | + self.row_layout = QHBoxLayout() |
| 88 | + self.layout.addLayout(self.row_layout) |
| 89 | + |
| 90 | + pixmap = QPixmap("cursor.png").scaled(64, 64) |
| 91 | + cursor = QCursor(pixmap, hotX=-1, hotY=-1) |
| 92 | + self.setCursor(cursor) |
| 93 | +# 创建键盘按钮 |
| 94 | + keys = [ |
| 95 | + ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'], |
| 96 | + ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p'], |
| 97 | + ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l'], |
| 98 | + ['z', 'x', 'c', 'v', 'b', 'n', 'm'] |
| 99 | + ] |
| 100 | + |
| 101 | + for row in keys: |
| 102 | + row_layout = QHBoxLayout() |
| 103 | + for key in row: |
| 104 | + button = QPushButton(key) |
| 105 | + button.setMaximumWidth(128) |
| 106 | + button.setMaximumHeight(128) |
| 107 | + button.setFont(QFont("Arial", 64)) |
| 108 | + button.setStyleSheet( |
| 109 | + "QPushButton{background-color:rgb(255,255,255);border-radius:10px;}" |
| 110 | + "QPushButton:hover{background-color:rgb(240,240,240);}" |
| 111 | + ) |
| 112 | + button.clicked.connect(self.button_clicked) |
| 113 | + row_layout.addWidget(button) |
| 114 | + self.layout.addLayout(row_layout) |
| 115 | + |
| 116 | + # 添加特殊功能键 |
| 117 | + special_keys_layout = QHBoxLayout() |
| 118 | + clear_button = QPushButton("🧹") |
| 119 | + clear_button.setMaximumWidth(200) |
| 120 | + clear_button.setMaximumHeight(200) |
| 121 | + clear_button.setFont(QFont("Arial", 64)) |
| 122 | + clear_button.setStyleSheet( |
| 123 | + "QPushButton{background-color:rgb(227, 227, 227);border-radius:10px;}" |
| 124 | + "QPushButton:hover{background-color:rgb(240,240,240);}" |
| 125 | + ) |
| 126 | + clear_button.clicked.connect(self.clear_clicked) |
| 127 | + special_keys_layout.addWidget(clear_button) |
| 128 | + |
| 129 | + backspace_button = QPushButton("DEL") |
| 130 | + backspace_button.setMaximumWidth(200) |
| 131 | + backspace_button.setMaximumHeight(200) |
| 132 | + backspace_button.setFont(QFont("Arial", 48)) |
| 133 | + backspace_button.setStyleSheet( |
| 134 | + "QPushButton{background-color:rgb(227, 227, 227);border-radius:10px;}" |
| 135 | + "QPushButton:hover{background-color:rgb(240,240,240);}" |
| 136 | + ) |
| 137 | + backspace_button.clicked.connect(self.backspace_clicked) |
| 138 | + special_keys_layout.addWidget(backspace_button) |
| 139 | + |
| 140 | + speak_button = QPushButton("🗣️") |
| 141 | + speak_button.setMaximumWidth(200) |
| 142 | + speak_button.setMaximumHeight(200) |
| 143 | + speak_button.setFont(QFont("Arial", 64)) |
| 144 | + speak_button.setStyleSheet( |
| 145 | + "QPushButton{background-color:rgb(227, 227, 227);border-radius:10px;}" |
| 146 | + "QPushButton:hover{background-color:rgb(240,240,240);}" |
| 147 | + ) |
| 148 | + speak_button.clicked.connect(self.speak_clicked) |
| 149 | + special_keys_layout.addWidget(speak_button) |
| 150 | + |
| 151 | + self.layout.addLayout(special_keys_layout) |
| 152 | + self.continue_typing_cache = '' |
| 153 | + |
| 154 | + def speak_clicked(self): |
| 155 | + text = self.label.text() |
| 156 | + speak(text) |
| 157 | + |
| 158 | + def button_clicked(self): |
| 159 | + button = self.sender() |
| 160 | + text = button.text() |
| 161 | + self.continue_typing_cache = self.continue_typing_cache + text |
| 162 | + if text.isdigit(): |
| 163 | + self.label.setText(self.label.text() + ' ' + text) |
| 164 | + speak(text) |
| 165 | + return |
| 166 | + if self.continue_typing_cache: |
| 167 | + print(self.continue_typing_cache) |
| 168 | + self.remove_buttons() |
| 169 | + hanzi = input_method_conversion(self.continue_typing_cache) |
| 170 | + else: |
| 171 | + hanzi = input_method_conversion(text) |
| 172 | + |
| 173 | + if self.continue_typing_cache: |
| 174 | + max_width = 200 |
| 175 | + font_size = 24 |
| 176 | + else: |
| 177 | + max_width = 128 |
| 178 | + font_size = 64 |
| 179 | + for key in hanzi: |
| 180 | + self.candidate_button = QPushButton(key) |
| 181 | + self.candidate_button.setMaximumWidth(max_width) |
| 182 | + self.candidate_button.setMaximumHeight(100) |
| 183 | + self.candidate_button.setFont(QFont("Arial", font_size)) |
| 184 | + self.candidate_button.setStyleSheet( |
| 185 | + "QPushButton{background-color:rgb(255,255,200);border-radius:10px;font-weight:bold;}" |
| 186 | + "QPushButton:hover{background-color:rgb(240,240,240);}" |
| 187 | + ) |
| 188 | + self.candidate_button.clicked.connect( |
| 189 | + self.button_candidate_clicked) |
| 190 | + self.row_layout.addWidget(self.candidate_button) |
| 191 | + self.layout.addLayout(self.row_layout) |
| 192 | + |
| 193 | + def clear_clicked(self): |
| 194 | + self.label.clear() |
| 195 | + |
| 196 | + def backspace_clicked(self): |
| 197 | + text = self.label.text() |
| 198 | + self.label.setText(text[:-1]) |
| 199 | + self.remove_buttons() |
| 200 | + self.continue_typing_cache = '' |
| 201 | + |
| 202 | + def button_candidate_clicked(self): |
| 203 | + self.continue_typing_cache = '' |
| 204 | + button = self.sender() |
| 205 | + self.label.setText(self.label.text() + button.text()) |
| 206 | + speak(button.text()) |
| 207 | + self.remove_buttons() |
| 208 | + |
| 209 | + def remove_buttons(self): |
| 210 | + for i in reversed(range(self.row_layout.count())): |
| 211 | + item = self.row_layout.itemAt(i) |
| 212 | + if isinstance(item.widget(), QPushButton): |
| 213 | + btn = item.widget() |
| 214 | + self.row_layout.removeWidget(btn) |
| 215 | + btn.setVisible(False) |
| 216 | + btn.deleteLater() |
| 217 | + |
| 218 | + |
| 219 | +if __name__ == "__main__": |
| 220 | + app = QApplication([]) |
| 221 | + keyboard = Keyboard() |
| 222 | + keyboard.showFullScreen() |
| 223 | + # Create a thread |
| 224 | + solagn = threading.Thread(target=speak, args=(solagn,)) |
| 225 | + # Start the thread |
| 226 | + solagn.start() |
| 227 | + app.exec_() |
0 commit comments