rush_sync_server/ui/
terminal.rs

1// =====================================================
2// FILE: src/ui/terminal.rs - VOLLSTÄNDIGE KEYBOARD-KONTROLLE
3// =====================================================
4
5use crate::core::constants::APP_TITLE;
6use crate::core::prelude::*;
7use crate::i18n::get_translation;
8use crossterm::{
9    cursor, execute,
10    style::ResetColor,
11    terminal::{
12        self, disable_raw_mode, enable_raw_mode, ClearType, EnterAlternateScreen,
13        LeaveAlternateScreen,
14    },
15};
16use std::io::Stdout;
17
18pub struct TerminalManager {
19    stdout: Stdout,
20    raw_mode_enabled: bool,
21}
22
23impl TerminalManager {
24    pub async fn new() -> Result<Self> {
25        let stdout = io::stdout();
26        Ok(Self {
27            stdout,
28            raw_mode_enabled: false,
29        })
30    }
31
32    pub async fn setup(&mut self) -> Result<()> {
33        // ✅ SCHRITT 1: VOLLSTÄNDIGER RAW MODE
34        self.enable_full_raw_mode().await?;
35
36        // ✅ SCHRITT 2: TERMINAL SETUP
37        execute!(
38            self.stdout,
39            terminal::Clear(ClearType::All),
40            EnterAlternateScreen,
41            terminal::DisableLineWrap,
42            terminal::SetTitle(APP_TITLE),
43            // Cursor-Zustand beim Setup zurücksetzen
44            crossterm::style::Print("\x1B]112\x07"), // Reset cursor color
45            crossterm::style::Print("\x1B[0 q"),     // Reset cursor shape
46            cursor::Hide
47        )?;
48
49        log::info!("✅ Terminal initialized");
50        log::debug!("🔧 Full raw mode enabled - All shortcuts intercepted");
51
52        Ok(())
53    }
54
55    /// ✅ VOLLSTÄNDIGER RAW MODE - Übernimmt ALLE Tastatur-Events
56    async fn enable_full_raw_mode(&mut self) -> Result<()> {
57        // Standard Raw Mode aktivieren
58        enable_raw_mode()?;
59        self.raw_mode_enabled = true;
60
61        // ✅ ERWEITERTE TERMINAL-KONTROLLE
62        execute!(
63            self.stdout,
64            // Alle Terminal-Escape-Sequenzen deaktivieren
65            crossterm::style::Print("\x1B[?1000h"), // Mouse tracking an (optional)
66            crossterm::style::Print("\x1B[?1002h"), // Cell motion mouse tracking
67            crossterm::style::Print("\x1B[?1015h"), // Enable urxvt mouse mode
68            crossterm::style::Print("\x1B[?1006h"), // Enable SGR mouse mode
69            // Spezielle Key-Kombinationen abfangen
70            crossterm::style::Print("\x1B[?1049h"), // Enable alternative screen buffer
71        )?;
72
73        log::debug!("🚀 Enhanced raw mode enabled - Terminal shortcuts bypassed");
74        Ok(())
75    }
76
77    pub async fn cleanup(&mut self) -> Result<()> {
78        log::info!("🔄 Starting terminal cleanup...");
79
80        // ✅ SCHRITT 1: Raw Mode zuerst deaktivieren
81        if self.raw_mode_enabled {
82            self.disable_full_raw_mode().await?;
83        }
84
85        // ✅ SCHRITT 2: Cursor-Farbe KOMPLETT zurücksetzen
86        execute!(
87            self.stdout,
88            // Reset cursor color (multiple standards for maximum compatibility)
89            crossterm::style::Print("\x1B]12;\x07"), // Xterm: empty = default
90            crossterm::style::Print("\x1B]Pl\x1B\\"), // iTerm2: reset
91            crossterm::style::Print("\x1B]112\x07"), // OSC 112: reset cursor color
92            crossterm::style::Print("\x1B[0 q"),     // Reset cursor shape to default
93            ResetColor,                              // Reset ANSI colors
94            cursor::Show,                            // Show cursor
95        )?;
96
97        // ✅ SCHRITT 3: Terminal-Modi zurücksetzen
98        execute!(
99            self.stdout,
100            terminal::Clear(ClearType::All),
101            LeaveAlternateScreen,
102            terminal::EnableLineWrap,
103            cursor::MoveTo(0, 0)
104        )?;
105
106        // ✅ SCHRITT 4: FINAL RESET - garantiert Standard-Terminal
107        execute!(
108            self.stdout,
109            // Kompletter Reset aller Terminal-Modi
110            crossterm::style::Print("\x1B[!p"), // RIS - Reset to Initial State
111            crossterm::style::Print("\x1B]12;white\x07"), // Explicit white cursor color
112            crossterm::style::Print("\x1B[0 q"), // Default cursor shape
113            crossterm::style::Print("\x1B[?25h"), // Show cursor
114            ResetColor,                         // Final color reset
115        )?;
116
117        // Buffer explizit leeren
118        self.stdout.flush()?;
119
120        log::info!("{}", get_translation("terminal.cleanup.done", &[]));
121        Ok(())
122    }
123
124    /// ✅ ERWEITERTEN RAW MODE DEAKTIVIEREN
125    async fn disable_full_raw_mode(&mut self) -> Result<()> {
126        if !self.raw_mode_enabled {
127            return Ok(());
128        }
129
130        // Erweiterte Modi deaktivieren
131        execute!(
132            self.stdout,
133            // Mouse tracking deaktivieren
134            crossterm::style::Print("\x1B[?1000l"), // Mouse tracking off
135            crossterm::style::Print("\x1B[?1002l"), // Cell motion mouse tracking off
136            crossterm::style::Print("\x1B[?1015l"), // Disable urxvt mouse mode
137            crossterm::style::Print("\x1B[?1006l"), // Disable SGR mouse mode
138            // Alternative screen buffer deaktivieren
139            crossterm::style::Print("\x1B[?1049l"), // Disable alternative screen buffer
140        )?;
141
142        // Standard Raw Mode deaktivieren
143        disable_raw_mode()?;
144        self.raw_mode_enabled = false;
145
146        log::debug!("🔄 Enhanced raw mode disabled - Terminal shortcuts restored");
147        Ok(())
148    }
149
150    /// ✅ DEBUG: Prüfe ob Raw Mode aktiv ist
151    pub fn is_raw_mode_enabled(&self) -> bool {
152        self.raw_mode_enabled
153    }
154
155    /// ✅ FORCE RAW MODE (falls es während der Laufzeit verloren geht)
156    pub async fn force_raw_mode(&mut self) -> Result<()> {
157        if !self.raw_mode_enabled {
158            log::warn!("🚨 Raw mode was lost, re-enabling...");
159            self.enable_full_raw_mode().await?;
160        }
161        Ok(())
162    }
163}
164
165// ✅ SICHERER DESTRUCTOR
166impl Drop for TerminalManager {
167    fn drop(&mut self) {
168        if self.raw_mode_enabled {
169            // Notfall-Cleanup falls cleanup() nicht aufgerufen wurde
170            let _ = futures::executor::block_on(self.disable_full_raw_mode());
171            log::warn!("🚨 Emergency terminal cleanup in destructor");
172        }
173    }
174}