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

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