|
@@ -176,20 +176,90 @@ static void bios_putchar ( int character ) {
|
176
|
176
|
: "ebp" );
|
177
|
177
|
}
|
178
|
178
|
|
|
179
|
+/**
|
|
180
|
+ * Pointer to current ANSI output sequence
|
|
181
|
+ *
|
|
182
|
+ * While we are in the middle of returning an ANSI sequence for a
|
|
183
|
+ * special key, this will point to the next character to return. When
|
|
184
|
+ * not in the middle of such a sequence, this will point to a NUL
|
|
185
|
+ * (note: not "will be NULL").
|
|
186
|
+ */
|
|
187
|
+static const char *ansi_input = "";
|
|
188
|
+
|
|
189
|
+/**
|
|
190
|
+ * Lowest BIOS scancode of interest
|
|
191
|
+ *
|
|
192
|
+ * Most of the BIOS key scancodes that we are interested in are in a
|
|
193
|
+ * dense range, so subtracting a constant and treating them as offsets
|
|
194
|
+ * into an array works efficiently.
|
|
195
|
+ */
|
|
196
|
+#define BIOS_KEY_MIN 0x47
|
|
197
|
+
|
|
198
|
+/** Offset into list of interesting BIOS scancodes */
|
|
199
|
+#define BIOS_KEY(scancode) ( (scancode) - BIOS_KEY_MIN )
|
|
200
|
+
|
|
201
|
+/** Mapping from BIOS scan codes to ANSI escape sequences */
|
|
202
|
+static const char *ansi_sequences[] = {
|
|
203
|
+ [ BIOS_KEY ( 0x47 ) ] = "[H", /* Home */
|
|
204
|
+ [ BIOS_KEY ( 0x48 ) ] = "[A", /* Up arrow */
|
|
205
|
+ [ BIOS_KEY ( 0x4b ) ] = "[D", /* Left arrow */
|
|
206
|
+ [ BIOS_KEY ( 0x4d ) ] = "[C", /* Right arrow */
|
|
207
|
+ [ BIOS_KEY ( 0x4f ) ] = "[F", /* End */
|
|
208
|
+ [ BIOS_KEY ( 0x50 ) ] = "[B", /* Down arrow */
|
|
209
|
+ [ BIOS_KEY ( 0x53 ) ] = "[3~", /* Delete */
|
|
210
|
+};
|
|
211
|
+
|
|
212
|
+/**
|
|
213
|
+ * Get ANSI escape sequence corresponding to BIOS scancode
|
|
214
|
+ *
|
|
215
|
+ * @v scancode BIOS scancode
|
|
216
|
+ * @ret ansi_seq ANSI escape sequence, if any, otherwise NULL
|
|
217
|
+ */
|
|
218
|
+static const char * scancode_to_ansi_seq ( unsigned int scancode ) {
|
|
219
|
+ unsigned int bios_key = BIOS_KEY ( scancode );
|
|
220
|
+
|
|
221
|
+ if ( bios_key < ( sizeof ( ansi_sequences ) /
|
|
222
|
+ sizeof ( ansi_sequences[0] ) ) ) {
|
|
223
|
+ return ansi_sequences[bios_key];
|
|
224
|
+ }
|
|
225
|
+ return NULL;
|
|
226
|
+}
|
|
227
|
+
|
179
|
228
|
/**
|
180
|
229
|
* Get character from BIOS console
|
181
|
230
|
*
|
182
|
231
|
* @ret character Character read from console
|
183
|
232
|
*/
|
184
|
233
|
static int bios_getchar ( void ) {
|
185
|
|
- uint8_t character;
|
186
|
|
-
|
|
234
|
+ uint16_t keypress;
|
|
235
|
+ unsigned int character;
|
|
236
|
+ char *ansi_seq;
|
|
237
|
+
|
|
238
|
+ /* If we are mid-sequence, pass out the next byte */
|
|
239
|
+ if ( ( character = *ansi_input ) ) {
|
|
240
|
+ ansi_input++;
|
|
241
|
+ return character;
|
|
242
|
+ }
|
|
243
|
+
|
|
244
|
+ /* Read character from real BIOS console */
|
187
|
245
|
__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
|
188
|
246
|
"int $0x16\n\t"
|
189
|
247
|
"cli\n\t" )
|
190
|
|
- : "=a" ( character ) : "a" ( 0x0000 ) );
|
|
248
|
+ : "=a" ( keypress ) : "a" ( 0x1000 ) );
|
|
249
|
+ character = ( keypress & 0xff );
|
191
|
250
|
|
192
|
|
- return character;
|
|
251
|
+ /* If it's a normal character, just return it */
|
|
252
|
+ if ( character )
|
|
253
|
+ return character;
|
|
254
|
+
|
|
255
|
+ /* Otherwise, check for a special key that we know about */
|
|
256
|
+ if ( ( ansi_seq = scancode_to_ansi_seq ( keypress >> 8 ) ) ) {
|
|
257
|
+ /* Start of escape sequence: return ESC (0x1b) */
|
|
258
|
+ ansi_input = ansi_seq;
|
|
259
|
+ return 0x1b;
|
|
260
|
+ }
|
|
261
|
+
|
|
262
|
+ return 0;
|
193
|
263
|
}
|
194
|
264
|
|
195
|
265
|
/**
|
|
@@ -201,7 +271,12 @@ static int bios_getchar ( void ) {
|
201
|
271
|
static int bios_iskey ( void ) {
|
202
|
272
|
unsigned int discard_a;
|
203
|
273
|
unsigned int flags;
|
204
|
|
-
|
|
274
|
+
|
|
275
|
+ /* If we are mid-sequence, we are always ready */
|
|
276
|
+ if ( *ansi_input )
|
|
277
|
+ return 1;
|
|
278
|
+
|
|
279
|
+ /* Otherwise check the real BIOS console */
|
205
|
280
|
__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
|
206
|
281
|
"int $0x16\n\t"
|
207
|
282
|
"pushfw\n\t"
|
|
@@ -209,7 +284,6 @@ static int bios_iskey ( void ) {
|
209
|
284
|
"cli\n\t" )
|
210
|
285
|
: "=r" ( flags ), "=a" ( discard_a )
|
211
|
286
|
: "a" ( 0x0100 ) );
|
212
|
|
-
|
213
|
287
|
return ( ! ( flags & ZF ) );
|
214
|
288
|
}
|
215
|
289
|
|