feat: Add page_refresh global tool and update voice shortcut to Ctrl+Space

- Add page_refresh tool to reload the page via MCP
- Change push-to-talk shortcut from Ctrl+S to Ctrl+Space
- Use capture phase for keyboard events to intercept before terminal
This commit is contained in:
2026-02-13 21:41:56 -06:00
parent 8ddf5dc4f3
commit e867b7873e
4 changed files with 37 additions and 17 deletions

View File

@@ -47,7 +47,7 @@ const displayText = computed(() => {
if (interimTranscript.value) {
return transcript.value + ' ' + interimTranscript.value
}
return transcript.value || 'Presiona el micrófono o mantén Ctrl+S...'
return transcript.value || 'Presiona el micrófono o mantén Ctrl+Space...'
})
const containerStyle = computed(() => {
@@ -252,10 +252,11 @@ function stopDrag() {
document.removeEventListener('mouseup', stopDrag)
}
// Keyboard shortcut handlers (Ctrl+S)
// Keyboard shortcut handlers (Ctrl+Space)
function handleKeyDown(e: KeyboardEvent) {
if (e.ctrlKey && e.key.toLowerCase() === 's') {
if (e.ctrlKey && e.key === ' ') {
e.preventDefault()
e.stopImmediatePropagation() // Prevent terminal and other handlers from receiving
// Ignore if already holding
if (keyDownTime > 0) return
@@ -267,19 +268,21 @@ function handleKeyDown(e: KeyboardEvent) {
isOpen.value = true
}
// Start recording after 500ms hold
// Start recording after 150ms hold
holdTimeout = window.setTimeout(() => {
if (keyDownTime > 0 && !isRecording.value) {
isPushToTalk.value = true
startRecording()
}
}, 500)
}, 150)
}
}
function handleKeyUp(e: KeyboardEvent) {
// Only react to 's' key release, ignore Control
if (e.key.toLowerCase() === 's' && keyDownTime > 0) {
// Only react to Space release when Ctrl+Space was pressed
if (e.key === ' ' && keyDownTime > 0) {
e.preventDefault()
e.stopImmediatePropagation() // Prevent terminal and other handlers from receiving
console.log('[Voice] Key S released, isPushToTalk:', isPushToTalk.value, 'isRecording:', isRecording.value)
if (holdTimeout) {
@@ -287,9 +290,9 @@ function handleKeyUp(e: KeyboardEvent) {
holdTimeout = null
}
// If was push-to-talk recording, stop and send after 500ms
// If was push-to-talk recording, stop and send after 1200ms
if (isPushToTalk.value && isRecording.value) {
console.log('[Voice] Stopping recording, will send in 500ms')
console.log('[Voice] Stopping recording, will send in 1200ms')
stopRecording()
setTimeout(() => {
console.log('[Voice] Sending transcript:', transcript.value.trim())
@@ -301,7 +304,7 @@ function handleKeyUp(e: KeyboardEvent) {
isPushToTalk.value = false
close()
}
}, 500)
}, 1200)
}
keyDownTime = 0
@@ -348,16 +351,17 @@ function sendTranscriptAndClose() {
onMounted(() => {
recognition = initRecognition()
document.addEventListener('keydown', handleKeyDown)
document.addEventListener('keyup', handleKeyUp)
// Use capture phase to intercept before terminal or other elements
document.addEventListener('keydown', handleKeyDown, { capture: true })
document.addEventListener('keyup', handleKeyUp, { capture: true })
})
onBeforeUnmount(() => {
stopRecording()
recognition = null
disconnectSocket()
document.removeEventListener('keydown', handleKeyDown)
document.removeEventListener('keyup', handleKeyUp)
document.removeEventListener('keydown', handleKeyDown, { capture: true })
document.removeEventListener('keyup', handleKeyUp, { capture: true })
document.removeEventListener('mousemove', onDrag)
document.removeEventListener('mouseup', stopDrag)
if (holdTimeout) clearTimeout(holdTimeout)
@@ -421,7 +425,7 @@ defineExpose({
<span class="final">{{ transcript }}</span>
<span class="interim">{{ interimTranscript }}</span>
<span v-if="!transcript && !interimTranscript" class="placeholder">
Presiona el micrófono o mantén Ctrl+S...
Presiona el micrófono o mantén Ctrl+Space...
</span>
</div>