2025-05-28 14:41:02 -05:00
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <port_io.h>
|
2025-06-13 19:53:54 -05:00
|
|
|
#include <tty.h>
|
2025-06-17 15:50:07 -05:00
|
|
|
#include <stdlib.h>
|
2025-10-20 21:57:30 -05:00
|
|
|
|
2025-05-28 14:41:02 -05:00
|
|
|
|
|
|
|
|
#include <drivers/ps2_keyboard.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2025-06-13 18:03:39 -05:00
|
|
|
PS/2 Controller IO Ports
|
2025-05-28 14:41:02 -05:00
|
|
|
|
2025-06-13 18:03:39 -05:00
|
|
|
The PS/2 Controller itself uses 2 IO ports (IO ports 0x60 and 0x64). Like many IO ports, reads and writes may access different internal registers.
|
2025-05-28 14:41:02 -05:00
|
|
|
|
2025-06-13 18:03:39 -05:00
|
|
|
Historical note: The PC-XT PPI had used port 0x61 to reset the keyboard interrupt request signal (among other unrelated functions). Port 0x61 has no keyboard related functions on AT and PS/2 compatibles.
|
|
|
|
|
IO Port Access Type Purpose
|
|
|
|
|
0x60 Read/Write Data Port
|
|
|
|
|
0x64 Read Status Register
|
|
|
|
|
0x64 Write Command Register
|
2025-05-28 14:41:02 -05:00
|
|
|
*/
|
|
|
|
|
|
2025-06-13 19:53:54 -05:00
|
|
|
/*
|
|
|
|
|
Note:
|
|
|
|
|
The interrupt number for keyboard input in 1.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#define PS2_DATA_PORT 0x60
|
|
|
|
|
#define PS2_STATUS_PORT 0x64
|
|
|
|
|
|
|
|
|
|
#define KEYBOARD_IRQ 1
|
|
|
|
|
|
2025-10-20 21:57:30 -05:00
|
|
|
#define RETURN_STI() do { _sti_asm(); return; } while (0)
|
|
|
|
|
|
2025-06-17 15:50:07 -05:00
|
|
|
bool ps2keyboard_initialized = false;
|
2025-06-13 19:53:54 -05:00
|
|
|
|
|
|
|
|
/* State for shift key */
|
|
|
|
|
static bool shift_pressed = false;
|
|
|
|
|
|
2025-06-17 15:50:07 -05:00
|
|
|
/* State for caps-lock key */
|
|
|
|
|
static bool capslock_pressed = false;
|
|
|
|
|
|
2025-07-03 20:30:21 -05:00
|
|
|
/* Used for arrow keys among others */
|
|
|
|
|
static bool extended = false;
|
|
|
|
|
|
|
|
|
|
static bool is_new_char = false;
|
2025-10-20 21:57:30 -05:00
|
|
|
static bool is_new_key = false;
|
|
|
|
|
|
|
|
|
|
static bool gets_called = false;
|
|
|
|
|
static volatile bool gets_finished = false;
|
2025-07-03 20:30:21 -05:00
|
|
|
|
|
|
|
|
volatile unsigned char current_char;
|
2025-10-20 21:57:30 -05:00
|
|
|
volatile char* current_string = NULL;
|
|
|
|
|
volatile char* gets_string = NULL;
|
2025-06-17 15:50:07 -05:00
|
|
|
volatile int32_t current_length = 0;
|
2025-10-20 21:57:30 -05:00
|
|
|
volatile int32_t gets_length = 0;
|
|
|
|
|
volatile int32_t capacity = 0;
|
|
|
|
|
volatile int32_t gets_capacity = 0;
|
2025-07-03 20:30:21 -05:00
|
|
|
volatile uint16_t current_key;
|
2025-06-17 15:50:07 -05:00
|
|
|
|
2025-10-20 21:57:30 -05:00
|
|
|
volatile ps2_hook_t* hooks = NULL;
|
|
|
|
|
volatile int hook_count = 0;
|
|
|
|
|
|
|
|
|
|
extern void _cli_asm(void);
|
|
|
|
|
extern void _sti_asm(void);
|
2025-06-17 15:50:07 -05:00
|
|
|
|
2025-06-13 19:53:54 -05:00
|
|
|
static const char scancode_map[128] = {
|
|
|
|
|
0, 27, '1','2','3','4','5','6','7','8','9','0','-','=','\b', /* Backspace */
|
2025-07-03 20:30:21 -05:00
|
|
|
'\t', /* Tab */
|
2025-06-13 19:53:54 -05:00
|
|
|
'q','w','e','r','t','y','u','i','o','p','[',']','\n', /* Enter */
|
|
|
|
|
0, /* Control */
|
|
|
|
|
'a','s','d','f','g','h','j','k','l',';','\'','`',
|
|
|
|
|
0, /* Left shift */
|
|
|
|
|
'\\','z','x','c','v','b','n','m',',','.','/',
|
|
|
|
|
0, /* Right shift */
|
|
|
|
|
'*',
|
|
|
|
|
0, /* Alt */
|
|
|
|
|
' ', /* Spacebar */
|
|
|
|
|
0, /* Caps lock */
|
|
|
|
|
/* The rest are function and control keys */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2025-05-28 14:41:02 -05:00
|
|
|
void keyboard_init(void)
|
|
|
|
|
{
|
2025-10-20 21:57:30 -05:00
|
|
|
#ifdef _DEBUG
|
|
|
|
|
printf("[ PS/2 KBD ] Initializing the PS/2 keyboard...\n");
|
|
|
|
|
#endif
|
|
|
|
|
|
2025-06-13 19:53:54 -05:00
|
|
|
outb(0x64, 0xAE); /* Enable keyboard interface (often optional, but here for safety) */
|
2025-10-20 21:57:30 -05:00
|
|
|
|
|
|
|
|
hooks = (ps2_hook_t*) malloc(sizeof(ps2_hook_t) * hook_count);
|
|
|
|
|
|
2025-06-17 15:50:07 -05:00
|
|
|
ps2keyboard_initialized = true;
|
2025-10-20 21:57:30 -05:00
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
|
printf("[ PS/2 KBD ] PS/2 Keyboard initialized\n");
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool setup_hook(ps2_hook_t func)
|
|
|
|
|
{
|
|
|
|
|
_cli_asm();
|
|
|
|
|
|
|
|
|
|
ps2_hook_t* copy = malloc(sizeof(ps2_hook_t) * hook_count);
|
|
|
|
|
|
|
|
|
|
if (hook_count > 0 && copy == NULL)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (hook_count > 0)
|
|
|
|
|
{
|
|
|
|
|
memcpy(copy, hooks, sizeof(ps2_hook_t) * hook_count);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free((void*) hooks);
|
|
|
|
|
|
|
|
|
|
hooks = malloc(sizeof(ps2_hook_t) * (hook_count + 1));
|
|
|
|
|
|
|
|
|
|
if (hooks == NULL)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (hook_count > 0)
|
|
|
|
|
{
|
|
|
|
|
memcpy((void*) hooks, copy, sizeof(ps2_hook_t) * hook_count);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free(copy);
|
|
|
|
|
|
|
|
|
|
hooks[hook_count] = func;
|
|
|
|
|
hook_count++;
|
|
|
|
|
|
|
|
|
|
_sti_asm();
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool remove_hook(ps2_hook_t func)
|
|
|
|
|
{
|
|
|
|
|
_cli_asm();
|
|
|
|
|
|
|
|
|
|
int index = -1;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < hook_count; i++)
|
|
|
|
|
{
|
|
|
|
|
if (hooks[i] == func)
|
|
|
|
|
{
|
|
|
|
|
index = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (index == -1)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = index; i < hook_count - 1; i++)
|
|
|
|
|
{
|
|
|
|
|
hooks[i] = hooks[i + 1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hook_count--;
|
|
|
|
|
|
|
|
|
|
if (hook_count == 0)
|
|
|
|
|
{
|
|
|
|
|
free((void*) hooks);
|
|
|
|
|
hooks = NULL;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ps2_hook_t* smaller = malloc(sizeof(ps2_hook_t) * hook_count);
|
|
|
|
|
|
|
|
|
|
if (smaller == NULL)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memcpy(smaller, (void*) hooks, sizeof(ps2_hook_t) * hook_count);
|
|
|
|
|
free((void*) hooks);
|
|
|
|
|
hooks = smaller;
|
|
|
|
|
|
|
|
|
|
_sti_asm();
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void call_hooks(char c)
|
|
|
|
|
{
|
|
|
|
|
_cli_asm();
|
|
|
|
|
|
|
|
|
|
if (hook_count == 0)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < hook_count; i++)
|
|
|
|
|
{
|
|
|
|
|
hooks[i](c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_sti_asm();
|
2025-06-17 15:50:07 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char get_char(void)
|
|
|
|
|
{
|
2025-07-03 20:30:21 -05:00
|
|
|
/*
|
|
|
|
|
ASCII code 5 (Enquiry) is/was used in legacy systems meant for requesting a response from a remote terminal or device.
|
2025-10-20 21:57:30 -05:00
|
|
|
For example, one system might send ENQ (ASCII 5), and the receiver could reply with ACK (ASCII 6) to indicate it's ready or still online.
|
2025-07-03 20:30:21 -05:00
|
|
|
|
|
|
|
|
In modern computing, ENQ is largely obsolete:
|
|
|
|
|
|
|
|
|
|
- Terminal emulators, shells, operating systems, and network protocols generally do not use ENQ.
|
|
|
|
|
|
|
|
|
|
- It's not used in text files, programming, or standard communications.
|
|
|
|
|
|
|
|
|
|
- It may still appear in legacy systems, embedded devices, or proprietary serial protocols, but that's niche.
|
|
|
|
|
*/
|
2025-10-20 21:57:30 -05:00
|
|
|
if (!is_new_char)
|
2025-07-03 20:30:21 -05:00
|
|
|
{
|
2025-10-20 21:57:30 -05:00
|
|
|
return 5;
|
2025-07-03 20:30:21 -05:00
|
|
|
}
|
2025-10-20 21:57:30 -05:00
|
|
|
|
2025-07-03 20:30:21 -05:00
|
|
|
is_new_char = false;
|
2025-10-20 21:57:30 -05:00
|
|
|
return current_char;
|
2025-07-03 20:30:21 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint16_t get_key(void)
|
|
|
|
|
{
|
|
|
|
|
uint16_t temp = 0xFFFA;
|
|
|
|
|
|
|
|
|
|
if (is_new_key)
|
|
|
|
|
{
|
|
|
|
|
temp = current_key;
|
|
|
|
|
is_new_key = false;
|
|
|
|
|
}
|
|
|
|
|
else if (is_new_char)
|
|
|
|
|
{
|
|
|
|
|
temp = (uint16_t)current_char;
|
|
|
|
|
is_new_char = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return temp;
|
2025-06-17 15:50:07 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char* get_string(void)
|
|
|
|
|
{
|
|
|
|
|
return current_string;
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-20 21:57:30 -05:00
|
|
|
char* kbd_gets(void)
|
|
|
|
|
{
|
|
|
|
|
gets_called = true;
|
|
|
|
|
gets_finished = false;
|
|
|
|
|
|
|
|
|
|
while (gets_finished != true)
|
|
|
|
|
{
|
|
|
|
|
sleep(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char* result = strdup(gets_string); /* Could be NULL, that is checked below */
|
|
|
|
|
|
|
|
|
|
free(gets_string);
|
|
|
|
|
|
|
|
|
|
gets_string = NULL;
|
|
|
|
|
gets_capacity = 0;
|
|
|
|
|
gets_length = 0;
|
|
|
|
|
gets_called = false;
|
|
|
|
|
|
|
|
|
|
return result == NULL ? "" : result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void gets_append_char(unsigned char c)
|
|
|
|
|
{
|
|
|
|
|
_cli_asm();
|
|
|
|
|
|
|
|
|
|
if (!gets_string && gets_capacity > 0)
|
|
|
|
|
{
|
|
|
|
|
printf("[keyboard] ERROR: gets_string is NULL but capacity > 0!\n");
|
|
|
|
|
RETURN_STI();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (c == KEY_ARROW_UP || c == KEY_ARROW_DOWN || c == KEY_ARROW_RIGHT || c == KEY_ARROW_LEFT)
|
|
|
|
|
{
|
|
|
|
|
gets_string[1] = '\0';
|
|
|
|
|
|
|
|
|
|
char tc = '\0';
|
|
|
|
|
|
|
|
|
|
switch (c)
|
|
|
|
|
{
|
|
|
|
|
case KEY_ARROW_UP:
|
|
|
|
|
tc = KEY_UP;
|
|
|
|
|
break;
|
|
|
|
|
case KEY_ARROW_DOWN:
|
|
|
|
|
tc = KEY_DOWN;
|
|
|
|
|
break;
|
|
|
|
|
case KEY_ARROW_RIGHT:
|
|
|
|
|
tc = KEY_RIGHT;
|
|
|
|
|
break;
|
|
|
|
|
case KEY_ARROW_LEFT:
|
|
|
|
|
tc = KEY_LEFT;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
tc = '\0';
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gets_string[0] = tc;
|
|
|
|
|
|
|
|
|
|
gets_finished = true;
|
|
|
|
|
|
|
|
|
|
RETURN_STI();
|
|
|
|
|
}
|
|
|
|
|
else if (c == '\n')
|
|
|
|
|
{
|
|
|
|
|
/* The returned string must/will not have newlines in it, so we return here after setting gets_finished to 'true'. */
|
|
|
|
|
|
|
|
|
|
gets_finished = true;
|
|
|
|
|
|
|
|
|
|
printf("\n");
|
|
|
|
|
|
|
|
|
|
RETURN_STI();
|
|
|
|
|
}
|
|
|
|
|
else if (c == 27) /* ASCII escape, here it's used to cancel input. */
|
|
|
|
|
{
|
|
|
|
|
gets_finished = true;
|
|
|
|
|
gets_string[0] = '\0';
|
|
|
|
|
|
|
|
|
|
RETURN_STI();
|
|
|
|
|
}
|
|
|
|
|
else if (c == '\b')
|
|
|
|
|
{
|
|
|
|
|
if (gets_length < 1)
|
|
|
|
|
{
|
|
|
|
|
RETURN_STI();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gets_length--;
|
|
|
|
|
gets_string[gets_length] = '\0';
|
|
|
|
|
|
|
|
|
|
printf("\b \b");
|
|
|
|
|
|
|
|
|
|
RETURN_STI();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((gets_length) >= gets_capacity)
|
|
|
|
|
{
|
|
|
|
|
int new_capacity = (gets_capacity == 0) ? 64 : gets_capacity * 2;
|
|
|
|
|
|
|
|
|
|
char* new_str = (char*) malloc(new_capacity);
|
|
|
|
|
|
|
|
|
|
if (!new_str)
|
|
|
|
|
{
|
|
|
|
|
RETURN_STI();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (gets_string)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < gets_length; i++)
|
|
|
|
|
{
|
|
|
|
|
new_str[i] = gets_string[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
new_str[gets_length] = '\0';
|
|
|
|
|
|
|
|
|
|
free(gets_string);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gets_string = new_str;
|
|
|
|
|
gets_capacity = new_capacity;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!gets_string)
|
|
|
|
|
{
|
|
|
|
|
RETURN_STI();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gets_string[gets_length] = (char) c;
|
|
|
|
|
gets_length++;
|
|
|
|
|
gets_string[gets_length] = '\0';
|
|
|
|
|
|
|
|
|
|
printf("%c", c);
|
|
|
|
|
|
|
|
|
|
RETURN_STI();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void append_char(char c)
|
2025-06-17 15:50:07 -05:00
|
|
|
{
|
2025-10-20 21:57:30 -05:00
|
|
|
_cli_asm();
|
|
|
|
|
|
2025-06-17 15:50:07 -05:00
|
|
|
if (current_length + 1 >= capacity)
|
|
|
|
|
{
|
|
|
|
|
int new_capacity = (capacity == 0) ? 16 : capacity * 2;
|
|
|
|
|
|
2025-10-20 21:57:30 -05:00
|
|
|
char* new_str = (char*) malloc(new_capacity);
|
|
|
|
|
|
|
|
|
|
if (!new_str)
|
|
|
|
|
{
|
|
|
|
|
printf("[keyboard] ERROR: malloc failed for new input buffer\n");
|
2025-06-17 15:50:07 -05:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-20 21:57:30 -05:00
|
|
|
|
2025-06-17 15:50:07 -05:00
|
|
|
if (current_string)
|
|
|
|
|
{
|
|
|
|
|
memcpy(new_str, current_string, current_length);
|
|
|
|
|
free(current_string);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
current_string = new_str;
|
|
|
|
|
capacity = new_capacity;
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-20 21:57:30 -05:00
|
|
|
if (!current_string)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-17 15:50:07 -05:00
|
|
|
current_string[current_length] = c;
|
|
|
|
|
current_length++;
|
2025-10-20 21:57:30 -05:00
|
|
|
current_string[current_length] = '\0';
|
|
|
|
|
|
|
|
|
|
_sti_asm();
|
2025-06-17 15:50:07 -05:00
|
|
|
}
|
|
|
|
|
|
2025-10-20 21:57:30 -05:00
|
|
|
|
|
|
|
|
void free_current_string(void)
|
2025-06-17 15:50:07 -05:00
|
|
|
{
|
|
|
|
|
if (current_string)
|
|
|
|
|
{
|
|
|
|
|
free(current_string);
|
|
|
|
|
current_string = NULL;
|
|
|
|
|
current_length = 0;
|
|
|
|
|
capacity = 0;
|
|
|
|
|
}
|
2025-06-13 19:53:54 -05:00
|
|
|
}
|
|
|
|
|
|
2025-07-03 20:30:21 -05:00
|
|
|
void keyboard_handler(void)
|
|
|
|
|
{
|
2025-06-13 19:53:54 -05:00
|
|
|
uint8_t scancode = inb(PS2_DATA_PORT);
|
|
|
|
|
|
|
|
|
|
/* Handle shift press/release */
|
|
|
|
|
if (scancode == 0x2A || scancode == 0x36)
|
|
|
|
|
{
|
|
|
|
|
shift_pressed = true;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else if (scancode == 0xAA || scancode == 0xB6)
|
|
|
|
|
{
|
|
|
|
|
shift_pressed = false;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-06-17 15:50:07 -05:00
|
|
|
else if (scancode == 0x3A)
|
|
|
|
|
{
|
|
|
|
|
capslock_pressed = !capslock_pressed;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-07-03 20:30:21 -05:00
|
|
|
else if (scancode == 0xE0)
|
|
|
|
|
{
|
|
|
|
|
extended = true;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-06-17 15:50:07 -05:00
|
|
|
|
2025-06-13 19:53:54 -05:00
|
|
|
|
|
|
|
|
if (scancode & 0x80)
|
|
|
|
|
{
|
2025-07-03 20:30:21 -05:00
|
|
|
extended = false;
|
|
|
|
|
}
|
|
|
|
|
else
|
2025-06-13 19:53:54 -05:00
|
|
|
{
|
2025-10-20 21:57:30 -05:00
|
|
|
uint16_t c = (uint16_t) scancode_map[scancode];
|
|
|
|
|
if ((shift_pressed ^ capslock_pressed) && ((char) c >= 'a') && ((char) c <= 'z'))
|
2025-07-03 20:30:21 -05:00
|
|
|
{
|
2025-06-13 19:53:54 -05:00
|
|
|
c -= 32; /* Convert to uppercase */
|
|
|
|
|
}
|
|
|
|
|
else if (shift_pressed)
|
|
|
|
|
{
|
2025-07-03 20:30:21 -05:00
|
|
|
c = (uint16_t) terminal_get_shifted((unsigned char) c);
|
2025-06-13 19:53:54 -05:00
|
|
|
}
|
2025-06-27 14:48:06 -05:00
|
|
|
|
2025-10-20 21:57:30 -05:00
|
|
|
if (hook_count > 0)
|
|
|
|
|
{
|
|
|
|
|
call_hooks(c);
|
|
|
|
|
}
|
2025-06-13 19:53:54 -05:00
|
|
|
|
2025-07-03 20:30:21 -05:00
|
|
|
if (extended)
|
|
|
|
|
{
|
|
|
|
|
switch (scancode)
|
|
|
|
|
{
|
|
|
|
|
case 0x48:
|
|
|
|
|
c = KEY_ARROW_UP;
|
|
|
|
|
break;
|
|
|
|
|
case 0x50:
|
|
|
|
|
c = KEY_ARROW_DOWN;
|
|
|
|
|
break;
|
|
|
|
|
case 0x4B:
|
|
|
|
|
c = KEY_ARROW_LEFT;
|
|
|
|
|
break;
|
|
|
|
|
case 0x4D:
|
|
|
|
|
c = KEY_ARROW_RIGHT;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
c = KEY_NONE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-20 21:57:30 -05:00
|
|
|
if (gets_called)
|
|
|
|
|
{
|
|
|
|
|
gets_append_char(c);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-03 20:30:21 -05:00
|
|
|
current_key = c;
|
|
|
|
|
|
|
|
|
|
is_new_key = true;
|
|
|
|
|
extended = false;
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-10-20 21:57:30 -05:00
|
|
|
|
|
|
|
|
if (gets_called)
|
|
|
|
|
{
|
|
|
|
|
gets_append_char(c);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-07-03 20:30:21 -05:00
|
|
|
|
2025-06-13 19:53:54 -05:00
|
|
|
if (c)
|
|
|
|
|
{
|
2025-10-20 21:57:30 -05:00
|
|
|
if (c != '\n')
|
|
|
|
|
{
|
|
|
|
|
append_char(c);
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-17 15:50:07 -05:00
|
|
|
current_char = c;
|
2025-07-03 20:30:21 -05:00
|
|
|
is_new_char = true;
|
2025-10-20 21:57:30 -05:00
|
|
|
|
2025-06-17 15:50:07 -05:00
|
|
|
if (c == '\n')
|
|
|
|
|
{
|
2025-10-20 21:57:30 -05:00
|
|
|
/*append_char(c);
|
|
|
|
|
current_char = c;
|
|
|
|
|
is_new_char = true;*/
|
|
|
|
|
|
2025-06-17 15:50:07 -05:00
|
|
|
free_current_string();
|
|
|
|
|
}
|
2025-06-13 19:53:54 -05:00
|
|
|
}
|
2025-10-20 21:57:30 -05:00
|
|
|
|
2025-06-13 19:53:54 -05:00
|
|
|
}
|
2025-05-28 14:41:02 -05:00
|
|
|
}
|
2025-06-27 14:48:06 -05:00
|
|
|
|
2025-10-20 21:57:30 -05:00
|
|
|
|