Merge pull request #15488 from kevin-ho/fix/tui-mouse-toggle
fix(tui): proactive mouse disable on ConPTY + /mouse toggle command
This commit is contained in:
commit
6407b3d5b3
@ -2789,6 +2789,23 @@ def _(rid, params: dict) -> dict:
|
||||
_write_config_key("display.tui_statusbar", nv)
|
||||
return _ok(rid, {"key": key, "value": nv})
|
||||
|
||||
if key == "mouse":
|
||||
raw = str(value or "").strip().lower()
|
||||
display = _load_cfg().get("display") if isinstance(_load_cfg().get("display"), dict) else {}
|
||||
current = bool(display.get("tui_mouse", True))
|
||||
|
||||
if raw in ("", "toggle"):
|
||||
nv = not current
|
||||
elif raw == "on":
|
||||
nv = True
|
||||
elif raw == "off":
|
||||
nv = False
|
||||
else:
|
||||
return _err(rid, 4002, f"unknown mouse value: {value}")
|
||||
|
||||
_write_config_key("display.tui_mouse", nv)
|
||||
return _ok(rid, {"key": key, "value": "on" if nv else "off"})
|
||||
|
||||
if key in ("prompt", "personality", "skin"):
|
||||
try:
|
||||
cfg = _load_cfg()
|
||||
@ -2917,6 +2934,10 @@ def _(rid, params: dict) -> dict:
|
||||
display.get("tui_statusbar", "top") if isinstance(display, dict) else "top"
|
||||
)
|
||||
return _ok(rid, {"value": _coerce_statusbar(raw)})
|
||||
if key == "mouse":
|
||||
display = _load_cfg().get("display")
|
||||
on = display.get("tui_mouse", True) if isinstance(display, dict) else True
|
||||
return _ok(rid, {"value": "on" if on else "off"})
|
||||
if key == "mtime":
|
||||
cfg_path = _hermes_home / "config.yaml"
|
||||
try:
|
||||
|
||||
@ -53,7 +53,7 @@ export function AlternateScreen(t0: Props) {
|
||||
}
|
||||
|
||||
writeRaw(
|
||||
ENTER_ALT_SCREEN + ERASE_SCROLLBACK + ERASE_SCREEN + CURSOR_HOME + (mouseTracking ? ENABLE_MOUSE_TRACKING : '')
|
||||
ENTER_ALT_SCREEN + ERASE_SCROLLBACK + ERASE_SCREEN + CURSOR_HOME + (mouseTracking ? ENABLE_MOUSE_TRACKING : DISABLE_MOUSE_TRACKING)
|
||||
)
|
||||
ink?.setAltScreenActive(true, mouseTracking)
|
||||
|
||||
|
||||
@ -1121,6 +1121,23 @@ export default class Ink {
|
||||
this.repaint()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle mouse tracking at runtime while the alt screen is active.
|
||||
* Writes the appropriate DEC reset/set sequences so the terminal
|
||||
* (and ConPTY on Windows WSL2) reflects the change immediately.
|
||||
*/
|
||||
setAltScreenMouseTracking(enabled: boolean): void {
|
||||
if (this.altScreenMouseTracking === enabled) {
|
||||
return
|
||||
}
|
||||
|
||||
this.altScreenMouseTracking = enabled
|
||||
|
||||
if (this.altScreenActive) {
|
||||
this.options.stdout.write(enabled ? ENABLE_MOUSE_TRACKING : DISABLE_MOUSE_TRACKING)
|
||||
}
|
||||
}
|
||||
get isAltScreenActive(): boolean {
|
||||
return this.altScreenActive
|
||||
}
|
||||
|
||||
@ -1,18 +1,21 @@
|
||||
import { useStore } from '@nanostores/react'
|
||||
|
||||
import { GatewayProvider } from './app/gatewayContext.js'
|
||||
import { useMainApp } from './app/useMainApp.js'
|
||||
import { $uiState } from './app/uiStore.js'
|
||||
import { AppLayout } from './components/appLayout.js'
|
||||
import { MOUSE_TRACKING } from './config/env.js'
|
||||
import type { GatewayClient } from './gatewayClient.js'
|
||||
|
||||
export function App({ gw }: { gw: GatewayClient }) {
|
||||
const { appActions, appComposer, appProgress, appStatus, appTranscript, gateway } = useMainApp(gw)
|
||||
const { mouseTracking } = useStore($uiState)
|
||||
|
||||
return (
|
||||
<GatewayProvider value={gateway}>
|
||||
<AppLayout
|
||||
actions={appActions}
|
||||
composer={appComposer}
|
||||
mouseTracking={MOUSE_TRACKING}
|
||||
mouseTracking={mouseTracking}
|
||||
progress={appProgress}
|
||||
status={appStatus}
|
||||
transcript={appTranscript}
|
||||
|
||||
@ -88,6 +88,7 @@ export interface UiState {
|
||||
detailsMode: DetailsMode
|
||||
info: null | SessionInfo
|
||||
inlineDiffs: boolean
|
||||
mouseTracking: boolean
|
||||
sections: SectionVisibility
|
||||
showCost: boolean
|
||||
showReasoning: boolean
|
||||
|
||||
@ -84,6 +84,27 @@ export const coreCommands: SlashCommand[] = [
|
||||
run: (_arg, ctx) => ctx.session.die()
|
||||
},
|
||||
|
||||
{
|
||||
aliases: ['scroll'],
|
||||
help: 'toggle mouse/wheel tracking [on|off|toggle]',
|
||||
name: 'mouse',
|
||||
run: (arg, ctx) => {
|
||||
const current = ctx.ui.mouseTracking
|
||||
const next = flagFromArg(arg, current)
|
||||
|
||||
if (next === null) {
|
||||
return ctx.transcript.sys('usage: /mouse [on|off|toggle]')
|
||||
}
|
||||
|
||||
patchUiState({ mouseTracking: next })
|
||||
ctx.gateway
|
||||
.rpc<ConfigSetResponse>('config.set', { key: 'mouse', value: next ? 'on' : 'off' })
|
||||
.catch(() => {})
|
||||
|
||||
queueMicrotask(() => ctx.transcript.sys(`mouse tracking ${next ? 'on' : 'off'}`))
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
aliases: ['new'],
|
||||
help: 'start a new session',
|
||||
|
||||
@ -2,6 +2,7 @@ import { atom } from 'nanostores'
|
||||
|
||||
import { ZERO } from '../domain/usage.js'
|
||||
import { DEFAULT_THEME } from '../theme.js'
|
||||
import { MOUSE_TRACKING } from '../config/env.js'
|
||||
|
||||
import type { UiState } from './interfaces.js'
|
||||
|
||||
@ -12,6 +13,7 @@ const buildUiState = (): UiState => ({
|
||||
detailsMode: 'collapsed',
|
||||
info: null,
|
||||
inlineDiffs: true,
|
||||
mouseTracking: MOUSE_TRACKING,
|
||||
sections: {},
|
||||
showCost: false,
|
||||
showReasoning: false,
|
||||
|
||||
@ -46,6 +46,7 @@ export const applyDisplay = (cfg: ConfigFullResponse | null, setBell: (v: boolea
|
||||
compact: !!d.tui_compact,
|
||||
detailsMode: resolveDetailsMode(d),
|
||||
inlineDiffs: d.inline_diffs !== false,
|
||||
mouseTracking: d.tui_mouse !== false,
|
||||
sections: resolveSections(d.sections),
|
||||
showCost: !!d.show_cost,
|
||||
showReasoning: !!d.show_reasoning,
|
||||
|
||||
@ -61,6 +61,7 @@ export interface ConfigDisplayConfig {
|
||||
streaming?: boolean
|
||||
thinking_mode?: string
|
||||
tui_compact?: boolean
|
||||
tui_mouse?: boolean
|
||||
tui_statusbar?: 'bottom' | 'off' | 'on' | 'top' | boolean
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user