TESTING - Patches to implement Ctrl-C in VTerm
[tpg/acess2.git] / KernelLand / Kernel / drv / vterm_input.c
1 /*
2  * Acess2 Kernel
3  * - By John Hodge (thePowersGang)
4  *
5  * drv/vterm_input.c
6  * - Virtual Terminal - Input code
7  */
8 #include "vterm.h"
9 #include <api_drv_keyboard.h>
10 #define DEBUG   1
11
12 // === GLOBALS ===
13 // --- Key States --- (Used for VT Switching/Magic Combos)
14  int    gbVT_CtrlDown = 0;
15  int    gbVT_AltDown = 0;
16  int    gbVT_SysrqDown = 0;
17
18 // === CODE ===
19 /**
20  * \fn void VT_InitInput()
21  * \brief Initialises the input
22  */
23 void VT_InitInput()
24 {
25         giVT_InputDevHandle = VFS_Open(gsVT_InputDevice, VFS_OPENFLAG_READ);
26         if(giVT_InputDevHandle == -1) {
27                 Log_Warning("VTerm", "Can't open the input device '%s'", gsVT_InputDevice);
28                 return ;
29         }
30         VFS_IOCtl(giVT_InputDevHandle, KB_IOCTL_SETCALLBACK, VT_KBCallBack);
31         LOG("VTerm input initialised");
32 }
33
34 /**
35  * \fn void VT_KBCallBack(Uint32 Codepoint)
36  * \brief Called on keyboard interrupt
37  * \param Codepoint     Pseudo-UTF32 character
38  * 
39  * Handles a key press and sends the key code to the user's buffer.
40  * If the code creates a kernel-magic sequence, it is not passed to the
41  * user and is handled in-kernel.
42  */
43 void VT_KBCallBack(Uint32 Codepoint)
44 {
45         tVTerm  *term = gpVT_CurTerm;
46
47         // Catch VT binds
48         switch( Codepoint & KEY_ACTION_MASK )
49         {
50         case KEY_ACTION_RAWSYM:
51                 term->RawScancode = Codepoint & KEY_CODEPOINT_MASK;
52                 break;
53         case KEY_ACTION_RELEASE:
54                 switch(term->RawScancode)
55                 {
56                 case KEYSYM_LEFTALT:    gbVT_AltDown &= ~1;     break;
57                 case KEYSYM_RIGHTALT:   gbVT_AltDown &= ~2;     break;
58                 case KEYSYM_LEFTCTRL:   gbVT_CtrlDown &= ~1;    break;
59                 case KEYSYM_RIGHTCTRL:  gbVT_CtrlDown &= ~2;    break;
60                 }
61                 break;
62         
63         case KEY_ACTION_PRESS:
64                 switch(term->RawScancode)
65                 {
66                 case KEYSYM_LEFTALT:    gbVT_AltDown |= 1;      break;
67                 case KEYSYM_RIGHTALT:   gbVT_AltDown |= 2;      break;
68                 case KEYSYM_LEFTCTRL:   gbVT_CtrlDown |= 1;     break;
69                 case KEYSYM_RIGHTCTRL:  gbVT_CtrlDown |= 2;     break;
70                 }
71                 
72                 // Check if the magic keys are held
73                 if(!gbVT_AltDown || !gbVT_CtrlDown)
74                         break;
75                 
76                 switch(term->RawScancode)
77                 {
78                 case KEYSYM_F1 :        VT_SetTerminal(0);      return;
79                 case KEYSYM_F2 :        VT_SetTerminal(1);      return;
80                 case KEYSYM_F3 :        VT_SetTerminal(2);      return;
81                 case KEYSYM_F4 :        VT_SetTerminal(3);      return;
82                 case KEYSYM_F5 :        VT_SetTerminal(4);      return;
83                 case KEYSYM_F6 :        VT_SetTerminal(5);      return;
84                 case KEYSYM_F7 :        VT_SetTerminal(6);      return;
85                 case KEYSYM_F8 :        VT_SetTerminal(7);      return;
86                 case KEYSYM_F9 :        VT_SetTerminal(8);      return;
87                 case KEYSYM_F10:        VT_SetTerminal(9);      return;
88                 case KEYSYM_F11:        VT_SetTerminal(10);     return;
89                 case KEYSYM_F12:        VT_SetTerminal(11);     return;
90                 }
91                 
92                 // Scrolling is only valid in text mode
93                 if(term->Mode != TERM_MODE_TEXT)
94                         break;
95                 
96 //              Log_Debug("VTerm", "Magic Ctrl-Alt-0x%x", term->RawScancode);   
97
98                 switch(term->RawScancode)
99                 {
100                 // Scrolling
101                 case KEYSYM_PGUP:
102                         if( term->Flags & VT_FLAG_ALTBUF )
103                                 return ;
104                         term->ViewPos = MAX( 0, term->ViewPos - term->Width );
105                         VT_int_UpdateScreen(term, 1);
106                         return;
107                 case KEYSYM_PGDN:
108                         if( term->Flags & VT_FLAG_ALTBUF )
109                                 return ;
110                         term->ViewPos = MIN(
111                                 term->ViewPos + term->Width,
112                                 term->Width * term->Height * giVT_Scrollback
113                                 );
114                         VT_int_UpdateScreen(term, 1);
115                         return;
116                 }
117                 break;
118         }
119         
120         // Encode key
121         if(term->Mode == TERM_MODE_TEXT)
122         {
123                 Uint8   buf[6] = {0};
124                  int    len = 0;
125         
126                 // Ignore anything that isn't a press or refire
127                 if( (Codepoint & KEY_ACTION_MASK) != KEY_ACTION_PRESS
128                  && (Codepoint & KEY_ACTION_MASK) != KEY_ACTION_REFIRE
129                     )
130                 {
131                         return ;
132                 }
133         
134                 Codepoint &= KEY_CODEPOINT_MASK;
135
136                 // Ignore Modifer Keys
137                 if(Codepoint > KEY_MODIFIERS)   return;
138                 
139                 // Get UTF-8/ANSI Encoding
140                 if( Codepoint == 0 )
141                 {
142                         // Non-printable keys
143                         switch(term->RawScancode)
144                         {
145                         case KEYSYM_LEFTARROW:
146                         case KEYSYM_KP4:
147                                 buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'D';
148                                 len = 3;
149                                 break;
150                         case KEYSYM_RIGHTARROW:
151                         case KEYSYM_KP6:
152                                 buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'C';
153                                 len = 3;
154                                 break;
155                         case KEYSYM_UPARROW:
156                         case KEYSYM_KP8:
157                                 buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'A';
158                                 len = 3;
159                                 break;
160                         case KEYSYM_DOWNARROW:
161                         case KEYSYM_KP2:
162                                 buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'B';
163                                 len = 3;
164                                 break;
165                         
166                         case KEYSYM_PGUP:
167                         case KEYSYM_KP9:        // If Codepoint=0, It's page up
168                                 buf[0] = '\x1B'; buf[1] = '['; buf[2] = '5'; buf[3] = '~';
169                                 len = 4;
170                                 break;
171                         case KEYSYM_PGDN:
172                         case KEYSYM_KP3:        // If Codepoint=0, It's page down
173                                 buf[0] = '\x1B'; buf[1] = '['; buf[2] = '6'; buf[3] = '~';
174                                 len = 4;
175                                 break;
176                         
177                         case KEYSYM_HOME:
178                         case KEYSYM_KP7:        // Codepoint==0, then it's home (not translated)
179                                 buf[0] = '\x1B'; buf[1] = 'O'; buf[2] = 'H';
180                                 len = 3;
181                                 break;
182                         case KEYSYM_END:
183                         case KEYSYM_KP1:        // You get the drill
184                                 buf[0] = '\x1B'; buf[1] = 'O'; buf[2] = 'F';
185                                 len = 3;
186                                 break;
187                         
188                         case KEYSYM_INSERT:
189                         case KEYSYM_KP0:        // See above
190                                 buf[0] = '\x1B'; buf[1] = '['; buf[2] = '2'; buf[3] = '~';
191                                 len = 4;
192                                 break;
193                         case KEYSYM_DELETE:
194                         case KEYSYM_KPPERIOD:   // Are you that dumb? Look up
195                                 buf[0] = '\x1B'; buf[1] = '['; buf[2] = '3'; buf[3] = '~';
196                                 len = 4;
197                                 break;
198                         }
199                 }
200                 else if( gbVT_CtrlDown )
201                 {
202                         len = 1;
203                         switch( term->RawScancode )
204                         {
205                         case KEYSYM_2:
206                                 buf[0] = '\0';
207                                 break;
208                         case KEYSYM_3 ... KEYSYM_7:
209                                 buf[0] = 0x1b + (term->RawScancode - KEYSYM_3);
210                                 break;
211                         case KEYSYM_8:
212                                 buf[0] = 0x7f;
213                                 break;
214                         // - Ctrl-A = \1, Ctrl-Z = \x1a
215                         case KEYSYM_a ... KEYSYM_z:
216                                 buf[0] = 0x01 + (term->RawScancode - KEYSYM_a);
217                                 break;
218                         default:
219                                 goto utf_encode;
220                         }
221                 }
222                 else
223                 {
224                 utf_encode:
225                         // Attempt to encode in UTF-8
226                         len = WriteUTF8( buf, Codepoint );
227                         if(len == 0) {
228                                 Warning("Codepoint (%x) is unrepresentable in UTF-8", Codepoint);
229                         }
230                 }
231                 
232                 if(len == 0) {
233                         // Unprintable / Don't Pass
234                         return;
235                 }
236
237                 // TODO: Implement Ctrl-C etc
238 #if 0
239                 // Handle meta characters
240                 if( !(term->Flags & VT_FLAG_RAWIN) )
241                 {
242                         // Implementation options for Ctrl-C -> SIGINT
243                         // - Kernel-land: here in the VT
244                         //  > Pros: No userland change needed
245                         //  > Cons: Requires process groups
246                         // - User-land, in the shell
247                         //  > Pros: Less threading changes
248                         //  > Cons: Needs the shell to get all user input before the app, worse latency
249                         //  >       Won't work with bash etc
250                         switch(buf[0])
251                         {
252                         case '\3':      // ^C
253                                 
254                                 break;
255                         }
256                 }
257 #endif
258                 
259                 // Write
260                 if( MAX_INPUT_CHARS8 - term->InputWrite >= len ) {
261                         memcpy( &term->InputBuffer[term->InputWrite], buf, len );
262                 }
263                 else {
264                         memcpy( &term->InputBuffer[term->InputWrite], buf, MAX_INPUT_CHARS8 - term->InputWrite );
265                         memcpy( &term->InputBuffer[0], buf, len - (MAX_INPUT_CHARS8 - term->InputWrite) );
266                 }
267                 // Roll the buffer over
268                 term->InputWrite += len;
269                 term->InputWrite %= MAX_INPUT_CHARS8;
270                 if( (term->InputWrite - term->InputRead + MAX_INPUT_CHARS8)%MAX_INPUT_CHARS8 < len ) {
271                         term->InputRead = term->InputWrite + 1;
272                         term->InputRead %= MAX_INPUT_CHARS8;
273                 }
274         }
275         else
276         {
277                 // Encode the raw key event
278                 Uint32  *raw_in = (void*)term->InputBuffer;
279         
280                 #if 0
281                 // Drop new keys
282                 if( term->InputWrite == term->InputRead )
283                         return ;                
284                 #endif
285
286                 raw_in[ term->InputWrite ] = Codepoint;
287                 term->InputWrite ++;
288                 if(term->InputWrite >= MAX_INPUT_CHARS32)
289                         term->InputWrite -= MAX_INPUT_CHARS32;
290                 
291                 #if 1
292                 // TODO: Should old or new be dropped?
293                 if(term->InputRead == term->InputWrite) {
294                         term->InputRead ++;
295                         if( term->InputRead >= MAX_INPUT_CHARS32 )
296                                 term->InputRead -= MAX_INPUT_CHARS32;
297                 }
298                 #endif
299         }
300         
301         VFS_MarkAvaliable(&term->Node, 1);
302 }
303

UCC git Repository :: git.ucc.asn.au