全选、复制、粘贴

This commit is contained in:
2026-04-15 19:10:00 +08:00
parent ceb04e9289
commit dad78c4f2e
4 changed files with 331 additions and 29 deletions

View File

@@ -1,5 +1,170 @@
#include "shell_internal.h" #include "shell_internal.h"
static char ush_input_clipboard[USH_LINE_MAX];
static u64 ush_input_clipboard_len = 0ULL;
static u64 ush_input_sel_start = 0ULL;
static u64 ush_input_sel_end = 0ULL;
static int ush_input_sel_active = 0;
static void ush_input_selection_clear(void) {
ush_input_sel_active = 0;
ush_input_sel_start = 0ULL;
ush_input_sel_end = 0ULL;
}
static void ush_input_selection_select_all(const ush_state *sh) {
if (sh == (const ush_state *)0 || sh->line_len == 0ULL) {
ush_input_selection_clear();
return;
}
ush_input_sel_active = 1;
ush_input_sel_start = 0ULL;
ush_input_sel_end = sh->line_len;
}
static int ush_input_selection_has_range(const ush_state *sh, u64 *out_start, u64 *out_end) {
u64 start;
u64 end;
if (sh == (const ush_state *)0 || ush_input_sel_active == 0) {
return 0;
}
start = ush_input_sel_start;
end = ush_input_sel_end;
if (start > sh->line_len) {
start = sh->line_len;
}
if (end > sh->line_len) {
end = sh->line_len;
}
if (start > end) {
u64 tmp = start;
start = end;
end = tmp;
}
if (start == end) {
return 0;
}
if (out_start != (u64 *)0) {
*out_start = start;
}
if (out_end != (u64 *)0) {
*out_end = end;
}
return 1;
}
static void ush_input_delete_range(ush_state *sh, u64 start, u64 end) {
u64 delta;
u64 i;
if (sh == (ush_state *)0 || start >= end || start >= sh->line_len) {
ush_input_selection_clear();
return;
}
if (end > sh->line_len) {
end = sh->line_len;
}
delta = end - start;
for (i = start; i + delta <= sh->line_len; i++) {
sh->line[i] = sh->line[i + delta];
}
sh->line_len -= delta;
if (sh->cursor > end) {
sh->cursor -= delta;
} else if (sh->cursor > start) {
sh->cursor = start;
}
if (sh->cursor > sh->line_len) {
sh->cursor = sh->line_len;
}
ush_input_selection_clear();
}
static int ush_input_delete_selection(ush_state *sh) {
u64 start;
u64 end;
if (ush_input_selection_has_range(sh, &start, &end) == 0) {
return 0;
}
ush_input_delete_range(sh, start, end);
return 1;
}
static void ush_input_copy_selection(const ush_state *sh) {
u64 start;
u64 end;
u64 len;
u64 i;
if (ush_input_selection_has_range(sh, &start, &end) == 0) {
return;
}
len = end - start;
if (len > USH_LINE_MAX - 1ULL) {
len = USH_LINE_MAX - 1ULL;
}
for (i = 0ULL; i < len; i++) {
ush_input_clipboard[i] = sh->line[start + i];
}
ush_input_clipboard[len] = '\0';
ush_input_clipboard_len = len;
}
static void ush_input_insert_text(ush_state *sh, const char *text, u64 text_len) {
u64 available;
u64 i;
if (sh == (ush_state *)0 || text == (const char *)0 || text_len == 0ULL) {
return;
}
if (sh->cursor > sh->line_len) {
sh->cursor = sh->line_len;
}
available = (USH_LINE_MAX - 1ULL) - sh->line_len;
if (text_len > available) {
text_len = available;
}
if (text_len == 0ULL) {
return;
}
for (i = sh->line_len + 1ULL; i > sh->cursor; i--) {
sh->line[i + text_len - 1ULL] = sh->line[i - 1ULL];
}
for (i = 0ULL; i < text_len; i++) {
sh->line[sh->cursor + i] = text[i];
}
sh->line_len += text_len;
sh->cursor += text_len;
}
static void ush_history_cancel_nav(ush_state *sh) { static void ush_history_cancel_nav(ush_state *sh) {
if (sh == (ush_state *)0) { if (sh == (ush_state *)0) {
return; return;
@@ -20,6 +185,7 @@ static void ush_reset_line(ush_state *sh) {
sh->cursor = 0ULL; sh->cursor = 0ULL;
sh->rendered_len = 0ULL; sh->rendered_len = 0ULL;
sh->line[0] = '\0'; sh->line[0] = '\0';
ush_input_selection_clear();
} }
static void ush_load_line(ush_state *sh, const char *line) { static void ush_load_line(ush_state *sh, const char *line) {
@@ -35,6 +201,43 @@ static void ush_load_line(ush_state *sh, const char *line) {
ush_copy(sh->line, (u64)sizeof(sh->line), line); ush_copy(sh->line, (u64)sizeof(sh->line), line);
sh->line_len = ush_strlen(sh->line); sh->line_len = ush_strlen(sh->line);
sh->cursor = sh->line_len; sh->cursor = sh->line_len;
ush_input_selection_clear();
}
static void ush_render_line_segment(const ush_state *sh, u64 limit) {
u64 i;
u64 sel_start = 0ULL;
u64 sel_end = 0ULL;
int has_sel;
int inverse_on = 0;
if (sh == (const ush_state *)0) {
return;
}
if (limit > sh->line_len) {
limit = sh->line_len;
}
has_sel = ush_input_selection_has_range(sh, &sel_start, &sel_end);
for (i = 0ULL; i < limit; i++) {
if (has_sel != 0 && inverse_on == 0 && i == sel_start) {
ush_write("\x1B[7m");
inverse_on = 1;
}
if (has_sel != 0 && inverse_on != 0 && i == sel_end) {
ush_write("\x1B[27m");
inverse_on = 0;
}
ush_write_char(sh->line[i]);
}
if (inverse_on != 0) {
ush_write("\x1B[27m");
}
} }
static void ush_render_line(ush_state *sh) { static void ush_render_line(ush_state *sh) {
@@ -46,10 +249,7 @@ static void ush_render_line(ush_state *sh) {
ush_write_char('\r'); ush_write_char('\r');
ush_prompt(sh); ush_prompt(sh);
ush_render_line_segment(sh, sh->line_len);
for (i = 0ULL; i < sh->line_len; i++) {
ush_write_char(sh->line[i]);
}
for (i = sh->line_len; i < sh->rendered_len; i++) { for (i = sh->line_len; i < sh->rendered_len; i++) {
ush_write_char(' '); ush_write_char(' ');
@@ -57,10 +257,7 @@ static void ush_render_line(ush_state *sh) {
ush_write_char('\r'); ush_write_char('\r');
ush_prompt(sh); ush_prompt(sh);
ush_render_line_segment(sh, sh->cursor);
for (i = 0ULL; i < sh->cursor; i++) {
ush_write_char(sh->line[i]);
}
sh->rendered_len = sh->line_len; sh->rendered_len = sh->line_len;
} }
@@ -131,6 +328,7 @@ static void ush_history_apply_current(ush_state *sh) {
if (sh->cursor > sh->line_len) { if (sh->cursor > sh->line_len) {
sh->cursor = sh->line_len; sh->cursor = sh->line_len;
} }
ush_input_selection_clear();
} }
ush_render_line(sh); ush_render_line(sh);
@@ -207,17 +405,42 @@ void ush_read_line(ush_state *sh, char *out_line, u64 out_size) {
return; return;
} }
if (ch == USH_KEY_SELECT_ALL) {
ush_input_selection_select_all(sh);
sh->cursor = sh->line_len;
ush_render_line(sh);
continue;
}
if (ch == USH_KEY_COPY) {
ush_input_copy_selection(sh);
continue;
}
if (ch == USH_KEY_PASTE) {
if (ush_input_clipboard_len > 0ULL) {
ush_history_cancel_nav(sh);
(void)ush_input_delete_selection(sh);
ush_input_insert_text(sh, ush_input_clipboard, ush_input_clipboard_len);
ush_render_line(sh);
}
continue;
}
if (ch == USH_KEY_UP) { if (ch == USH_KEY_UP) {
ush_input_selection_clear();
ush_history_up(sh); ush_history_up(sh);
continue; continue;
} }
if (ch == USH_KEY_DOWN) { if (ch == USH_KEY_DOWN) {
ush_input_selection_clear();
ush_history_down(sh); ush_history_down(sh);
continue; continue;
} }
if (ch == USH_KEY_LEFT) { if (ch == USH_KEY_LEFT) {
ush_input_selection_clear();
if (sh->cursor > 0ULL) { if (sh->cursor > 0ULL) {
sh->cursor--; sh->cursor--;
ush_render_line(sh); ush_render_line(sh);
@@ -226,6 +449,7 @@ void ush_read_line(ush_state *sh, char *out_line, u64 out_size) {
} }
if (ch == USH_KEY_RIGHT) { if (ch == USH_KEY_RIGHT) {
ush_input_selection_clear();
if (sh->cursor < sh->line_len) { if (sh->cursor < sh->line_len) {
sh->cursor++; sh->cursor++;
ush_render_line(sh); ush_render_line(sh);
@@ -234,6 +458,7 @@ void ush_read_line(ush_state *sh, char *out_line, u64 out_size) {
} }
if (ch == USH_KEY_HOME) { if (ch == USH_KEY_HOME) {
ush_input_selection_clear();
if (sh->cursor != 0ULL) { if (sh->cursor != 0ULL) {
sh->cursor = 0ULL; sh->cursor = 0ULL;
ush_render_line(sh); ush_render_line(sh);
@@ -242,6 +467,7 @@ void ush_read_line(ush_state *sh, char *out_line, u64 out_size) {
} }
if (ch == USH_KEY_END) { if (ch == USH_KEY_END) {
ush_input_selection_clear();
if (sh->cursor != sh->line_len) { if (sh->cursor != sh->line_len) {
sh->cursor = sh->line_len; sh->cursor = sh->line_len;
ush_render_line(sh); ush_render_line(sh);
@@ -250,10 +476,17 @@ void ush_read_line(ush_state *sh, char *out_line, u64 out_size) {
} }
if (ch == '\b' || ch == 127) { if (ch == '\b' || ch == 127) {
if (ush_input_delete_selection(sh) != 0) {
ush_history_cancel_nav(sh);
ush_render_line(sh);
continue;
}
if (sh->cursor > 0ULL && sh->line_len > 0ULL) { if (sh->cursor > 0ULL && sh->line_len > 0ULL) {
u64 i; u64 i;
ush_history_cancel_nav(sh); ush_history_cancel_nav(sh);
ush_input_selection_clear();
for (i = sh->cursor - 1ULL; i < sh->line_len; i++) { for (i = sh->cursor - 1ULL; i < sh->line_len; i++) {
sh->line[i] = sh->line[i + 1ULL]; sh->line[i] = sh->line[i + 1ULL];
@@ -267,10 +500,17 @@ void ush_read_line(ush_state *sh, char *out_line, u64 out_size) {
} }
if (ch == USH_KEY_DELETE) { if (ch == USH_KEY_DELETE) {
if (ush_input_delete_selection(sh) != 0) {
ush_history_cancel_nav(sh);
ush_render_line(sh);
continue;
}
if (sh->cursor < sh->line_len) { if (sh->cursor < sh->line_len) {
u64 i; u64 i;
ush_history_cancel_nav(sh); ush_history_cancel_nav(sh);
ush_input_selection_clear();
for (i = sh->cursor; i < sh->line_len; i++) { for (i = sh->cursor; i < sh->line_len; i++) {
sh->line[i] = sh->line[i + 1ULL]; sh->line[i] = sh->line[i + 1ULL];
@@ -290,32 +530,25 @@ void ush_read_line(ush_state *sh, char *out_line, u64 out_size) {
continue; continue;
} }
if (sh->line_len + 1ULL >= USH_LINE_MAX) {
continue;
}
ush_history_cancel_nav(sh); ush_history_cancel_nav(sh);
if (sh->cursor == sh->line_len) {
sh->line[sh->line_len++] = ch;
sh->line[sh->line_len] = '\0';
sh->cursor = sh->line_len;
ush_write_char(ch);
sh->rendered_len = sh->line_len;
continue;
}
{ {
u64 i; int replaced_selection = ush_input_delete_selection(sh);
for (i = sh->line_len; i > sh->cursor; i--) { if (sh->line_len + 1ULL >= USH_LINE_MAX) {
sh->line[i] = sh->line[i - 1ULL]; continue;
} }
sh->line[sh->cursor] = ch; if (replaced_selection == 0 && sh->cursor == sh->line_len) {
sh->line_len++; sh->line[sh->line_len++] = ch;
sh->cursor++; sh->line[sh->line_len] = '\0';
sh->line[sh->line_len] = '\0'; sh->cursor = sh->line_len;
ush_write_char(ch);
sh->rendered_len = sh->line_len;
continue;
}
ush_input_insert_text(sh, &ch, 1ULL);
ush_render_line(sh); ush_render_line(sh);
} }
} }

View File

@@ -21,6 +21,9 @@ typedef long long i64;
#define USH_KEY_HOME ((char)0x05) #define USH_KEY_HOME ((char)0x05)
#define USH_KEY_END ((char)0x06) #define USH_KEY_END ((char)0x06)
#define USH_KEY_DELETE ((char)0x07) #define USH_KEY_DELETE ((char)0x07)
#define USH_KEY_SELECT_ALL ((char)0x10)
#define USH_KEY_COPY ((char)0x11)
#define USH_KEY_PASTE ((char)0x12)
#define USH_CMD_CTX_PATH "/temp/.ush_cmd_ctx.bin" #define USH_CMD_CTX_PATH "/temp/.ush_cmd_ctx.bin"
#define USH_CMD_RET_PATH "/temp/.ush_cmd_ret.bin" #define USH_CMD_RET_PATH "/temp/.ush_cmd_ret.bin"
@@ -100,3 +103,4 @@ int ush_command_program_main(const char *command_name);
int ush_try_exec_external(ush_state *sh, const char *cmd, const char *arg, int *out_success); int ush_try_exec_external(ush_state *sh, const char *cmd, const char *arg, int *out_success);
#endif #endif

View File

@@ -10,6 +10,9 @@
#define CLKS_KEY_HOME ((char)0x05) #define CLKS_KEY_HOME ((char)0x05)
#define CLKS_KEY_END ((char)0x06) #define CLKS_KEY_END ((char)0x06)
#define CLKS_KEY_DELETE ((char)0x07) #define CLKS_KEY_DELETE ((char)0x07)
#define CLKS_KEY_SELECT_ALL ((char)0x10)
#define CLKS_KEY_COPY ((char)0x11)
#define CLKS_KEY_PASTE ((char)0x12)
void clks_keyboard_init(void); void clks_keyboard_init(void);
void clks_keyboard_handle_scancode(u8 scancode); void clks_keyboard_handle_scancode(u8 scancode);
@@ -22,3 +25,4 @@ u64 clks_keyboard_push_count(void);
u64 clks_keyboard_pop_count(void); u64 clks_keyboard_pop_count(void);
#endif #endif

View File

@@ -8,6 +8,7 @@
#define CLKS_SC_ALT 0x38U #define CLKS_SC_ALT 0x38U
#define CLKS_SC_LSHIFT 0x2AU #define CLKS_SC_LSHIFT 0x2AU
#define CLKS_SC_RSHIFT 0x36U #define CLKS_SC_RSHIFT 0x36U
#define CLKS_SC_CTRL 0x1DU
#define CLKS_SC_F1 0x3BU #define CLKS_SC_F1 0x3BU
#define CLKS_SC_F2 0x3CU #define CLKS_SC_F2 0x3CU
#define CLKS_SC_F3 0x3DU #define CLKS_SC_F3 0x3DU
@@ -58,6 +59,8 @@ static u16 clks_kbd_input_count[CLKS_KBD_TTY_MAX];
static clks_bool clks_kbd_alt_down = CLKS_FALSE; static clks_bool clks_kbd_alt_down = CLKS_FALSE;
static clks_bool clks_kbd_lshift_down = CLKS_FALSE; static clks_bool clks_kbd_lshift_down = CLKS_FALSE;
static clks_bool clks_kbd_rshift_down = CLKS_FALSE; static clks_bool clks_kbd_rshift_down = CLKS_FALSE;
static clks_bool clks_kbd_lctrl_down = CLKS_FALSE;
static clks_bool clks_kbd_rctrl_down = CLKS_FALSE;
static clks_bool clks_kbd_e0_prefix = CLKS_FALSE; static clks_bool clks_kbd_e0_prefix = CLKS_FALSE;
static u64 clks_kbd_hotkey_switches = 0ULL; static u64 clks_kbd_hotkey_switches = 0ULL;
@@ -160,6 +163,39 @@ static char clks_keyboard_translate_scancode(u8 code) {
return clks_kbd_map[code]; return clks_kbd_map[code];
} }
static clks_bool clks_keyboard_ctrl_active(void) {
return (clks_kbd_lctrl_down == CLKS_TRUE || clks_kbd_rctrl_down == CLKS_TRUE) ? CLKS_TRUE : CLKS_FALSE;
}
static clks_bool clks_keyboard_try_emit_ctrl_shortcut(u8 code, u32 tty_index) {
char shortcut = '\0';
if (clks_keyboard_ctrl_active() == CLKS_FALSE) {
return CLKS_FALSE;
}
switch (code) {
case 0x1EU:
shortcut = CLKS_KEY_SELECT_ALL;
break;
case 0x2EU:
shortcut = CLKS_KEY_COPY;
break;
case 0x2FU:
shortcut = CLKS_KEY_PASTE;
break;
default:
return CLKS_FALSE;
}
if (clks_keyboard_queue_push_for_tty(tty_index, shortcut) == CLKS_TRUE &&
clks_keyboard_should_pump_shell_now() == CLKS_TRUE) {
clks_shell_pump_input(1U);
}
return CLKS_TRUE;
}
void clks_keyboard_init(void) { void clks_keyboard_init(void) {
u32 tty; u32 tty;
@@ -172,6 +208,8 @@ void clks_keyboard_init(void) {
clks_kbd_alt_down = CLKS_FALSE; clks_kbd_alt_down = CLKS_FALSE;
clks_kbd_lshift_down = CLKS_FALSE; clks_kbd_lshift_down = CLKS_FALSE;
clks_kbd_rshift_down = CLKS_FALSE; clks_kbd_rshift_down = CLKS_FALSE;
clks_kbd_lctrl_down = CLKS_FALSE;
clks_kbd_rctrl_down = CLKS_FALSE;
clks_kbd_e0_prefix = CLKS_FALSE; clks_kbd_e0_prefix = CLKS_FALSE;
clks_kbd_hotkey_switches = 0ULL; clks_kbd_hotkey_switches = 0ULL;
clks_kbd_push_count = 0ULL; clks_kbd_push_count = 0ULL;
@@ -195,8 +233,24 @@ void clks_keyboard_handle_scancode(u8 scancode) {
released = ((scancode & 0x80U) != 0U) ? CLKS_TRUE : CLKS_FALSE; released = ((scancode & 0x80U) != 0U) ? CLKS_TRUE : CLKS_FALSE;
code = (u8)(scancode & 0x7FU); code = (u8)(scancode & 0x7FU);
if (code == CLKS_SC_CTRL) {
if (clks_kbd_e0_prefix == CLKS_TRUE) {
clks_kbd_rctrl_down = (released == CLKS_FALSE) ? CLKS_TRUE : CLKS_FALSE;
clks_kbd_e0_prefix = CLKS_FALSE;
return;
}
clks_kbd_lctrl_down = (released == CLKS_FALSE) ? CLKS_TRUE : CLKS_FALSE;
return;
}
if (code == CLKS_SC_ALT) { if (code == CLKS_SC_ALT) {
clks_kbd_alt_down = (released == CLKS_FALSE) ? CLKS_TRUE : CLKS_FALSE; clks_kbd_alt_down = (released == CLKS_FALSE) ? CLKS_TRUE : CLKS_FALSE;
if (clks_kbd_e0_prefix == CLKS_TRUE) {
clks_kbd_e0_prefix = CLKS_FALSE;
}
return; return;
} }
@@ -264,8 +318,14 @@ void clks_keyboard_handle_scancode(u8 scancode) {
} }
{ {
char translated = clks_keyboard_translate_scancode(code);
u32 active_tty = clks_tty_active(); u32 active_tty = clks_tty_active();
char translated;
if (clks_keyboard_try_emit_ctrl_shortcut(code, active_tty) == CLKS_TRUE) {
return;
}
translated = clks_keyboard_translate_scancode(code);
if (translated != '\0') { if (translated != '\0') {
if (clks_keyboard_queue_push_for_tty(active_tty, translated) == CLKS_TRUE && if (clks_keyboard_queue_push_for_tty(active_tty, translated) == CLKS_TRUE &&
@@ -320,3 +380,4 @@ u64 clks_keyboard_push_count(void) {
u64 clks_keyboard_pop_count(void) { u64 clks_keyboard_pop_count(void) {
return clks_kbd_pop_count; return clks_kbd_pop_count;
} }