fix: 长按 1s 录音 + 3s 复位 CapsLock 灯 + 防抖保护
- 分离两个定时器:longPressTimer(1s) 启动录音,capsResetTimer(3s) 复位灯 - 1s 时只确认录音状态,不操作 CapsLock 灯 - 3s 时才模拟 CapsLock 按键复位灯,避免手指抖动导致状态闪烁 - 松开时自动取消 3s 定时器,避免松开后再复位 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
d4db8756b5
commit
13d4aae725
@ -39,19 +39,29 @@ VoiceInputService::VoiceInputService(ConfigManager* configManager,
|
||||
, impl_(std::make_unique<Impl>())
|
||||
{
|
||||
impl_->sttEngine = sttEngine;
|
||||
|
||||
// 1s 定时器:启动录音
|
||||
longPressTimer_ = new QTimer(this);
|
||||
longPressTimer_->setSingleShot(true);
|
||||
connect(longPressTimer_, &QTimer::timeout, this, [this]() {
|
||||
// 长按超时仍未松开 → 确认为长按录音
|
||||
if (!longPressDetected_) {
|
||||
longPressDetected_ = true;
|
||||
capsResetDone_ = true;
|
||||
// 立即复位 CapsLock,不等用户松开
|
||||
simulateCapsLock();
|
||||
emit statusChanged("正在录音...");
|
||||
}
|
||||
});
|
||||
|
||||
// 3s 定时器:复位 CapsLock 灯(防抖:只在未按下状态下执行)
|
||||
capsResetTimer_ = new QTimer(this);
|
||||
capsResetTimer_->setSingleShot(true);
|
||||
connect(capsResetTimer_, &QTimer::timeout, this, [this]() {
|
||||
// 如果已经松开(recording_ = false),不执行
|
||||
if (recording_) {
|
||||
capsResetDone_ = true;
|
||||
simulateCapsLock();
|
||||
LOG_DEBUG(kTag, "CapsLock 灯已复位(防抖保护中)");
|
||||
}
|
||||
});
|
||||
|
||||
// 松开后的冷却定时器
|
||||
cooldownTimer_ = new QTimer(this);
|
||||
cooldownTimer_->setSingleShot(true);
|
||||
@ -111,6 +121,7 @@ void VoiceInputService::stop() {
|
||||
if (!running_) return;
|
||||
|
||||
longPressTimer_->stop();
|
||||
capsResetTimer_->stop();
|
||||
cooldownTimer_->stop();
|
||||
|
||||
if (impl_->audioCapture) {
|
||||
@ -146,10 +157,12 @@ void VoiceInputService::onHotkeyActivated() {
|
||||
LOG_DEBUG(kTag, "快捷键激活(按下)");
|
||||
recording_ = true;
|
||||
longPressDetected_ = false;
|
||||
capsResetDone_ = false;
|
||||
audioBuffer_.clear();
|
||||
|
||||
// 启动长按定时器
|
||||
// 启动 1s 录音确认定时器 + 3s CapsLock 灯复位定时器
|
||||
longPressTimer_->start(longPressThreshold_);
|
||||
capsResetTimer_->start(capsResetDelayMs_);
|
||||
|
||||
// 开始音频采集(后台预采集)
|
||||
int deviceIndex = configManager_->get("audio.input_device").toInt();
|
||||
@ -164,6 +177,7 @@ void VoiceInputService::onHotkeyDeactivated() {
|
||||
LOG_DEBUG(kTag, "快捷键停用(松开)");
|
||||
recording_ = false;
|
||||
longPressTimer_->stop();
|
||||
capsResetTimer_->stop();
|
||||
|
||||
// 停止音频采集
|
||||
if (impl_->audioCapture && impl_->audioCapture->isRunning()) {
|
||||
@ -176,7 +190,7 @@ void VoiceInputService::onHotkeyDeactivated() {
|
||||
simulateCapsLock();
|
||||
emit statusChanged("短按:切换 CapsLock");
|
||||
} else {
|
||||
// 长按 → CapsLock 已在长按阈值时复位,松开后直接开始识别
|
||||
// 长按 → CapsLock 已在 3s 定时器时复位,松开后直接开始识别
|
||||
stopRecordingAndTranscribe();
|
||||
}
|
||||
|
||||
|
||||
@ -69,14 +69,16 @@ private:
|
||||
bool longPressDetected_ = false;
|
||||
bool capsResetDone_ = false; // CapsLock 复位后忽略重复 Activated
|
||||
bool cooldownActive_ = false; // 松开后的冷却期,防止立即重新触发
|
||||
int longPressThreshold_ = 1000;
|
||||
int releaseCooldownMs_ = 1000; // 松开后冷却时间
|
||||
int longPressThreshold_ = 1000; // 1s 启动录音
|
||||
int capsResetDelayMs_ = 3000; // 3s 后复位 CapsLock 灯
|
||||
int releaseCooldownMs_ = 1000; // 松开后冷却时间
|
||||
|
||||
std::vector<float> audioBuffer_;
|
||||
int audioSampleRate_ = 16000;
|
||||
|
||||
QTimer* longPressTimer_ = nullptr;
|
||||
QTimer* cooldownTimer_ = nullptr;
|
||||
QTimer* longPressTimer_ = nullptr; // 1s 启动录音
|
||||
QTimer* capsResetTimer_ = nullptr; // 3s 复位 CapsLock 灯
|
||||
QTimer* cooldownTimer_ = nullptr; // 松开后冷却
|
||||
|
||||
void startRecording();
|
||||
void stopRecordingAndTranscribe();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user