1 module unde.command_line.events;
2 
3 import unde.global_state;
4 import unde.lib;
5 import unde.tick;
6 import unde.marks;
7 import unde.command_line.run;
8 import unde.command_line.lib;
9 import unde.file_manager.events;
10 import unde.keybar.lib;
11 import unde.translations.lib;
12 
13 import derelict.sdl2.sdl;
14 
15 import std.stdio;
16 import std..string;
17 import std.utf;
18 import std.math;
19 import std.concurrency;
20 import std.functional;
21 
22 enum CommandLineEventHandlerResult
23 {
24     Pass,
25     Block
26 }
27 
28 void
29 turn_on_off_ctrl_mode(GlobalState gs)
30 {
31     gs.command_line.ctrl_mode = !gs.command_line.ctrl_mode;
32 }
33 
34 void
35 turn_off_terminal(GlobalState gs)
36 {
37     gs.command_line.terminal = false;
38     gs.keybar.handlers_double[SDL_SCANCODE_RETURN] = KeyHandler(toDelegate(&turn_on_terminal), _("Open Terminal"), "terminal.png");
39     gs.keybar.handlers.remove(SDL_SCANCODE_ESCAPE);
40 }
41 
42 void
43 turn_on_terminal(GlobalState gs)
44 {
45     gs.command_line.terminal = true;
46     gs.keybar.handlers_double.remove(SDL_SCANCODE_RETURN);
47     gs.keybar.handlers[SDL_SCANCODE_ESCAPE] = KeyHandler(toDelegate(&turn_off_terminal), _("Close terminal"), "terminal.png");
48 }
49 
50 void
51 turn_on_command_line(GlobalState gs)
52 {
53     gs.command_line.just_started_input = true;
54     writefln("Command line open");
55     gs.command_line.enter = true;
56     gs.keybar.input_mode = true;
57     setup_keybar_command_line_default(gs);
58 }
59 
60 void
61 turn_off_command_line(GlobalState gs)
62 {
63     with (gs.command_line)
64     {
65         if (search_mode)
66         {
67             search_mode = false;
68             search = "";
69             pos = command.length;
70         }
71         else
72         {
73             if (!terminal || command_in_focus_id == 0)
74             {
75                 gs.keybar.input_mode = false;
76             }
77             writefln("Command line close");
78             enter = false;
79             setup_keybar_filemanager_default(gs);
80         }
81     }
82 }
83 
84 private void
85 command_line_left(GlobalState gs)
86 {
87     with (gs.command_line)
88     {
89         if (search_mode && hist_pos == 0)
90         {
91             if (pos > 0)
92                 pos -= search.strideBack(pos);
93         }
94         else
95         {
96             if (pos > 0)
97             {
98                 if (pos >= command.length)
99                 {
100                     pos--;
101                 }
102                 else
103                 {
104                     pos -= command.strideBack(pos);
105                 }
106             }
107         }
108     }
109 }
110 
111 private void
112 command_line_right(GlobalState gs)
113 {
114     with (gs.command_line)
115     {
116         if (search_mode && hist_pos == 0)
117         {
118             if (pos < search.length)
119                 pos += search.stride(pos);
120         }
121         else
122         {
123             if (pos < command.length)
124                 pos += command.stride(pos);
125         }
126     }
127 }
128 
129 private void
130 command_line_backspace(GlobalState gs)
131 {
132     with (gs.command_line)
133     {
134         if (search_mode && hist_pos == 0)
135         {
136             if ( search > "" && pos > 0 )
137             {
138                 int sb = search.strideBack(pos);
139                 search = (search[0..pos-sb] ~ search[pos..$]).idup();
140                 pos -= sb;
141             }
142         }
143         else
144         {
145             if ( command > "" && pos > 0 )
146             {
147                 int sb = command.strideBack(pos);
148                 command = (command[0..pos-sb] ~ command[pos..$]).idup();
149                 pos -= sb;
150             }
151         }
152     }
153 }
154 
155 private void
156 command_line_tab(GlobalState gs)
157 {
158     with (gs.command_line)
159     {
160         if (complete.length > 1 && complete[0] == '1')
161         {
162             command = command[0..pos] ~ complete[1..$] ~ command[pos..$];
163             pos += complete[1..$].length;
164         }
165     }
166 }
167 
168 private void
169 command_line_search_mode_on(GlobalState gs)
170 {
171     with (gs.command_line)
172     {
173         search_mode = true;
174         pos = 0;
175         hist_pos = 0;
176     }
177 
178     gs.keybar.handlers[SDL_SCANCODE_ESCAPE] = KeyHandler(toDelegate(&turn_off_command_line), _("Cancel search mode"), "Esc");
179 }
180 
181 private void
182 command_line_search_mode_off(GlobalState gs)
183 {
184     with (gs.command_line)
185     {
186         search_mode = false;
187     }
188     gs.keybar.handlers[SDL_SCANCODE_ESCAPE] = KeyHandler(toDelegate(&turn_off_command_line), _("Close command line"), "command_line.png");
189 }
190 
191 private void
192 command_line_delete(GlobalState gs)
193 {
194     with (gs.command_line)
195     {
196         if ( command > "" && pos > 0 )
197         {
198             /*int sb = command.strideBack(pos);
199               command = (command[0..pos-sb] ~ command[pos..$]).idup();
200               pos -= sb;*/
201         }
202     }
203 }
204 
205 private void
206 command_line_enter(GlobalState gs)
207 {
208     with (gs.command_line)
209     {
210         if (gs.ctrl)
211         {
212             if (search_mode && hist_pos == 0)
213             {
214                 search = (search[0..pos] ~
215                         "\n" ~
216                         search[pos..$]).idup();
217             }
218             else
219             {
220                 command = (command[0..pos] ~
221                         "\n" ~
222                         command[pos..$]).idup();
223             }
224             pos++;
225         }
226         else
227         {
228             search_mode = false;
229             search = "";
230             run_command(gs, command);
231             hist_cmd_id = 0;
232             command = "";
233             pos = 0;
234             gs.keybar.input_mode = false;
235             writefln("Command line close");
236             gs.command_line.enter = false;
237         }
238     }
239 }
240 
241 private auto
242 get_send_input(string input)
243 {
244     return (GlobalState gs)
245     {
246         with (gs.command_line)
247         {
248             send(command_in_focus_tid, input);
249         }
250     };
251 }
252 
253 private void
254 terminal_page_up(GlobalState gs)
255 {
256     with (gs.command_line)
257     {
258         int line_height = cast(int)(round(SQRT2^^9)*1.2);
259         y += gs.screen.h - 2*line_height;
260         neg_y = 0;
261     }
262 }
263 
264 private void
265 terminal_page_down(GlobalState gs)
266 {
267     with (gs.command_line)
268     {
269         int line_height = cast(int)(round(SQRT2^^9)*1.2);
270         y -= gs.screen.h - 2*line_height;
271         neg_y -= gs.screen.h - 2*line_height;
272     }
273 }
274 
275 CommandLineEventHandlerResult
276 process_event(GlobalState gs, ref SDL_Event event)
277 {
278     auto result = CommandLineEventHandlerResult.Pass;
279 
280     if (gs.command_line.terminal)
281     {
282          result = CommandLineEventHandlerResult.Block;
283     }
284 
285     switch( event.type )
286     {
287         case SDL_TEXTINPUT:
288             with (gs.command_line)
289             {
290                 if (enter)
291                 {
292                     char[] input = fromStringz(cast(char*)event.text.text);
293 
294                     if (just_started_input && input == ";")
295                     {
296                         just_started_input = false;
297                         return CommandLineEventHandlerResult.Block;
298                     }
299                     just_started_input = false;
300 
301                     if (search_mode && hist_pos == 0)
302                     {
303                         search = (search[0..pos] ~
304                             input ~
305                             search[pos..$]).idup();
306                         pos += input.length;
307                     }
308                     else
309                     {
310                         if (input[0] == char.init)
311                         {
312                             if (input[1] == '1')
313                             {
314                                 shift_selected(gs);
315                             }
316                             else
317                             {
318                                 change_layout_selected(gs);
319                             }
320                         }
321                         else
322                         {
323                             command = (command[0..pos] ~
324                                 input ~
325                                 command[pos..$]).idup();
326                             pos += input.length;
327                         }
328                     }
329                     last_redraw = 0;
330                 }
331                 else if (command_in_focus_id > 0)
332                 {
333                     char[] input = fromStringz(cast(char*)event.text.text);
334                     send(command_in_focus_tid, input.idup());
335                 }
336             }
337             break;
338 
339         case SDL_MOUSEMOTION:
340             if (gs.mouse_buttons & unDE_MouseButtons.Left)
341             {
342                 with (gs.command_line)
343                 {
344                     if (enter && gs.mouse_screen_x > cmd_rect.x &&
345                             gs.mouse_screen_x < cmd_rect.x + cmd_rect.w &&
346                             gs.mouse_screen_y > cmd_rect.y &&
347                             gs.mouse_screen_y < cmd_rect.y + cmd_rect.h)
348                     {
349                         if (cmd_mouse_pos > cmd_first_click)
350                         {
351                             cmd_start_selection = cmd_first_click;
352                             cmd_end_selection = cmd_mouse_pos;
353                         }
354                         else
355                         {
356                             cmd_start_selection = cmd_mouse_pos;
357                             cmd_end_selection = cmd_first_click;
358                         }
359                     }
360                     else if (ctrl_mode ^ gs.ctrl)
361                     {
362                         if (mouse > first_click)
363                         {
364                             start_selection = first_click;
365                             end_selection = mouse;
366                         }
367                         else
368                         {
369                             start_selection = mouse;
370                             end_selection = first_click;
371                         }
372                     }
373                     else
374                     {
375                         y += event.motion.yrel;
376                         if (event.motion.yrel > 0)
377                             neg_y = 0;
378                         else
379                             neg_y += event.motion.yrel;
380                     }
381                     last_redraw = 0;
382                 }
383             }
384             gs.mouse_screen_x = event.motion.x;
385             gs.mouse_screen_y = event.motion.y;
386             gs.command_line.moved_while_click++;
387             break;
388             
389         case SDL_MOUSEBUTTONDOWN:
390             switch (event.button.button)
391             {
392                 case SDL_BUTTON_LEFT:
393                     gs.mouse_buttons |= unDE_MouseButtons.Left;
394                     gs.command_line.moved_while_click = 0;
395                     with (gs.command_line)
396                     {
397                         if (enter && gs.mouse_screen_x > cmd_rect.x &&
398                                 gs.mouse_screen_x < cmd_rect.x + cmd_rect.w &&
399                                 gs.mouse_screen_y > cmd_rect.y &&
400                                 gs.mouse_screen_y < cmd_rect.y + cmd_rect.h)
401                         {
402                             cmd_first_click = cmd_mouse_pos;
403                         }
404                         else if (ctrl_mode ^ gs.ctrl)
405                         {
406                             first_click = mouse;
407                         }
408                     }
409                     break;
410                 case SDL_BUTTON_MIDDLE:
411                     gs.mouse_buttons |= unDE_MouseButtons.Middle;
412                     break;
413                 case SDL_BUTTON_RIGHT:
414                     gs.mouse_buttons |= unDE_MouseButtons.Right;
415                     break;
416                 default:
417                     break;
418             }
419             break;
420             
421         case SDL_MOUSEBUTTONUP:
422             if (gs.mouse_screen_x < gs.screen.w)
423             {
424                 switch (event.button.button)
425                 {
426                     case SDL_BUTTON_LEFT:
427                         with (gs.command_line)
428                         {
429                             gs.mouse_buttons &= ~unDE_MouseButtons.Left;
430                             if (enter && gs.mouse_screen_x > cmd_rect.x &&
431                                     gs.mouse_screen_x < cmd_rect.x + cmd_rect.w &&
432                                     gs.mouse_screen_y > cmd_rect.y &&
433                                     gs.mouse_screen_y < cmd_rect.y + cmd_rect.h)
434                             {
435                                 if (!moved_while_click || command == "")
436                                 {
437                                     cmd_start_selection = -1;
438                                     cmd_end_selection = -1;
439                                 }
440                                 else
441                                 {
442                                     if (cmd_mouse_pos > cmd_first_click)
443                                     {
444                                         cmd_start_selection = cmd_first_click;
445                                         cmd_end_selection = cmd_mouse_pos;
446                                     }
447                                     else
448                                     {
449                                         cmd_start_selection = cmd_mouse_pos;
450                                         cmd_end_selection = cmd_first_click;
451                                     }
452                                     cmd_selection_to_buffer(gs);
453                                 }
454                             }
455                             else if (terminal)
456                             {
457                                 if (!moved_while_click)
458                                 {
459                                     if (gs.shift)
460                                     {
461                                         if (mouse > first_click)
462                                         {
463                                             end_selection = mouse;
464                                         }
465                                         else
466                                         {
467                                             start_selection = mouse;
468                                         }
469                                         selection_to_buffer(gs);
470                                     }
471                                     else if (on_click !is null)
472                                     {
473                                         on_click();
474                                     }
475                                     else if (ctrl_mode ^ gs.ctrl)
476                                     {
477                                         start_selection = CmdOutPos();
478                                         end_selection = CmdOutPos();
479                                     }
480                                     else if (SDL_GetTicks() - last_left_click < DOUBLE_DELAY)
481                                     {
482                                         command_in_focus_id = 0;
483                                         gs.keybar.input_mode = false;
484                                     }
485                                     else
486                                     {
487                                         //writefln("mouse_cmd_id=%s", mouse_cmd_id);
488                                         auto ptid = mouse.cmd_id in gs.tid_by_command_id;
489                                         if (ptid)
490                                         {
491                                             writefln("Command in Focus");
492                                             command_in_focus_tid = *ptid;
493                                             command_in_focus_id = mouse.cmd_id;
494                                             enter = false;
495                                             gs.keybar.input_mode = true;
496                                         }
497                                         else
498                                         {
499                                             command_in_focus_id = 0;
500                                             if (!enter)
501                                             {
502                                                 gs.keybar.input_mode = false;
503                                             }
504                                         }
505                                     }
506                                     last_left_click = SDL_GetTicks();
507                                 }
508                                 else if (ctrl_mode ^ gs.ctrl)
509                                 {
510                                     if (mouse > first_click)
511                                     {
512                                         start_selection = first_click;
513                                         end_selection = mouse;
514                                     }
515                                     else
516                                     {
517                                         start_selection = mouse;
518                                         end_selection = first_click;
519                                     }
520                                     selection_to_buffer(gs);
521                                 }
522                             }
523                         }
524                         break;
525                     case SDL_BUTTON_MIDDLE:
526                         gs.mouse_buttons &= ~unDE_MouseButtons.Middle;
527                         with (gs.command_line)
528                         {
529                             if (enter && gs.mouse_screen_x < gs.screen.w)
530                             {
531                                char* clipboard = SDL_GetClipboardText();
532                                 if (clipboard)
533                                 {
534                                     string buffer = clipboard.fromStringz().idup();
535 
536                                     command = (command[0..pos] ~
537                                             buffer ~
538                                             command[pos..$]).idup();
539                                     pos += buffer.length;
540                                 }
541                             }
542                             else if (command_in_focus_id > 0)
543                             {
544                                 char* clipboard = SDL_GetClipboardText();
545                                 if (clipboard)
546                                 {
547                                     string buffer = clipboard.fromStringz().idup();
548                                     send(command_in_focus_tid, buffer);
549                                 }
550                             }
551                         }
552                         break;
553                     case SDL_BUTTON_RIGHT:
554                         gs.mouse_buttons &= ~unDE_MouseButtons.Right;
555                         break;
556                     default:
557                         break;
558                 }
559             }
560             break;
561 
562         case SDL_MOUSEWHEEL:
563             with (gs.command_line)
564             {
565                 if (terminal)
566                 {
567                     if (ctrl_mode ^ gs.ctrl)
568                     {
569                         y += event.wheel.y * 40;
570                         if (event.wheel.y > 0)
571                             neg_y = 0;
572                         else
573                             neg_y += event.wheel.y * 40;
574                     }
575                     else
576                     {
577                         fontsize += event.wheel.y;
578 
579                         font_changed = true;
580                         if (fontsize < 4) fontsize = 4;
581                         if (fontsize > 15) fontsize = 15;
582                     }
583                     last_redraw = 0;
584 
585                     update_winsize(gs);
586                 }
587             }
588             break;
589             
590         case SDL_QUIT:
591             /* Do something event.quit */
592             gs.finish=true;
593             break;
594             
595         default:
596             //writeln("Ignored event: "~to!string(event.type));
597             break;
598     }
599 
600     return result;
601 }
602 
603 void
604 setup_keybar_command_line_default(GlobalState gs)
605 {
606     gs.keybar.handlers.clear();
607     gs.keybar.handlers_down.clear();
608     gs.keybar.handlers_double.clear();
609     if (gs.command_line.search_mode)
610     {
611         gs.keybar.handlers[SDL_SCANCODE_ESCAPE] = KeyHandler(toDelegate(&turn_off_command_line), _("Finish search mode"), "Esc");
612     }
613     else
614     {
615         gs.keybar.handlers[SDL_SCANCODE_ESCAPE] = KeyHandler(toDelegate(&turn_off_command_line), _("Close command line"), "command_line.png");
616     }
617     gs.keybar.handlers_down[SDL_SCANCODE_LEFT] = KeyHandler(toDelegate(&command_line_left), _("Left"), "←");
618     gs.keybar.handlers_down[SDL_SCANCODE_RIGHT] = KeyHandler(toDelegate(&command_line_right), _("Right"), "→");
619     gs.keybar.handlers[SDL_SCANCODE_UP] = KeyHandler(toDelegate(&hist_up), _("Search history backward"), "↑");
620     gs.keybar.handlers[SDL_SCANCODE_DOWN] = KeyHandler(toDelegate(&hist_down), _("Search history forward"), "↓");
621     gs.keybar.handlers_down[SDL_SCANCODE_BACKSPACE] = KeyHandler(toDelegate(&command_line_backspace), _("Backspace"), "<--");
622     gs.keybar.handlers[SDL_SCANCODE_TAB] = KeyHandler(toDelegate(&command_line_tab), _("Autocomplete"), "Tab");
623     gs.keybar.handlers_down[SDL_SCANCODE_DELETE] = KeyHandler(toDelegate(&command_line_delete), _("Delete"), "Del");
624     gs.keybar.handlers[SDL_SCANCODE_RETURN] = KeyHandler(toDelegate(&command_line_enter), _("Run Command"), "Run");
625     //gs.keybar.handlers_down[SDL_SCANCODE_LCTRL] = KeyHandler(toDelegate(&command_line_ctrl_down), "Some commands", "Ctrl");
626     //gs.keybar.handlers[SDL_SCANCODE_LCTRL] = KeyHandler(toDelegate(&command_line_ctrl_up), "", "Ctrl");
627 }
628 
629 void
630 setup_keybar_command_line_ctrl(GlobalState gs)
631 {
632     setup_keybar_command_line_default(gs);
633     gs.keybar.handlers_down[SDL_SCANCODE_R] = KeyHandler(toDelegate(&command_line_search_mode_on), _("Search mode"), "Srch");
634     gs.keybar.handlers[SDL_SCANCODE_RETURN] = KeyHandler(toDelegate(&command_line_enter), _("New line"), "\\n");
635     //gs.keybar.handlers_down[SDL_SCANCODE_APOSTROPHE] = KeyHandler(toDelegate(&gomark), "Go To Mark", "gomark.png");
636 }
637 
638 void
639 setup_keybar_terminal(GlobalState gs)
640 {
641     gs.keybar.handlers.clear();
642     gs.keybar.handlers_down.clear();
643     gs.keybar.handlers_double.clear();
644 
645     gs.keybar.handlers[SDL_SCANCODE_Q] = KeyHandler(toDelegate(&quit), _("Quit"), "exit.png");
646     gs.keybar.handlers[SDL_SCANCODE_PRINTSCREEN] = KeyHandler(toDelegate(&make_screenshot), _("Make screenshot"), "Prt Sc");
647     gs.keybar.handlers[SDL_SCANCODE_APOSTROPHE] = KeyHandler(toDelegate(&gomark), _("Go To Mark"), "gomark.png");
648     if (gs.shift)
649     {
650         gs.keybar.handlers[SDL_SCANCODE_PAGEUP] = KeyHandler(toDelegate(&terminal_page_up), _("Page Up"), "PgUp");
651         gs.keybar.handlers[SDL_SCANCODE_PAGEDOWN] = KeyHandler(toDelegate(&terminal_page_down), _("Page Down"), "PgD");
652     }
653     gs.keybar.handlers_double[SDL_SCANCODE_LCTRL] = KeyHandler(toDelegate(&turn_on_off_ctrl_mode), _("Ctrl Mode"), "Ctrl");
654     gs.keybar.handlers_double[SDL_SCANCODE_RCTRL] = KeyHandler(toDelegate(&turn_on_off_ctrl_mode), "", "");
655     gs.keybar.handlers_down[SDL_SCANCODE_LCTRL] = KeyHandler(toDelegate(&setup_keybar_terminal_ctrl), "", "Ctrl");
656     gs.keybar.handlers_down[SDL_SCANCODE_RCTRL] = KeyHandler(toDelegate(&setup_keybar_terminal_ctrl), "", "");
657     gs.keybar.handlers[SDL_SCANCODE_ESCAPE] = KeyHandler(toDelegate(&turn_off_terminal), _("Close terminal"), "Esc");
658 }
659 
660 void
661 setup_keybar_terminal_ctrl(GlobalState gs)
662 {
663     gs.keybar.handlers.clear();
664     gs.keybar.handlers_down.clear();
665     gs.keybar.handlers_double.clear();
666 
667     gs.keybar.handlers[SDL_SCANCODE_Q] = KeyHandler(toDelegate(&restart), _("Restart"), "exit.png");
668     gs.keybar.handlers[SDL_SCANCODE_SEMICOLON] = KeyHandler(toDelegate(&turn_on_command_line), _("Command line"), "command_line.png");
669     gs.keybar.handlers[SDL_SCANCODE_APOSTROPHE] = KeyHandler(toDelegate(&gomark), _("Go To Mark"), "gomark.png");
670     gs.keybar.handlers[SDL_SCANCODE_LCTRL] = KeyHandler(toDelegate(&setup_keybar_terminal), "", "Ctrl");
671     gs.keybar.handlers[SDL_SCANCODE_RCTRL] = KeyHandler(toDelegate(&setup_keybar_terminal), "", "");
672 }
673 
674 void
675 setup_keybar_terminal_command_focus_in(GlobalState gs)
676 {
677     gs.keybar.handlers.clear();
678     gs.keybar.handlers_down.clear();
679     gs.keybar.handlers_double.clear();
680 
681     if (gs.ctrl)
682     {
683         for (SDL_Scancode i = SDL_SCANCODE_A; i <= SDL_SCANCODE_Z; i++)
684         {
685             string letter = fromStringz(SDL_GetScancodeName(i)).idup();
686             char[] scancode_name = fromStringz(SDL_GetScancodeName(i)).dup();
687             scancode_name[0] -= 'A'-1;
688             gs.keybar.handlers_down[i] = KeyHandler(get_send_input(scancode_name.idup()), "Ctrl+"~letter, letter);
689         }
690         foreach(i; [SDL_SCANCODE_LEFTBRACKET, SDL_SCANCODE_RIGHTBRACKET])
691         {
692             string letter = fromStringz(SDL_GetScancodeName(i)).idup();
693             char[] scancode_name = fromStringz(SDL_GetScancodeName(i)).dup();
694             scancode_name[0] -= 'A'-1;
695             gs.keybar.handlers_down[i] = KeyHandler(get_send_input(scancode_name.idup()), "Ctrl+"~letter, letter);
696         }
697         gs.keybar.handlers_down[SDL_SCANCODE_SEMICOLON] = KeyHandler(toDelegate(&turn_on_command_line), _("Command line"), "command_line.png");
698         //gs.keybar.handlers_down[SDL_SCANCODE_APOSTROPHE] = KeyHandler(toDelegate(&gomark), "Go To Mark", "gomark.png");
699     }
700 
701     if (gs.shift)
702     {
703         gs.keybar.handlers[SDL_SCANCODE_PAGEUP] = KeyHandler(toDelegate(&terminal_page_up), _("Page Up"), "PgUp");
704         gs.keybar.handlers[SDL_SCANCODE_PAGEDOWN] = KeyHandler(toDelegate(&terminal_page_down), _("Page Down"), "PgD");
705     }
706 
707     gs.keybar.handlers_down[SDL_SCANCODE_ESCAPE] = KeyHandler(get_send_input("\x1B"), "", "Esc");
708     gs.keybar.handlers_down[SDL_SCANCODE_LEFT] = KeyHandler(get_send_input("\x1B[D"), "", "←");
709     gs.keybar.handlers_down[SDL_SCANCODE_RIGHT] = KeyHandler(get_send_input("\x1B[C"), "", "→");
710     gs.keybar.handlers_down[SDL_SCANCODE_UP] = KeyHandler(get_send_input("\x1B[A"), "", "↑");
711     gs.keybar.handlers_down[SDL_SCANCODE_DOWN] = KeyHandler(get_send_input("\x1B[B"), "", "↓");
712     gs.keybar.handlers_down[SDL_SCANCODE_BACKSPACE] = KeyHandler(get_send_input("\x08"), "", "<--");
713     gs.keybar.handlers_down[SDL_SCANCODE_INSERT] = KeyHandler(get_send_input("\x1B[2~"), "", "Ins");
714     gs.keybar.handlers_down[SDL_SCANCODE_HOME] = KeyHandler(get_send_input("\x1B[7~"), "", "Home");
715     gs.keybar.handlers_down[SDL_SCANCODE_END] = KeyHandler(get_send_input("\x1B[8~"), "", "End");
716     gs.keybar.handlers_down[SDL_SCANCODE_TAB] = KeyHandler(get_send_input("\t"), "", "Tab");
717 
718     gs.keybar.handlers_down[SDL_SCANCODE_F1] = KeyHandler(get_send_input("\x1B[11~"), "", "F1");
719     gs.keybar.handlers_down[SDL_SCANCODE_F2] = KeyHandler(get_send_input("\x1B[12~"), "", "F2");
720     gs.keybar.handlers_down[SDL_SCANCODE_F3] = KeyHandler(get_send_input("\x1B[13~"), "", "F3");
721     gs.keybar.handlers_down[SDL_SCANCODE_F4] = KeyHandler(get_send_input("\x1B[14~"), "", "F4");
722     gs.keybar.handlers_down[SDL_SCANCODE_F5] = KeyHandler(get_send_input("\x1B[15~"), "", "F5");
723 
724     gs.keybar.handlers_down[SDL_SCANCODE_F6] = KeyHandler(get_send_input("\x1B[17~"), "", "F6");
725     gs.keybar.handlers_down[SDL_SCANCODE_F7] = KeyHandler(get_send_input("\x1B[18~"), "", "F7");
726     gs.keybar.handlers_down[SDL_SCANCODE_F8] = KeyHandler(get_send_input("\x1B[19~"), "", "F8");
727     gs.keybar.handlers_down[SDL_SCANCODE_F9] = KeyHandler(get_send_input("\x1B[20~"), "", "F9");
728     gs.keybar.handlers_down[SDL_SCANCODE_F10] = KeyHandler(get_send_input("\x1B[21~"), "", "F10");
729 
730     gs.keybar.handlers_down[SDL_SCANCODE_F11] = KeyHandler(get_send_input("\x1B[23~"), "", "F11");
731     gs.keybar.handlers_down[SDL_SCANCODE_F12] = KeyHandler(get_send_input("\x1B[24~"), "", "F12");
732 
733     gs.keybar.handlers_down[SDL_SCANCODE_PAGEUP] = KeyHandler(get_send_input("\x1B[5~"), "", "PgUp");
734     gs.keybar.handlers_down[SDL_SCANCODE_PAGEDOWN] = KeyHandler(get_send_input("\x1B[6~"), "", "PgD");
735     gs.keybar.handlers_down[SDL_SCANCODE_DELETE] = KeyHandler(get_send_input("\x1B[3~"), "", "Del");
736     gs.keybar.handlers_down[SDL_SCANCODE_RETURN] = KeyHandler(get_send_input("\n"), "", "Enter");
737 }