1 /* Copyright (C) 2021-2023 Harry Godden (hgn) - All Rights Reserved */
11 #include "vg/vg_log.h"
13 #define VG_VAR_F32( NAME, ... ) \
14 { u32 flags=0x00; __VA_ARGS__ ;\
15 vg_console_reg_var( #NAME, &NAME, k_var_dtype_f32, flags ); }
17 #define VG_VAR_I32( NAME, ... ) \
18 { u32 flags=0x00; __VA_ARGS__ ;\
19 vg_console_reg_var( #NAME, &NAME, k_var_dtype_i32, flags ); }
21 #define VG_VAR_PERSISTENT 0x1
22 #define VG_VAR_CHEAT 0x2
24 typedef struct vg_var vg_var
;
25 typedef struct vg_cmd vg_cmd
;
44 int (*function
)( int argc
, char const *argv
[] );
45 void (*poll_suggest
)( int argc
, char const *argv
[] );
58 int suggestion_select
,
62 u32 var_count
, function_count
;
66 int cursor_user
, cursor_pos
, string_length
;
69 int history_last
, history_pos
, history_count
;
76 VG_STATIC
void _vg_console_draw( void );
77 void _vg_console_println( const char *str
);
78 VG_STATIC
int _vg_console_list( int argc
, char const *argv
[] );
79 VG_STATIC
void _vg_console_init(void);
80 VG_STATIC
void _vg_console_write_persistent(void);
81 VG_STATIC
void _vg_console_free(void);
82 VG_STATIC
void vg_execute_console_input( const char *cmd
);
87 VG_STATIC
void console_make_selection( int* start
, int* end
);
88 VG_STATIC
void console_move_cursor( int* cursor0
, int* cursor1
,
89 int dir
, int snap_together
);
90 VG_STATIC
int console_makeroom( int datastart
, int length
);
91 VG_STATIC
int console_delete_char( int direction
);
92 VG_STATIC
void console_to_clipboard(void);
93 VG_STATIC
void console_clipboard_paste(void);
94 VG_STATIC
void console_put_char( char c
);
95 VG_STATIC
void console_history_get( char* buf
, int entry_num
);
96 VG_STATIC
int _vg_console_enabled(void);
97 VG_STATIC
void console_proc_key( SDL_Keysym ev
);
102 VG_STATIC
int _vg_console_enabled(void)
104 return vg_console
.enabled
;
108 void vg_console_reg_var( const char *alias
, void *ptr
, enum vg_var_dtype type
,
111 if( vg_console
.var_count
> vg_list_size(vg_console
.vars
) )
112 vg_fatal_error( "Too many vars registered" );
114 vg_var
*var
= &vg_console
.vars
[ vg_console
.var_count
++ ];
117 var
->data_type
= type
;
120 vg_info( "Console variable '%s' registered\n", alias
);
124 void vg_console_reg_cmd( const char *alias
,
125 int (*function
)(int argc
, const char *argv
[]),
126 void (*poll_suggest
)(int argc
, const char *argv
[]) )
128 if( vg_console
.function_count
> vg_list_size(vg_console
.functions
) )
129 vg_fatal_error( "Too many functions registered" );
131 vg_cmd
*cmd
= &vg_console
.functions
[ vg_console
.function_count
++ ];
133 cmd
->function
= function
;
134 cmd
->poll_suggest
= poll_suggest
;
137 vg_info( "Console function '%s' registered\n", alias
);
140 VG_STATIC
void _vg_console_draw(void)
142 if( !vg_console
.enabled
)
145 SDL_AtomicLock( &log_print_sl
);
147 int ptr
= vg_log
.buffer_line_current
;
150 int console_lines
= VG_MIN( log_lines
, vg_log
.buffer_line_count
);
152 vg_uictx
.cursor
[0] = 0;
153 vg_uictx
.cursor
[1] = 0;
154 vg_uictx
.cursor
[3] = log_lines
*fh
;
162 ui_fill_rect( vg_uictx
.cursor
, 0x77181818 );
164 vg_uictx
.cursor
[3] = fh
;
167 for( int i
=0; i
<console_lines
; i
++ ){
171 ptr
= vg_list_size( vg_log
.buffer
)-1;
173 ui_text( vg_uictx
.cursor
, vg_log
.buffer
[ptr
], 1, 0 );
174 vg_uictx
.cursor
[1] -= fh
;
182 vg_uictx
.cursor
[1] += 2;
183 vg_uictx
.cursor
[3] = fh
;
187 ui_fill_rect( vg_uictx
.cursor
, 0x77111111 );
188 ui_text( vg_uictx
.cursor
, vg_console
.input
, 1, 0 );
190 int start
= VG_MIN( vg_console
.cursor_pos
, vg_console
.cursor_user
),
191 end
= VG_MAX( vg_console
.cursor_pos
, vg_console
.cursor_user
);
193 vg_uictx
.cursor
[0] = start
* UI_GLYPH_SPACING_X
;
194 vg_uictx
.cursor
[2] = (start
== end
? 0.5f
: (float)(end
-start
))
195 * (float)UI_GLYPH_SPACING_X
;
197 ui_fill_rect( vg_uictx
.cursor
, 0x66ffffff );
203 if( vg_console
.suggestion_count
){
204 vg_uictx
.cursor
[0] += UI_GLYPH_SPACING_X
* vg_console
.suggestion_pastepos
;
205 vg_uictx
.cursor
[1] += 2;
206 vg_uictx
.cursor
[3] = vg_console
.suggestion_count
* fh
;
207 vg_uictx
.cursor
[2] = UI_GLYPH_SPACING_X
* vg_console
.suggestion_maxlen
;
211 ui_fill_rect( vg_uictx
.cursor
, 0x77040404 );
213 vg_uictx
.cursor
[3] = fh
;
214 for( int i
=0; i
<vg_console
.suggestion_count
; i
++ ){
215 if( i
== vg_console
.suggestion_select
)
216 ui_fill_rect( vg_uictx
.cursor
, 0x66a0e508 );
218 ui_text( vg_uictx
.cursor
, vg_console
.suggestions
[i
].str
, 1, 0 );
219 vg_uictx
.cursor
[1] += fh
;
225 SDL_AtomicUnlock( &log_print_sl
);
228 VG_STATIC
int _vg_console_list( int argc
, char const *argv
[] )
230 for( int i
=0; i
<vg_console
.function_count
; i
++ ){
231 struct vg_cmd
*cmd
= &vg_console
.functions
[ i
];
232 vg_info( "* %s\n", cmd
->name
);
235 for( int i
=0; i
<vg_console
.var_count
; i
++ ){
236 struct vg_var
*cv
= &vg_console
.vars
[ i
];
237 vg_info( "%s\n", cv
->name
);
243 int _test_break( int argc
, const char *argv
[] )
245 vg_fatal_error( "Test crash from main, after loading (console)" );
249 int _vg_console_exec( int argc
, const char *argv
[] )
251 if( argc
< 1 ) return 0;
254 strcpy( path
, "cfg/" );
255 strncat( path
, argv
[0], 250 );
257 FILE *fp
= fopen( path
, "r" );
261 while( fgets( line
, sizeof( line
), fp
) ){
262 line
[ strcspn( line
, "\r\n#" ) ] = 0x00;
264 if( line
[0] != 0x00 ){
265 vg_execute_console_input( line
);
272 vg_error( "Could not open '%s'\n", path
);
278 VG_STATIC
void _vg_console_init(void)
280 vg_console_reg_cmd( "list", _vg_console_list
, NULL
);
281 vg_console_reg_cmd( "crash", _test_break
, NULL
);
282 vg_console_reg_cmd( "exec", _vg_console_exec
, NULL
);
285 VG_STATIC
void vg_console_load_autos(void)
287 _vg_console_exec( 1, (const char *[]){ "auto.conf" } );
290 VG_STATIC
void _vg_console_write_persistent(void)
292 FILE *fp
= fopen( "cfg/auto.conf", "w" );
294 for( int i
=0; i
<vg_console
.var_count
; i
++ ){
295 struct vg_var
*cv
= &vg_console
.vars
[i
];
297 if( cv
->flags
& VG_VAR_PERSISTENT
){
298 switch( cv
->data_type
){
299 case k_var_dtype_i32
:
300 fprintf( fp
, "%s %d\n", cv
->name
, *(i32
*)(cv
->data
) );
302 case k_var_dtype_u32
:
303 fprintf( fp
, "%s %u\n", cv
->name
, *(u32
*)(cv
->data
) );
305 case k_var_dtype_f32
:
306 fprintf( fp
, "%s %.5f\n", cv
->name
, *(float *)(cv
->data
) );
315 VG_STATIC
void _vg_console_free(void)
317 _vg_console_write_persistent();
321 * splits src into tokens and fills out args as pointers to those tokens
322 * returns number of tokens
323 * dst must be as long as src
325 VG_STATIC
int vg_console_tokenize( const char *src
, char *dst
,
326 const char *args
[8] )
331 for( int i
=0;; i
++ ){
333 if( src
[i
] == ' ' || src
[i
] == '\t' ){
346 args
[ arg_count
++ ] = &dst
[i
];
360 VG_STATIC vg_var
*vg_console_match_var( const char *kw
)
362 for( int i
=0; i
<vg_console
.var_count
; i
++ ){
363 struct vg_var
*cv
= &vg_console
.vars
[ i
];
364 if( !strcmp( cv
->name
, kw
) ){
372 VG_STATIC vg_cmd
*vg_console_match_cmd( const char *kw
)
374 for( int i
=0; i
<vg_console
.function_count
; i
++ ){
375 struct vg_cmd
*cmd
= &vg_console
.functions
[ i
];
376 if( !strcmp( cmd
->name
, kw
) ){
384 VG_STATIC
void vg_execute_console_input( const char *cmd
)
388 int arg_count
= vg_console_tokenize( cmd
, temp
, args
);
393 vg_var
*cv
= vg_console_match_var( args
[0] );
394 vg_cmd
*fn
= vg_console_match_cmd( args
[0] );
396 assert( !(cv
&& fn
) );
399 /* Cvar Matched, try get value */
400 if( arg_count
>= 2 ){
401 if( (cv
->data_type
== k_var_dtype_u32
) ||
402 (cv
->data_type
== k_var_dtype_i32
) )
405 *ptr
= atoi( args
[1] );
407 else if( cv
->data_type
== k_var_dtype_f32
){
408 float *ptr
= cv
->data
;
409 *ptr
= atof( args
[1] );
413 if( cv
->data_type
== k_var_dtype_i32
)
414 vg_info( "= %d\n", *((int *)cv
->data
) );
415 else if( cv
->data_type
== k_var_dtype_u32
)
416 vg_info( "= %u\n", *((u32
*)cv
->data
) );
417 else if( cv
->data_type
== k_var_dtype_f32
)
418 vg_info( "= %.4f\n", *((float *)cv
->data
) );
424 fn
->function( arg_count
-1, args
+1 );
428 vg_error( "No command/var named '%s'. Use 'list' to view all\n", args
[0] );
431 u32
str_lev_distance( const char *s1
, const char *s2
)
433 u32 m
= strlen( s1
),
439 assert( n
+1 <= 256 );
443 for( u32 k
=0; k
<=n
; k
++ )
447 for( u32 i
=0; i
<m
; i
++ ){
452 for( u32 j
=0; j
<n
; j
++ ){
453 u32 upper
= costs
[j
+1];
456 costs
[ j
+1 ] = corner
;
458 u32 t
= (upper
< corner
)? upper
: corner
;
459 costs
[j
+1] = ((costs
[j
] < t
)? costs
[j
]: t
) + 1;
469 u32
str_lcs( const char *s1
, const char *s2
)
471 u32 m
= VG_MIN( 31, strlen( s1
) ),
472 n
= VG_MIN( 31, strlen( s2
) );
477 for( int i
=0; i
<=m
; i
++ ){
478 for( int j
=0; j
<=n
; j
++ ){
479 if( i
== 0 || j
== 0 )
481 else if( s1
[i
-1] == s2
[j
-1] ){
482 suff
[i
][j
] = suff
[i
-1][j
-1] + 1;
483 result
= VG_MAX( result
, suff
[i
][j
] );
493 /* str must not fuckoff ever! */
494 VG_STATIC
void console_suggest_score_text( const char *str
, const char *input
,
497 /* filter duplicates */
498 for( int i
=0; i
<vg_console
.suggestion_count
; i
++ )
499 if( !strcmp( vg_console
.suggestions
[i
].str
, str
) )
503 u32 score
= str_lcs( str
, input
);
505 if( score
< minscore
)
508 int best_pos
= vg_console
.suggestion_count
;
509 for( int j
=best_pos
-1; j
>=0; j
-- )
510 if( score
> vg_console
.suggestions
[j
].lev_score
)
513 /* insert if good score */
514 if( best_pos
< vg_list_size( vg_console
.suggestions
) ){
515 int start
= VG_MIN( vg_console
.suggestion_count
,
516 vg_list_size( vg_console
.suggestions
)-1 );
517 for( int j
=start
; j
>best_pos
; j
-- )
518 vg_console
.suggestions
[j
] = vg_console
.suggestions
[j
-1];
520 vg_console
.suggestions
[ best_pos
].str
= str
;
521 vg_console
.suggestions
[ best_pos
].len
= strlen( str
);
522 vg_console
.suggestions
[ best_pos
].lev_score
= score
;
524 if( vg_console
.suggestion_count
<
525 vg_list_size( vg_console
.suggestions
) )
526 vg_console
.suggestion_count
++;
530 VG_STATIC
void console_update_suggestions(void)
532 vg_console
.suggestion_count
= 0;
533 vg_console
.suggestion_select
= -1;
534 vg_console
.suggestion_maxlen
= 0;
537 * - must be typing something
538 * - must be at the end
539 * - prev char must not be a whitespace
540 * - cursors should match
543 if( vg_console
.cursor_pos
== 0 )
546 if( vg_console
.cursor_pos
!= vg_console
.cursor_user
)
549 if( vg_console
.input
[ vg_console
.cursor_pos
] != '\0' )
552 if( (vg_console
.input
[ vg_console
.cursor_pos
-1 ] == ' ') ||
553 (vg_console
.input
[ vg_console
.cursor_pos
-1 ] == '\t') )
559 int token_count
= vg_console_tokenize( vg_console
.input
, temp
, args
);
561 vg_console
.suggestion_pastepos
= args
[token_count
-1]-temp
;
563 /* Score all our commands and cvars */
564 if( token_count
== 1 ){
565 for( int i
=0; i
<vg_console
.var_count
; i
++ ){
566 vg_var
*cvar
= &vg_console
.vars
[i
];
567 console_suggest_score_text( cvar
->name
, args
[0], 1 );
570 for( int i
=0; i
<vg_console
.function_count
; i
++ ){
571 vg_cmd
*cmd
= &vg_console
.functions
[i
];
572 console_suggest_score_text( cmd
->name
, args
[0], 1 );
576 vg_cmd
*cmd
= vg_console_match_cmd( args
[0] );
577 vg_var
*var
= vg_console_match_var( args
[0] );
579 assert( !( cmd
&& var
) );
582 if( cmd
->poll_suggest
)
583 cmd
->poll_suggest( token_count
-1, &args
[1] );
586 /* some post processing */
587 for( int i
=0; i
<vg_console
.suggestion_count
; i
++ ){
588 vg_console
.suggestion_maxlen
= VG_MAX( vg_console
.suggestion_maxlen
,
589 vg_console
.suggestions
[i
].len
);
591 if( vg_console
.suggestions
[i
].lev_score
<
592 vg_console
.suggestions
[0].lev_score
/2 )
594 vg_console
.suggestion_count
= i
;
603 VG_STATIC
void console_make_selection( int* start
, int* end
)
605 *start
= VG_MIN( vg_console
.cursor_pos
, vg_console
.cursor_user
);
606 *end
= VG_MAX( vg_console
.cursor_pos
, vg_console
.cursor_user
);
609 VG_STATIC
void console_move_cursor( int* cursor0
, int* cursor1
,
610 int dir
, int snap_together
)
612 *cursor0
= VG_MAX( 0, vg_console
.cursor_user
+ dir
);
615 VG_MIN( vg_list_size(vg_console
.input
)-1, strlen( vg_console
.input
)),
622 VG_STATIC
int console_makeroom( int datastart
, int length
)
624 int move_to
= VG_MIN( datastart
+length
, vg_list_size( vg_console
.input
)-1 );
625 int move_amount
= strlen( vg_console
.input
)-datastart
;
627 VG_MIN( move_to
+move_amount
, vg_list_size( vg_console
.input
)-1 );
628 move_amount
= move_end
-move_to
;
631 memmove( &vg_console
.input
[ move_to
],
632 &vg_console
.input
[ datastart
],
635 vg_console
.input
[ move_end
] = '\0';
637 return VG_MIN( length
, vg_list_size( vg_console
.input
)-datastart
-1 );
640 VG_STATIC
int console_delete_char( int direction
)
643 console_make_selection( &start
, &end
);
645 /* There is no selection */
647 if( direction
== 1 ) end
= VG_MIN( end
+1, strlen( vg_console
.input
) );
648 else if( direction
== -1 ) start
= VG_MAX( start
-1, 0 );
651 /* Still no selction, no need to do anything */
655 /* Copy the end->terminator to start */
656 int remaining_length
= strlen( vg_console
.input
)+1-end
;
657 memmove( &vg_console
.input
[ start
],
658 &vg_console
.input
[ end
],
663 VG_STATIC
void console_to_clipboard(void)
666 console_make_selection( &start
, &end
);
670 memcpy( buffer
, &vg_console
.input
[ start
], end
-start
);
671 buffer
[ end
-start
] = 0x00;
672 SDL_SetClipboardText( buffer
);
676 VG_STATIC
void console_clipboard_paste(void)
678 if( !SDL_HasClipboardText() )
681 char *text
= SDL_GetClipboardText();
686 int datastart
= console_delete_char( 0 );
687 int length
= strlen( text
);
688 int cpylength
= console_makeroom( datastart
, length
);
690 memcpy( vg_console
.input
+ datastart
, text
, cpylength
);
691 console_move_cursor( &vg_console
.cursor_user
,
692 &vg_console
.cursor_pos
, cpylength
, 1 );
695 console_update_suggestions();
698 VG_STATIC
void console_put_char( char c
)
700 if( !vg_console
.enabled
)
703 vg_console
.cursor_user
= console_delete_char(0);
705 if( console_makeroom( vg_console
.cursor_user
, 1 ) )
706 vg_console
.input
[ vg_console
.cursor_user
] = c
;
708 console_move_cursor( &vg_console
.cursor_user
, &vg_console
.cursor_pos
, 1, 1 );
711 VG_STATIC
void console_history_get( char* buf
, int entry_num
)
713 if( !vg_console
.history_count
)
716 int offset
= VG_MIN( entry_num
, vg_console
.history_count
-1 ),
717 pick
= (vg_console
.history_last
- offset
) %
718 vg_list_size( vg_console
.history
);
719 strcpy( buf
, vg_console
.history
[ pick
] );
722 /* Receed secondary cursor */
723 VG_STATIC
void _console_left_select(void)
725 console_move_cursor( &vg_console
.cursor_user
, NULL
, -1, 0 );
728 /* Match and receed both cursors */
729 VG_STATIC
void _console_left(void)
731 int cursor_diff
= vg_console
.cursor_pos
- vg_console
.cursor_user
? 0: 1;
733 console_move_cursor( &vg_console
.cursor_user
,
734 &vg_console
.cursor_pos
, -cursor_diff
, 1 );
737 VG_STATIC
void _console_right_select(void)
739 console_move_cursor( &vg_console
.cursor_user
, NULL
, 1, 0 );
742 VG_STATIC
void _console_right(void)
744 int cursor_diff
= vg_console
.cursor_pos
- vg_console
.cursor_user
? 0: 1;
746 console_move_cursor( &vg_console
.cursor_user
,
747 &vg_console
.cursor_pos
, +cursor_diff
, 1 );
750 VG_STATIC
void _console_down(void)
752 vg_console
.history_pos
= VG_MAX( 0, vg_console
.history_pos
-1 );
753 console_history_get( vg_console
.input
, vg_console
.history_pos
);
755 console_move_cursor( &vg_console
.cursor_user
,
756 &vg_console
.cursor_pos
,
757 vg_list_size(vg_console
.input
)-1, 1 );
760 VG_STATIC
void _console_up(void)
762 vg_console
.history_pos
= VG_MAX
767 vg_console
.history_pos
+1,
770 vg_list_size( vg_console
.history
),
771 vg_console
.history_count
- 1
776 console_history_get( vg_console
.input
, vg_console
.history_pos
);
777 console_move_cursor( &vg_console
.cursor_user
,
778 &vg_console
.cursor_pos
,
779 vg_list_size(vg_console
.input
)-1, 1);
782 VG_STATIC
void _console_backspace(void)
784 vg_console
.cursor_user
= console_delete_char( -1 );
785 vg_console
.cursor_pos
= vg_console
.cursor_user
;
787 console_update_suggestions();
790 VG_STATIC
void _console_delete(void)
792 vg_console
.cursor_user
= console_delete_char( 1 );
793 vg_console
.cursor_pos
= vg_console
.cursor_user
;
795 console_update_suggestions();
798 VG_STATIC
void _console_home_select(void)
800 console_move_cursor( &vg_console
.cursor_user
, NULL
, -10000, 0 );
803 VG_STATIC
void _console_home(void)
805 console_move_cursor( &vg_console
.cursor_user
,
806 &vg_console
.cursor_pos
, -10000, 1 );
809 VG_STATIC
void _console_end_select(void)
811 console_move_cursor( &vg_console
.cursor_user
, NULL
, 10000, 0 );
814 VG_STATIC
void _console_end(void)
816 console_move_cursor( &vg_console
.cursor_user
,
817 &vg_console
.cursor_pos
,
818 vg_list_size(vg_console
.input
)-1, 1 );
821 VG_STATIC
void _console_select_all(void)
823 console_move_cursor( &vg_console
.cursor_user
, NULL
, 10000, 0);
824 console_move_cursor( &vg_console
.cursor_pos
, NULL
, -10000, 0);
827 VG_STATIC
void _console_cut(void)
829 console_to_clipboard();
830 vg_console
.cursor_user
= console_delete_char(0);
831 vg_console
.cursor_pos
= vg_console
.cursor_user
;
834 VG_STATIC
void _console_enter(void)
836 if( !strlen( vg_console
.input
) )
839 vg_info( "%s\n", vg_console
.input
);
841 if( strcmp( vg_console
.input
,
842 vg_console
.history
[ vg_console
.history_last
]) )
844 vg_console
.history_last
= ( vg_console
.history_last
+ 1) %
845 vg_list_size(vg_console
.history
);
846 vg_console
.history_count
=
847 VG_MIN( vg_list_size( vg_console
.history
),
848 vg_console
.history_count
+ 1 );
849 strcpy( vg_console
.history
[ vg_console
.history_last
],
853 vg_console
.history_pos
= -1;
854 vg_execute_console_input( vg_console
.input
);
855 console_move_cursor( &vg_console
.cursor_user
,
856 &vg_console
.cursor_pos
, -10000, 1 );
857 vg_console
.input
[0] = '\0';
859 console_update_suggestions();
863 * Suggestion controls
865 VG_STATIC
void _console_fetch_suggestion(void)
867 char *target
= &vg_console
.input
[ vg_console
.suggestion_pastepos
];
869 if( vg_console
.suggestion_select
== -1 ){
870 strcpy( target
, vg_console
.input_copy
);
871 console_move_cursor( &vg_console
.cursor_user
,
872 &vg_console
.cursor_pos
, 10000, 1 );
876 vg_console
.suggestions
[ vg_console
.suggestion_select
].str
,
877 vg_list_size( vg_console
.input
)-1 );
879 console_move_cursor( &vg_console
.cursor_user
,
880 &vg_console
.cursor_pos
, 10000, 1 );
881 console_put_char( ' ' );
885 VG_STATIC
void _console_suggest_store_normal(void)
887 if( vg_console
.suggestion_select
== -1 ){
888 char *target
= &vg_console
.input
[ vg_console
.suggestion_pastepos
];
889 strcpy( vg_console
.input_copy
, target
);
893 VG_STATIC
void _console_suggest_next(void)
895 if( vg_console
.suggestion_count
){
896 _console_suggest_store_normal();
898 vg_console
.suggestion_select
++;
900 if( vg_console
.suggestion_select
>= vg_console
.suggestion_count
)
901 vg_console
.suggestion_select
= -1;
903 _console_fetch_suggestion();
907 VG_STATIC
void _console_suggest_prev(void)
909 if( vg_console
.suggestion_count
){
910 _console_suggest_store_normal();
912 vg_console
.suggestion_select
--;
914 if( vg_console
.suggestion_select
< -1 )
915 vg_console
.suggestion_select
= vg_console
.suggestion_count
-1;
917 _console_fetch_suggestion();
924 VG_STATIC
void console_proc_key( SDL_Keysym ev
)
926 /* Open / close console */
927 if( ev
.sym
== SDLK_BACKQUOTE
){
928 vg_console
.enabled
= !vg_console
.enabled
;
930 if( vg_console
.enabled
)
931 SDL_StartTextInput();
936 if( !vg_console
.enabled
) return;
938 struct console_mapping
943 void (*handler
)(void);
947 { 0, SDLK_LEFT
, _console_left
},
948 { KMOD_SHIFT
, SDLK_LEFT
, _console_left_select
},
949 { 0, SDLK_RIGHT
, _console_right
},
950 { KMOD_SHIFT
, SDLK_RIGHT
, _console_right_select
},
951 { 0, SDLK_DOWN
, _console_down
},
952 { 0, SDLK_UP
, _console_up
},
953 { 0, SDLK_BACKSPACE
, _console_backspace
},
954 { 0, SDLK_DELETE
, _console_delete
},
955 { 0, SDLK_HOME
, _console_home
},
956 { KMOD_SHIFT
, SDLK_HOME
, _console_home_select
},
957 { 0, SDLK_END
, _console_end
},
958 { KMOD_SHIFT
, SDLK_END
, _console_end_select
},
959 { KMOD_CTRL
, SDLK_a
, _console_select_all
},
960 { KMOD_CTRL
, SDLK_c
, console_to_clipboard
},
961 { KMOD_CTRL
, SDLK_x
, _console_cut
},
962 { KMOD_CTRL
, SDLK_v
, console_clipboard_paste
},
963 { 0, SDLK_RETURN
, _console_enter
},
964 { KMOD_CTRL
, SDLK_n
, _console_suggest_next
},
965 { KMOD_CTRL
, SDLK_p
, _console_suggest_prev
}
970 if( ev
.mod
& KMOD_SHIFT
)
973 if( ev
.mod
& KMOD_CTRL
)
976 if( ev
.mod
& KMOD_ALT
)
979 for( int i
=0; i
<vg_list_size( mappings
); i
++ ){
980 struct console_mapping
*mapping
= &mappings
[i
];
982 if( mapping
->key
== ev
.sym
){
983 if( mapping
->mod
== 0 ){
989 else if( (mod
& mapping
->mod
) == mapping
->mod
){
998 * Callback for text entry mode
1000 VG_STATIC
void console_proc_utf8( const char *text
)
1002 const char *ptr
= text
;
1006 console_put_char( *ptr
);
1010 console_update_suggestions();
1013 #endif /* VG_CONSOLE_H */