fix #68

Merged
p9o3yklam merged 3 commits from main into llllllllllllllCC 4 months ago

@ -60,6 +60,27 @@ class InputProcessor(QObject):
# 6. 返回处理结果
return True
def process_text_commit(self, text: str) -> bool:
"""处理输入法提交的完整文本(支持中文输入)"""
if not text:
return False
# 逐个处理提交的字符
for char in text:
self.input_buffer += char
self.current_position += 1
# 发送每个字符的text_changed信号
self.text_changed.emit(char)
# 发送完整的文本提交信号
self.key_pressed.emit(f"text_commit:{text}")
# 检查是否完成输入
if self.expected_text and self.input_buffer == self.expected_text:
self.input_completed.emit()
return True
def get_current_input(self) -> str:
# 实现获取当前输入逻辑

@ -19,6 +19,7 @@ class TypingLogic:
"""
检查用户输入与学习材料的匹配情况
- 逐字符比较逻辑
- 支持中文整词匹配
- 进度跟踪
- 准确率计算
- 返回字典包含:
@ -42,13 +43,31 @@ class TypingLogic:
user_text = user_text[:self.total_chars]
current_position = len(user_text)
# 检查当前输入是否正确
# 检查当前输入是否正确(支持中文整词匹配)
correct = True
expected_char = ''
if self.current_index < self.total_chars:
expected_char = self.learning_content[self.current_index]
if len(user_text) > self.current_index and user_text[self.current_index] != expected_char:
correct = False
# 中文整词匹配优化
# 如果当前位置是中文文本的开始,尝试进行整词匹配
if self._is_chinese_text_start(self.current_index):
# 获取期望的中文词组
expected_word = self._get_chinese_word_at(self.current_index)
# 获取用户输入的对应部分
user_word = user_text[self.current_index:min(self.current_index + len(expected_word), len(user_text))]
# 如果用户输入的词组与期望词组匹配,则认为是正确的
if user_word == expected_word:
correct = True
else:
# 如果整词不匹配,回退到逐字符匹配
if len(user_text) > self.current_index and user_text[self.current_index] != expected_char:
correct = False
else:
# 非中文词组开始位置,使用逐字符匹配
if len(user_text) > self.current_index and user_text[self.current_index] != expected_char:
correct = False
else:
# 已经完成所有输入
# 恢复原始的typed_chars值用于准确率计算
@ -78,21 +97,35 @@ class TypingLogic:
"accuracy": accuracy
}
def update_position(self, user_text: str):
def update_position(self, user_text: str) -> dict:
"""
更新当前索引和错误计数
- 根据用户输入更新当前位置
- 计算并更新错误计数
更新当前位置并计算错误数
- 支持中文整词匹配
- 逐字符比较逻辑回退机制
- 错误计数
- 位置更新
- 返回字典包含:
* new_position: 整数新的位置
* error_count: 整数错误数
* completed: 布尔值是否完成
"""
new_position = len(user_text)
# 更新当前索引位置
self.current_index = len(user_text)
# 重置错误计数
self.error_count = 0
# 使用中文整词匹配优化错误计算
self._calculate_errors_with_chinese_support(user_text)
# 计算新增的错误数
for i in range(self.current_index, min(new_position, self.total_chars)):
if user_text[i] != self.learning_content[i]:
self.error_count += 1
# 检查是否完成
completed = self.current_index >= self.total_chars
# 更新当前索引
self.current_index = new_position
return {
"new_position": self.current_index,
"error_count": self.error_count,
"completed": completed
}
def get_expected_text(self, length: int = 10) -> str:
"""
@ -236,4 +269,85 @@ class TypingLogic:
return 0.0
finally:
# 清除递归保护标志
self._calculating_accuracy = False
self._calculating_accuracy = False
def _is_chinese_text_start(self, index: int) -> bool:
"""
判断指定位置是否是中文文本的开始
- 检查当前字符是否为中文
- 检查前一个字符是否为非中文或空格
"""
if index < 0 or index >= len(self.learning_content):
return False
current_char = self.learning_content[index]
# 检查当前字符是否为中文
if not self._is_chinese_char(current_char):
return False
# 如果是第一个字符,或者是紧跟在非中文字符后的中文,则认为是中文文本的开始
if index == 0:
return True
prev_char = self.learning_content[index - 1]
return not self._is_chinese_char(prev_char) or prev_char.isspace()
def _is_chinese_char(self, char: str) -> bool:
"""
判断字符是否为中文
- 使用Unicode范围判断中文字符
"""
return '\u4e00' <= char <= '\u9fff' or '\u3400' <= char <= '\u4dbf'
def _get_chinese_word_at(self, index: int) -> str:
"""
获取指定位置开始的中文词组
- 从当前位置开始连续获取中文字符
- 遇到非中文字符或字符串结束则停止
"""
if index < 0 or index >= len(self.learning_content):
return ""
word = ""
current_index = index
while current_index < len(self.learning_content):
char = self.learning_content[current_index]
if self._is_chinese_char(char):
word += char
current_index += 1
else:
break
return word
def _calculate_errors_with_chinese_support(self, user_text: str) -> None:
"""
使用中文整词匹配优化错误计算
- 优先尝试中文整词匹配
- 整词匹配失败时回退到逐字符匹配
"""
i = 0
while i < min(len(user_text), len(self.learning_content)):
# 检查当前位置是否为中文文本开始
if self._is_chinese_text_start(i):
# 获取期望的中文词组
expected_word = self._get_chinese_word_at(i)
# 获取用户输入的对应部分
user_word = user_text[i:min(i + len(expected_word), len(user_text))]
# 如果整词匹配成功,跳过整个词组
if user_word == expected_word:
i += len(expected_word)
continue
else:
# 整词匹配失败,回退到逐字符匹配
if user_text[i] != self.learning_content[i]:
self.error_count += 1
else:
# 非中文文本,使用逐字符匹配
if user_text[i] != self.learning_content[i]:
self.error_count += 1
i += 1

