3 * - By John Hodge (thePowersGang)
6 * - Virtual Terminal - Input code
9 #include <api_drv_keyboard.h>
13 // --- Key States --- (Used for VT Switching/Magic Combos)
14 int gbVT_CtrlDown = 0;
16 int gbVT_SysrqDown = 0;
20 * \fn void VT_InitInput()
21 * \brief Initialises the input
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);
30 VFS_IOCtl(giVT_InputDevHandle, KB_IOCTL_SETCALLBACK, VT_KBCallBack);
31 LOG("VTerm input initialised");
35 * \fn void VT_KBCallBack(Uint32 Codepoint)
36 * \brief Called on keyboard interrupt
37 * \param Codepoint Pseudo-UTF32 character
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.
43 void VT_KBCallBack(Uint32 Codepoint)
45 tVTerm *term = gpVT_CurTerm;
48 switch( Codepoint & KEY_ACTION_MASK )
50 case KEY_ACTION_RAWSYM:
51 term->RawScancode = Codepoint & KEY_CODEPOINT_MASK;
53 case KEY_ACTION_RELEASE:
54 switch(term->RawScancode)
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;
63 case KEY_ACTION_PRESS:
64 switch(term->RawScancode)
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;
72 // Check if the magic keys are held
73 if(!gbVT_AltDown || !gbVT_CtrlDown)
76 switch(term->RawScancode)
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;
92 // Scrolling is only valid in text mode
93 if(term->Mode != TERM_MODE_TEXT)
96 // Log_Debug("VTerm", "Magic Ctrl-Alt-0x%x", term->RawScancode);
98 switch(term->RawScancode)
102 if( term->Flags & VT_FLAG_ALTBUF )
104 term->ViewPos = MAX( 0, term->ViewPos - term->Width );
105 VT_int_UpdateScreen(term, 1);
108 if( term->Flags & VT_FLAG_ALTBUF )
111 term->ViewPos + term->Width,
112 term->Width * term->Height * giVT_Scrollback
114 VT_int_UpdateScreen(term, 1);
121 if(term->Mode == TERM_MODE_TEXT)
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
134 Codepoint &= KEY_CODEPOINT_MASK;
136 // Ignore Modifer Keys
137 if(Codepoint > KEY_MODIFIERS) return;
139 // Get UTF-8/ANSI Encoding
142 // Non-printable keys
143 switch(term->RawScancode)
145 case KEYSYM_LEFTARROW:
147 buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'D';
150 case KEYSYM_RIGHTARROW:
152 buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'C';
157 buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'A';
160 case KEYSYM_DOWNARROW:
162 buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'B';
167 case KEYSYM_KP9: // If Codepoint=0, It's page up
168 buf[0] = '\x1B'; buf[1] = '['; buf[2] = '5'; buf[3] = '~';
172 case KEYSYM_KP3: // If Codepoint=0, It's page down
173 buf[0] = '\x1B'; buf[1] = '['; buf[2] = '6'; buf[3] = '~';
178 case KEYSYM_KP7: // Codepoint==0, then it's home (not translated)
179 buf[0] = '\x1B'; buf[1] = 'O'; buf[2] = 'H';
183 case KEYSYM_KP1: // You get the drill
184 buf[0] = '\x1B'; buf[1] = 'O'; buf[2] = 'F';
189 case KEYSYM_KP0: // See above
190 buf[0] = '\x1B'; buf[1] = '['; buf[2] = '2'; buf[3] = '~';
194 case KEYSYM_KPPERIOD: // Are you that dumb? Look up
195 buf[0] = '\x1B'; buf[1] = '['; buf[2] = '3'; buf[3] = '~';
200 else if( gbVT_CtrlDown )
203 switch( term->RawScancode )
208 case KEYSYM_3 ... KEYSYM_7:
209 buf[0] = 0x1b + (term->RawScancode - KEYSYM_3);
214 // - Ctrl-A = \1, Ctrl-Z = \x1a
215 case KEYSYM_a ... KEYSYM_z:
216 buf[0] = 0x01 + (term->RawScancode - KEYSYM_a);
225 // Attempt to encode in UTF-8
226 len = WriteUTF8( buf, Codepoint );
228 Warning("Codepoint (%x) is unrepresentable in UTF-8", Codepoint);
233 // Unprintable / Don't Pass
237 // TODO: Implement Ctrl-C etc
239 // Handle meta characters
240 if( !(term->Flags & VT_FLAG_RAWIN) )
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
260 if( MAX_INPUT_CHARS8 - term->InputWrite >= len ) {
261 memcpy( &term->InputBuffer[term->InputWrite], buf, len );
264 memcpy( &term->InputBuffer[term->InputWrite], buf, MAX_INPUT_CHARS8 - term->InputWrite );
265 memcpy( &term->InputBuffer[0], buf, len - (MAX_INPUT_CHARS8 - term->InputWrite) );
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;
277 // Encode the raw key event
278 Uint32 *raw_in = (void*)term->InputBuffer;
282 if( term->InputWrite == term->InputRead )
286 raw_in[ term->InputWrite ] = Codepoint;
288 if(term->InputWrite >= MAX_INPUT_CHARS32)
289 term->InputWrite -= MAX_INPUT_CHARS32;
292 // TODO: Should old or new be dropped?
293 if(term->InputRead == term->InputWrite) {
295 if( term->InputRead >= MAX_INPUT_CHARS32 )
296 term->InputRead -= MAX_INPUT_CHARS32;
301 VFS_MarkAvaliable(&term->Node, 1);