@@ -34,38 +34,20 @@ class _TerminalKeyboardState extends State<TerminalKeyboard> {
3434 }
3535
3636 void _sendKey (TerminalKey key) {
37- widget.terminal.keyInput (
38- key,
39- ctrl: _isCtrlActive,
40- alt: _isAltActive,
41- );
42-
43- if (_isCtrlActive || _isAltActive) {
44- setState (() {
45- _isCtrlActive = false ;
46- _isAltActive = false ;
47- });
37+ widget.terminal.keyInput (key, alt: _isAltActive);
38+ if (_isAltActive) {
39+ setState (() => _isAltActive = false );
4840 }
4941 }
5042
51- void _sendText (String text) {
52- if (_isCtrlActive) {
53- if (text.length == 1 ) {
54- final charCode = text.toLowerCase ().codeUnitAt (0 );
55- if (charCode >= 97 && charCode <= 122 ) {
56- widget.terminal.paste (String .fromCharCode (charCode - 96 ));
57- }
58- }
59- } else {
60- widget.terminal.paste (text);
61- }
43+ void _sendCtrlByte (String char) {
44+ final code = char.toUpperCase ().codeUnitAt (0 ) - 64 ;
45+ widget.terminal.textInput (String .fromCharCode (code));
46+ setState (() => _isCtrlActive = false );
47+ }
6248
63- if (_isCtrlActive || _isAltActive) {
64- setState (() {
65- _isCtrlActive = false ;
66- _isAltActive = false ;
67- });
68- }
49+ void _sendText (String text) {
50+ widget.terminal.paste (text);
6951 }
7052
7153 @override
@@ -78,58 +60,83 @@ class _TerminalKeyboardState extends State<TerminalKeyboard> {
7860 color: theme.colorScheme.surface,
7961 border: Border (top: BorderSide (color: theme.dividerColor)),
8062 ),
81- child: ListView (
82- scrollDirection: Axis .horizontal,
83- padding: const EdgeInsets .symmetric (horizontal: 4 ),
84- children: [
85-
86- _buildToggleKey ('CTRL' , _isCtrlActive, () => setState (() => _isCtrlActive = ! _isCtrlActive)),
87- _buildToggleKey ('ALT' , _isAltActive, () => setState (() => _isAltActive = ! _isAltActive)),
88- _buildVerticalDivider (),
63+ child: _isCtrlActive ? _buildCtrlActiveRow () : _buildNormalRow (),
64+ );
65+ }
8966
90- _buildTerminalKey ('ESC' , TerminalKey .escape),
91- _buildTerminalKey ('TAB' , TerminalKey .tab),
92- _buildTerminalKey ('↑' , TerminalKey .arrowUp),
93- _buildTerminalKey ('↓' , TerminalKey .arrowDown),
94- _buildTerminalKey ('←' , TerminalKey .arrowLeft),
95- _buildTerminalKey ('→' , TerminalKey .arrowRight),
96- _buildVerticalDivider (),
67+ Widget _buildNormalRow () {
68+ final theme = Theme .of (context);
69+ return ListView (
70+ scrollDirection: Axis .horizontal,
71+ padding: const EdgeInsets .symmetric (horizontal: 4 ),
72+ children: [
73+ _buildToggleKey ('CTRL' , _isCtrlActive, () => setState (() => _isCtrlActive = true )),
74+ _buildToggleKey ('ALT' , _isAltActive, () => setState (() => _isAltActive = ! _isAltActive)),
75+ _buildVerticalDivider (),
9776
98- _buildTerminalKey ('HOME' , TerminalKey .home),
99- _buildTerminalKey ('END' , TerminalKey .end),
100- _buildTerminalKey ('PGUP' , TerminalKey .pageUp),
101- _buildTerminalKey ('PGDN' , TerminalKey .pageDown),
102- _buildTerminalKey ('DEL' , TerminalKey .delete),
103- _buildVerticalDivider (),
77+ _buildTerminalKey ('ESC' , TerminalKey .escape),
78+ _buildTerminalKey ('TAB' , TerminalKey .tab),
79+ _buildTerminalKey ('↑' , TerminalKey .arrowUp),
80+ _buildTerminalKey ('↓' , TerminalKey .arrowDown),
81+ _buildTerminalKey ('←' , TerminalKey .arrowLeft),
82+ _buildTerminalKey ('→' , TerminalKey .arrowRight),
83+ _buildVerticalDivider (),
10484
105- _buildTerminalKey ('F1' , TerminalKey .f1),
106- _buildTerminalKey ('F2' , TerminalKey .f2),
107- _buildTerminalKey ('F3' , TerminalKey .f3),
108- _buildTerminalKey ('F4' , TerminalKey .f4),
109- _buildTerminalKey ('F5' , TerminalKey .f5),
110- _buildTerminalKey ('F6' , TerminalKey .f6),
111- _buildTerminalKey ('F7' , TerminalKey .f7),
112- _buildTerminalKey ('F8' , TerminalKey .f8),
113- _buildTerminalKey ('F9' , TerminalKey .f9),
114- _buildTerminalKey ('F10' , TerminalKey .f10),
115- _buildVerticalDivider (),
85+ _buildTerminalKey ('HOME' , TerminalKey .home),
86+ _buildTerminalKey ('END' , TerminalKey .end),
87+ _buildTerminalKey ('PGUP' , TerminalKey .pageUp),
88+ _buildTerminalKey ('PGDN' , TerminalKey .pageDown),
89+ _buildTerminalKey ('DEL' , TerminalKey .delete),
90+ _buildVerticalDivider (),
11691
117- ..._snippets.map ((snippet) => _buildSnippetKey (snippet)),
92+ _buildTerminalKey ('F1' , TerminalKey .f1),
93+ _buildTerminalKey ('F2' , TerminalKey .f2),
94+ _buildTerminalKey ('F3' , TerminalKey .f3),
95+ _buildTerminalKey ('F4' , TerminalKey .f4),
96+ _buildTerminalKey ('F5' , TerminalKey .f5),
97+ _buildTerminalKey ('F6' , TerminalKey .f6),
98+ _buildTerminalKey ('F7' , TerminalKey .f7),
99+ _buildTerminalKey ('F8' , TerminalKey .f8),
100+ _buildTerminalKey ('F9' , TerminalKey .f9),
101+ _buildTerminalKey ('F10' , TerminalKey .f10),
102+ _buildVerticalDivider (),
118103
119- Padding (
120- padding : const EdgeInsets . only (left : 4.0 , right : 16.0 ),
121- child : TextButton (
122- style : TextButton . styleFrom (
123- backgroundColor : theme.primaryColor. withOpacity ( 0.15 ),
124- minimumSize : const Size ( 40 , 35 ),
125- shape : RoundedRectangleBorder (borderRadius : BorderRadius . circular ( 8 )),
126- ),
127- onPressed : _showAddSnippetDialog ,
128- child : Icon ( Icons .add, color : theme.primaryColor, size : 18 ),
104+ ..._snippets. map ((snippet) => _buildSnippetKey (snippet)),
105+
106+ Padding (
107+ padding : const EdgeInsets . only (left : 4.0 , right : 16.0 ),
108+ child : TextButton (
109+ focusNode : FocusNode (canRequestFocus : false ),
110+ style : TextButton . styleFrom (
111+ backgroundColor : theme.primaryColor. withOpacity ( 0.15 ),
112+ minimumSize : const Size ( 40 , 35 ) ,
113+ shape : RoundedRectangleBorder (borderRadius : BorderRadius . circular ( 8 ) ),
129114 ),
115+ onPressed: _showAddSnippetDialog,
116+ child: Icon (Icons .add, color: theme.primaryColor, size: 18 ),
130117 ),
131- ],
132- ),
118+ ),
119+ ],
120+ );
121+ }
122+
123+ Widget _buildCtrlActiveRow () {
124+ return ListView (
125+ scrollDirection: Axis .horizontal,
126+ padding: const EdgeInsets .symmetric (horizontal: 4 ),
127+ children: [
128+ _buildToggleKey ('CANCEL' , true , () => setState (() => _isCtrlActive = false ), isCancel: true ),
129+ _buildVerticalDivider (),
130+
131+ _buildActionKey ('C' , 'SIGINT' , () => _sendCtrlByte ('C' )),
132+ _buildActionKey ('D' , 'EOF' , () => _sendCtrlByte ('D' )),
133+ _buildActionKey ('Z' , 'SUSPEND' , () => _sendCtrlByte ('Z' )),
134+ _buildActionKey ('L' , 'CLEAR' , () => _sendCtrlByte ('L' )),
135+ _buildActionKey ('A' , 'HOME' , () => _sendCtrlByte ('A' )),
136+ _buildActionKey ('E' , 'END' , () => _sendCtrlByte ('E' )),
137+ _buildActionKey ('W' , 'DEL WORD' , () => _sendCtrlByte ('W' )),
138+ _buildActionKey ('U' , 'DEL LINE' , () => _sendCtrlByte ('U' )),
139+ ],
133140 );
134141 }
135142
@@ -141,13 +148,16 @@ class _TerminalKeyboardState extends State<TerminalKeyboard> {
141148 );
142149 }
143150
144- Widget _buildToggleKey (String label, bool isActive, VoidCallback onPressed) {
151+ Widget _buildToggleKey (String label, bool isActive, VoidCallback onPressed, { bool isCancel = false } ) {
145152 final theme = Theme .of (context);
153+ final bgColor = isCancel ? Colors .red.withOpacity (0.8 ) : (isActive ? theme.primaryColor : theme.dividerColor.withOpacity (0.5 ));
154+
146155 return Padding (
147156 padding: const EdgeInsets .symmetric (horizontal: 2 , vertical: 6 ),
148157 child: TextButton (
158+ focusNode: FocusNode (canRequestFocus: false ),
149159 style: TextButton .styleFrom (
150- backgroundColor: isActive ? theme.primaryColor : theme.dividerColor. withOpacity ( 0.5 ) ,
160+ backgroundColor: bgColor ,
151161 minimumSize: const Size (45 , 35 ),
152162 padding: const EdgeInsets .symmetric (horizontal: 8 ),
153163 shape: RoundedRectangleBorder (borderRadius: BorderRadius .circular (6 )),
@@ -156,7 +166,7 @@ class _TerminalKeyboardState extends State<TerminalKeyboard> {
156166 child: Text (
157167 label,
158168 style: TextStyle (
159- color: isActive ? theme.colorScheme.surface : theme.textTheme.bodyMedium? .color,
169+ color: isActive || isCancel ? theme.colorScheme.surface : theme.textTheme.bodyMedium? .color,
160170 fontWeight: FontWeight .bold,
161171 fontSize: 12
162172 ),
@@ -169,6 +179,7 @@ class _TerminalKeyboardState extends State<TerminalKeyboard> {
169179 return Padding (
170180 padding: const EdgeInsets .symmetric (horizontal: 2 , vertical: 6 ),
171181 child: TextButton (
182+ focusNode: FocusNode (canRequestFocus: false ),
172183 style: TextButton .styleFrom (
173184 backgroundColor: Colors .transparent,
174185 minimumSize: const Size (45 , 35 ),
@@ -187,32 +198,64 @@ class _TerminalKeyboardState extends State<TerminalKeyboard> {
187198 );
188199 }
189200
190- Widget _buildSnippetKey ( Snippet snippet ) {
201+ Widget _buildActionKey ( String letter, String subtitle, VoidCallback onPressed ) {
191202 final theme = Theme .of (context);
192203 return Padding (
193204 padding: const EdgeInsets .symmetric (horizontal: 3 , vertical: 6 ),
194- child: InkWell (
195- onLongPress: () => _confirmDeleteSnippet (snippet),
196- child: TextButton (
197- style: TextButton .styleFrom (
198- backgroundColor: theme.primaryColor.withOpacity (0.1 ),
199- minimumSize: const Size (60 , 35 ),
200- padding: const EdgeInsets .symmetric (horizontal: 12 ),
201- shape: RoundedRectangleBorder (
202- borderRadius: BorderRadius .circular (6 ),
203- side: BorderSide (color: theme.primaryColor.withOpacity (0.3 )),
204- ),
205+ child: TextButton (
206+ focusNode: FocusNode (canRequestFocus: false ),
207+ style: TextButton .styleFrom (
208+ backgroundColor: theme.primaryColor.withOpacity (0.1 ),
209+ minimumSize: const Size (55 , 35 ),
210+ padding: const EdgeInsets .symmetric (horizontal: 8 ),
211+ shape: RoundedRectangleBorder (
212+ borderRadius: BorderRadius .circular (6 ),
213+ side: BorderSide (color: theme.primaryColor.withOpacity (0.5 )),
205214 ),
206- onPressed: () {
207- String toSend = snippet.command;
208- if (snippet.autoEnter && ! _isCtrlActive) toSend += '\r ' ;
209- _sendText (toSend);
210- },
211- child: Text (
212- snippet.label,
213- style: TextStyle (color: theme.primaryColor, fontWeight: FontWeight .bold, fontSize: 12 ),
215+ ),
216+ onPressed: onPressed,
217+ child: Column (
218+ mainAxisAlignment: MainAxisAlignment .center,
219+ children: [
220+ Text (
221+ letter,
222+ style: TextStyle (color: theme.primaryColor, fontWeight: FontWeight .bold, fontSize: 14 , height: 1.0 ),
223+ ),
224+ Text (
225+ subtitle,
226+ style: const TextStyle (color: Colors .grey, fontSize: 8 , height: 1.0 ),
227+ ),
228+ ],
229+ ),
230+ ),
231+ );
232+ }
233+
234+ Widget _buildSnippetKey (Snippet snippet) {
235+ final theme = Theme .of (context);
236+ return Padding (
237+ padding: const EdgeInsets .symmetric (horizontal: 3 , vertical: 6 ),
238+ child: TextButton (
239+ focusNode: FocusNode (canRequestFocus: false ),
240+ style: TextButton .styleFrom (
241+ backgroundColor: theme.primaryColor.withOpacity (0.1 ),
242+ minimumSize: const Size (60 , 35 ),
243+ padding: const EdgeInsets .symmetric (horizontal: 12 ),
244+ shape: RoundedRectangleBorder (
245+ borderRadius: BorderRadius .circular (6 ),
246+ side: BorderSide (color: theme.primaryColor.withOpacity (0.3 )),
214247 ),
215248 ),
249+ onPressed: () {
250+ String toSend = snippet.command;
251+ if (snippet.autoEnter) toSend += '\r ' ;
252+ _sendText (toSend);
253+ },
254+ onLongPress: () => _confirmDeleteSnippet (snippet),
255+ child: Text (
256+ snippet.label,
257+ style: TextStyle (color: theme.primaryColor, fontWeight: FontWeight .bold, fontSize: 12 ),
258+ ),
216259 ),
217260 );
218261 }
0 commit comments