@ -5,7 +5,7 @@ from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel,
QComboBox, QSpinBox, QFontComboBox, QToolBar,
QSizePolicy)
from PyQt5.QtCore import Qt, QSize
from PyQt5.QtGui import QFont, QIcon, QPalette, QColor
from PyQt5.QtGui import QFont, QIcon, QPalette, QColor, QInputMethodEvent
import requests
import json
from datetime import datetime
@ -502,6 +502,48 @@ class WordTextEdit(QTextEdit):
# 让父类处理实际的文本编辑逻辑
super().keyPressEvent(event)
def inputMethodEvent(self, event):
"""重写输入法事件处理,支持中文输入法"""
if event.type() == QInputMethodEvent.InputMethod:
# 获取输入法事件中的文本
commit_string = event.commitString()
preedit_string = event.preeditString()
# 处理提交的文本(用户选择了候选词)
if commit_string:
if self.input_processor:
# 使用新的process_text_commit方法处理完整的提交文本
self.input_processor.process_text_commit(commit_string)
# 让父类处理实际的文本插入
super().inputMethodEvent(event)
# 触发文本变化信号,让学习模式能够处理
self.textChanged.emit()
# 处理预编辑文本(用户正在输入拼音)
elif preedit_string:
# 在预编辑阶段,我们只显示预编辑文本,不传递给输入处理器
# 这样可以避免在学习模式下出现错误的匹配
super().inputMethodEvent(event)
else:
# 其他情况,使用默认处理
super().inputMethodEvent(event)
else:
# 非输入法事件,使用默认处理
super().inputMethodEvent(event)
def inputMethodQuery(self, query):
"""重写输入法查询,提供更好的输入法支持"""
if query == Qt.ImEnabled:
return True # 启用输入法支持
elif query == Qt.ImCursorRectangle:
# 返回光标位置,帮助输入法定位候选词窗口
cursor_rect = self.cursorRect()
return cursor_rect
else:
return super().inputMethodQuery(query)
def setup_ui(self):
"""设置文本编辑区域样式"""
self.setStyleSheet("""

@ -642,15 +642,21 @@ class WordStyleMainWindow(QMainWindow):
cursor.movePosition(cursor.End)
self.text_edit.setTextCursor(cursor)
# 更新打字逻辑(只检查已显示的部分
# 更新打字逻辑(支持中文整词匹配
if display_text:
result = self.typing_logic.check_input(display_text)
self.typing_logic.update_position(display_text)
# 错误处理
# 错误处理(支持中文整词显示)
if not result['correct'] and display_text:
expected_char = result.get('expected', '')
self.status_bar.showMessage(f"输入错误,期望字符: '{expected_char}'", 2000)
# 如果是中文文本,显示更友好的错误信息
if self.typing_logic._is_chinese_char(expected_char):
# 获取期望的中文词组
expected_word = self.typing_logic._get_chinese_word_at(result['position'])
self.status_bar.showMessage(f"输入错误,期望词组: '{expected_word}'", 3000)
else:
self.status_bar.showMessage(f"输入错误,期望字符: '{expected_char}'", 2000)
self.highlight_next_char(result['position'], expected_char)
# 更新统计信息
@ -743,10 +749,16 @@ class WordStyleMainWindow(QMainWindow):
result = self.typing_logic.check_input(current_text)
self.typing_logic.update_position(current_text)
# 错误处理
# 错误处理(支持中文整词显示)
if not result['correct']:
expected_char = result.get('expected', '')
self.status_bar.showMessage(f"输入错误,期望字符: '{expected_char}'", 2000)
# 如果是中文文本,显示更友好的错误信息
if self.typing_logic._is_chinese_char(expected_char):
# 获取期望的中文词组
expected_word = self.typing_logic._get_chinese_word_at(result['position'])
self.status_bar.showMessage(f"输入错误,期望词组: '{expected_word}'", 3000)
else:
self.status_bar.showMessage(f"输入错误,期望字符: '{expected_char}'", 2000)
self.highlight_next_char(result['position'], expected_char)
# 更新统计信息
@ -762,10 +774,16 @@ class WordStyleMainWindow(QMainWindow):
result = self.typing_logic.check_input(current_text)
self.typing_logic.update_position(current_text)
# 错误处理
# 错误处理(支持中文整词显示)
if not result['correct']:
expected_char = result.get('expected', '')
self.status_bar.showMessage(f"输入错误,期望字符: '{expected_char}'", 2000)
# 如果是中文文本,显示更友好的错误信息
if self.typing_logic._is_chinese_char(expected_char):
# 获取期望的中文词组
expected_word = self.typing_logic._get_chinese_word_at(result['position'])
self.status_bar.showMessage(f"输入错误,期望词组: '{expected_word}'", 3000)
else:
self.status_bar.showMessage(f"输入错误,期望字符: '{expected_char}'", 2000)
self.highlight_next_char(result['position'], expected_char)
# 更新统计信息
@ -838,10 +856,16 @@ class WordStyleMainWindow(QMainWindow):
result = self.typing_logic.check_input(display_text)
self.typing_logic.update_position(display_text)
# 错误处理
# 错误处理(支持中文整词显示)
if not result['correct'] and display_text:
expected_char = result.get('expected', '')
self.status_bar.showMessage(f"输入错误,期望字符: '{expected_char}'", 2000)
# 如果是中文文本,显示更友好的错误信息
if self.typing_logic._is_chinese_char(expected_char):
# 获取期望的中文词组
expected_word = self.typing_logic._get_chinese_word_at(result['position'])
self.status_bar.showMessage(f"输入错误,期望词组: '{expected_word}'", 3000)
else:
self.status_bar.showMessage(f"输入错误,期望字符: '{expected_char}'", 2000)
self.highlight_next_char(result['position'], expected_char)
# 更新统计信息

Loading…
Cancel
Save