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)
143 if( !vg_console
.enabled
)
146 SDL_AtomicLock( &log_print_sl
);
148 int ptr
= vg_log
.buffer_line_current
;
151 int console_lines
= VG_MIN( log_lines
, vg_log
.buffer_line_count
);
153 vg_uictx
.cursor
[0] = 0;
154 vg_uictx
.cursor
[1] = 0;
155 vg_uictx
.cursor
[3] = log_lines
*fh
;
163 ui_fill_rect( vg_uictx
.cursor
, 0x77181818 );
165 vg_uictx
.cursor
[3] = fh
;
168 for( int i
=0; i
<console_lines
; i
++ ){
172 ptr
= vg_list_size( vg_log
.buffer
)-1;
174 ui_text( vg_uictx
.cursor
, vg_log
.buffer
[ptr
], 1, 0 );
175 vg_uictx
.cursor
[1] -= fh
;
183 vg_uictx
.cursor
[1] += 2;
184 vg_uictx
.cursor
[3] = fh
;
188 ui_fill_rect( vg_uictx
.cursor
, 0x77111111 );
189 ui_text( vg_uictx
.cursor
, vg_console
.input
, 1, 0 );
191 int start
= VG_MIN( vg_console
.cursor_pos
, vg_console
.cursor_user
),
192 end
= VG_MAX( vg_console
.cursor_pos
, vg_console
.cursor_user
);
194 vg_uictx
.cursor
[0] = start
* UI_GLYPH_SPACING_X
;
195 vg_uictx
.cursor
[2] = (start
== end
? 0.5f
: (float)(end
-start
))
196 * (float)UI_GLYPH_SPACING_X
;
198 ui_fill_rect( vg_uictx
.cursor
, 0x66ffffff );
204 if( vg_console
.suggestion_count
){
205 vg_uictx
.cursor
[0] += UI_GLYPH_SPACING_X
* vg_console
.suggestion_pastepos
;
206 vg_uictx
.cursor
[1] += 2;
207 vg_uictx
.cursor
[3] = vg_console
.suggestion_count
* fh
;
208 vg_uictx
.cursor
[2] = UI_GLYPH_SPACING_X
* vg_console
.suggestion_maxlen
;
212 ui_fill_rect( vg_uictx
.cursor
, 0x77040404 );
214 vg_uictx
.cursor
[3] = fh
;
215 for( int i
=0; i
<vg_console
.suggestion_count
; i
++ ){
216 if( i
== vg_console
.suggestion_select
)
217 ui_fill_rect( vg_uictx
.cursor
, 0x66a0e508 );
219 ui_text( vg_uictx
.cursor
, vg_console
.suggestions
[i
].str
, 1, 0 );
220 vg_uictx
.cursor
[1] += fh
;
226 SDL_AtomicUnlock( &log_print_sl
);
230 VG_STATIC
int _vg_console_list( int argc
, char const *argv
[] )
232 for( int i
=0; i
<vg_console
.function_count
; i
++ ){
233 struct vg_cmd
*cmd
= &vg_console
.functions
[ i
];
234 vg_info( "* %s\n", cmd
->name
);
237 for( int i
=0; i
<vg_console
.var_count
; i
++ ){
238 struct vg_var
*cv
= &vg_console
.vars
[ i
];
239 vg_info( "%s\n", cv
->name
);
245 int _test_break( int argc
, const char *argv
[] )
247 vg_fatal_error( "Test crash from main, after loading (console)" );
251 int _vg_console_exec( int argc
, const char *argv
[] )
253 if( argc
< 1 ) return 0;
256 strcpy( path
, "cfg/" );
257 strncat( path
, argv
[0], 250 );
259 FILE *fp
= fopen( path
, "r" );
263 while( fgets( line
, sizeof( line
), fp
) ){
264 line
[ strcspn( line
, "\r\n#" ) ] = 0x00;
266 if( line
[0] != 0x00 ){
267 vg_execute_console_input( line
);
274 vg_error( "Could not open '%s'\n", path
);
280 VG_STATIC
void _vg_console_init(void)
282 vg_console_reg_cmd( "list", _vg_console_list
, NULL
);
283 vg_console_reg_cmd( "crash", _test_break
, NULL
);
284 vg_console_reg_cmd( "exec", _vg_console_exec
, NULL
);
287 VG_STATIC
void vg_console_load_autos(void)
289 _vg_console_exec( 1, (const char *[]){ "auto.conf" } );
292 VG_STATIC
void _vg_console_write_persistent(void)
294 FILE *fp
= fopen( "cfg/auto.conf", "w" );
296 for( int i
=0; i
<vg_console
.var_count
; i
++ ){
297 struct vg_var
*cv
= &vg_console
.vars
[i
];
299 if( cv
->flags
& VG_VAR_PERSISTENT
){
300 switch( cv
->data_type
){
301 case k_var_dtype_i32
:
302 fprintf( fp
, "%s %d\n", cv
->name
, *(i32
*)(cv
->data
) );
304 case k_var_dtype_u32
:
305 fprintf( fp
, "%s %u\n", cv
->name
, *(u32
*)(cv
->data
) );
307 case k_var_dtype_f32
:
308 fprintf( fp
, "%s %.5f\n", cv
->name
, *(float *)(cv
->data
) );
317 VG_STATIC
void _vg_console_free(void)
319 _vg_console_write_persistent();
323 * splits src into tokens and fills out args as pointers to those tokens
324 * returns number of tokens
325 * dst must be as long as src
327 VG_STATIC
int vg_console_tokenize( const char *src
, char *dst
,
328 const char *args
[8] )
333 for( int i
=0;; i
++ ){
335 if( src
[i
] == ' ' || src
[i
] == '\t' ){
348 args
[ arg_count
++ ] = &dst
[i
];
362 VG_STATIC vg_var
*vg_console_match_var( const char *kw
)
364 for( int i
=0; i
<vg_console
.var_count
; i
++ ){
365 struct vg_var
*cv
= &vg_console
.vars
[ i
];
366 if( !strcmp( cv
->name
, kw
) ){
374 VG_STATIC vg_cmd
*vg_console_match_cmd( const char *kw
)
376 for( int i
=0; i
<vg_console
.function_count
; i
++ ){
377 struct vg_cmd
*cmd
= &vg_console
.functions
[ i
];
378 if( !strcmp( cmd
->name
, kw
) ){
386 VG_STATIC
void vg_execute_console_input( const char *cmd
)
390 int arg_count
= vg_console_tokenize( cmd
, temp
, args
);
395 vg_var
*cv
= vg_console_match_var( args
[0] );
396 vg_cmd
*fn
= vg_console_match_cmd( args
[0] );
398 assert( !(cv
&& fn
) );
401 /* Cvar Matched, try get value */
402 if( arg_count
>= 2 ){
403 if( (cv
->data_type
== k_var_dtype_u32
) ||
404 (cv
->data_type
== k_var_dtype_i32
) )
407 *ptr
= atoi( args
[1] );
409 else if( cv
->data_type
== k_var_dtype_f32
){
410 float *ptr
= cv
->data
;
411 *ptr
= atof( args
[1] );
415 if( cv
->data_type
== k_var_dtype_i32
)
416 vg_info( "= %d\n", *((int *)cv
->data
) );
417 else if( cv
->data_type
== k_var_dtype_u32
)
418 vg_info( "= %u\n", *((u32
*)cv
->data
) );
419 else if( cv
->data_type
== k_var_dtype_f32
)
420 vg_info( "= %.4f\n", *((float *)cv
->data
) );
426 fn
->function( arg_count
-1, args
+1 );
430 vg_error( "No command/var named '%s'. Use 'list' to view all\n", args
[0] );
433 u32
str_lev_distance( const char *s1
, const char *s2
)
435 u32 m
= strlen( s1
),
441 assert( n
+1 <= 256 );
445 for( u32 k
=0; k
<=n
; k
++ )
449 for( u32 i
=0; i
<m
; i
++ ){
454 for( u32 j
=0; j
<n
; j
++ ){
455 u32 upper
= costs
[j
+1];
458 costs
[ j
+1 ] = corner
;
460 u32 t
= (upper
< corner
)? upper
: corner
;
461 costs
[j
+1] = ((costs
[j
] < t
)? costs
[j
]: t
) + 1;
471 u32
str_lcs( const char *s1
, const char *s2
)
473 u32 m
= VG_MIN( 31, strlen( s1
) ),
474 n
= VG_MIN( 31, strlen( s2
) );
479 for( int i
=0; i
<=m
; i
++ ){
480 for( int j
=0; j
<=n
; j
++ ){
481 if( i
== 0 || j
== 0 )
483 else if( s1
[i
-1] == s2
[j
-1] ){
484 suff
[i
][j
] = suff
[i
-1][j
-1] + 1;
485 result
= VG_MAX( result
, suff
[i
][j
] );
495 /* str must not fuckoff ever! */
496 VG_STATIC
void console_suggest_score_text( const char *str
, const char *input
,
499 /* filter duplicates */
500 for( int i
=0; i
<vg_console
.suggestion_count
; i
++ )
501 if( !strcmp( vg_console
.suggestions
[i
].str
, str
) )
505 u32 score
= str_lcs( str
, input
);
507 if( score
< minscore
)
510 int best_pos
= vg_console
.suggestion_count
;
511 for( int j
=best_pos
-1; j
>=0; j
-- )
512 if( score
> vg_console
.suggestions
[j
].lev_score
)
515 /* insert if good score */
516 if( best_pos
< vg_list_size( vg_console
.suggestions
) ){
517 int start
= VG_MIN( vg_console
.suggestion_count
,
518 vg_list_size( vg_console
.suggestions
)-1 );
519 for( int j
=start
; j
>best_pos
; j
-- )
520 vg_console
.suggestions
[j
] = vg_console
.suggestions
[j
-1];
522 vg_console
.suggestions
[ best_pos
].str
= str
;
523 vg_console
.suggestions
[ best_pos
].len
= strlen( str
);
524 vg_console
.suggestions
[ best_pos
].lev_score
= score
;
526 if( vg_console
.suggestion_count
<
527 vg_list_size( vg_console
.suggestions
) )
528 vg_console
.suggestion_count
++;
532 VG_STATIC
void console_update_suggestions(void)
534 vg_console
.suggestion_count
= 0;
535 vg_console
.suggestion_select
= -1;
536 vg_console
.suggestion_maxlen
= 0;
539 * - must be typing something
540 * - must be at the end
541 * - prev char must not be a whitespace
542 * - cursors should match
545 if( vg_console
.cursor_pos
== 0 )
548 if( vg_console
.cursor_pos
!= vg_console
.cursor_user
)
551 if( vg_console
.input
[ vg_console
.cursor_pos
] != '\0' )
554 if( (vg_console
.input
[ vg_console
.cursor_pos
-1 ] == ' ') ||
555 (vg_console
.input
[ vg_console
.cursor_pos
-1 ] == '\t') )
561 int token_count
= vg_console_tokenize( vg_console
.input
, temp
, args
);
563 vg_console
.suggestion_pastepos
= args
[token_count
-1]-temp
;
565 /* Score all our commands and cvars */
566 if( token_count
== 1 ){
567 for( int i
=0; i
<vg_console
.var_count
; i
++ ){
568 vg_var
*cvar
= &vg_console
.vars
[i
];
569 console_suggest_score_text( cvar
->name
, args
[0], 1 );
572 for( int i
=0; i
<vg_console
.function_count
; i
++ ){
573 vg_cmd
*cmd
= &vg_console
.functions
[i
];
574 console_suggest_score_text( cmd
->name
, args
[0], 1 );
578 vg_cmd
*cmd
= vg_console_match_cmd( args
[0] );
579 vg_var
*var
= vg_console_match_var( args
[0] );
581 assert( !( cmd
&& var
) );
584 if( cmd
->poll_suggest
)
585 cmd
->poll_suggest( token_count
-1, &args
[1] );
588 /* some post processing */
589 for( int i
=0; i
<vg_console
.suggestion_count
; i
++ ){
590 vg_console
.suggestion_maxlen
= VG_MAX( vg_console
.suggestion_maxlen
,
591 vg_console
.suggestions
[i
].len
);
593 if( vg_console
.suggestions
[i
].lev_score
<
594 vg_console
.suggestions
[0].lev_score
/2 )
596 vg_console
.suggestion_count
= i
;
605 VG_STATIC
void console_make_selection( int* start
, int* end
)
607 *start
= VG_MIN( vg_console
.cursor_pos
, vg_console
.cursor_user
);
608 *end
= VG_MAX( vg_console
.cursor_pos
, vg_console
.cursor_user
);
611 VG_STATIC
void console_move_cursor( int* cursor0
, int* cursor1
,
612 int dir
, int snap_together
)
614 *cursor0
= VG_MAX( 0, vg_console
.cursor_user
+ dir
);
617 VG_MIN( vg_list_size(vg_console
.input
)-1, strlen( vg_console
.input
)),
624 VG_STATIC
int console_makeroom( int datastart
, int length
)
626 int move_to
= VG_MIN( datastart
+length
, vg_list_size( vg_console
.input
)-1 );
627 int move_amount
= strlen( vg_console
.input
)-datastart
;
629 VG_MIN( move_to
+move_amount
, vg_list_size( vg_console
.input
)-1 );
630 move_amount
= move_end
-move_to
;
633 memmove( &vg_console
.input
[ move_to
],
634 &vg_console
.input
[ datastart
],
637 vg_console
.input
[ move_end
] = '\0';
639 return VG_MIN( length
, vg_list_size( vg_console
.input
)-datastart
-1 );
642 VG_STATIC
int console_delete_char( int direction
)
645 console_make_selection( &start
, &end
);
647 /* There is no selection */
649 if( direction
== 1 ) end
= VG_MIN( end
+1, strlen( vg_console
.input
) );
650 else if( direction
== -1 ) start
= VG_MAX( start
-1, 0 );
653 /* Still no selction, no need to do anything */
657 /* Copy the end->terminator to start */
658 int remaining_length
= strlen( vg_console
.input
)+1-end
;
659 memmove( &vg_console
.input
[ start
],
660 &vg_console
.input
[ end
],
665 VG_STATIC
void console_to_clipboard(void)
668 console_make_selection( &start
, &end
);
672 memcpy( buffer
, &vg_console
.input
[ start
], end
-start
);
673 buffer
[ end
-start
] = 0x00;
674 SDL_SetClipboardText( buffer
);
678 VG_STATIC
void console_clipboard_paste(void)
680 if( !SDL_HasClipboardText() )
683 char *text
= SDL_GetClipboardText();
688 int datastart
= console_delete_char( 0 );
689 int length
= strlen( text
);
690 int cpylength
= console_makeroom( datastart
, length
);
692 memcpy( vg_console
.input
+ datastart
, text
, cpylength
);
693 console_move_cursor( &vg_console
.cursor_user
,
694 &vg_console
.cursor_pos
, cpylength
, 1 );
697 console_update_suggestions();
700 VG_STATIC
void console_put_char( char c
)
702 if( !vg_console
.enabled
)
705 vg_console
.cursor_user
= console_delete_char(0);
707 if( console_makeroom( vg_console
.cursor_user
, 1 ) )
708 vg_console
.input
[ vg_console
.cursor_user
] = c
;
710 console_move_cursor( &vg_console
.cursor_user
, &vg_console
.cursor_pos
, 1, 1 );
713 VG_STATIC
void console_history_get( char* buf
, int entry_num
)
715 if( !vg_console
.history_count
)
718 int offset
= VG_MIN( entry_num
, vg_console
.history_count
-1 ),
719 pick
= (vg_console
.history_last
- offset
) %
720 vg_list_size( vg_console
.history
);
721 strcpy( buf
, vg_console
.history
[ pick
] );
724 /* Receed secondary cursor */
725 VG_STATIC
void _console_left_select(void)
727 console_move_cursor( &vg_console
.cursor_user
, NULL
, -1, 0 );
730 /* Match and receed both cursors */
731 VG_STATIC
void _console_left(void)
733 int cursor_diff
= vg_console
.cursor_pos
- vg_console
.cursor_user
? 0: 1;
735 console_move_cursor( &vg_console
.cursor_user
,
736 &vg_console
.cursor_pos
, -cursor_diff
, 1 );
739 VG_STATIC
void _console_right_select(void)
741 console_move_cursor( &vg_console
.cursor_user
, NULL
, 1, 0 );
744 VG_STATIC
void _console_right(void)
746 int cursor_diff
= vg_console
.cursor_pos
- vg_console
.cursor_user
? 0: 1;
748 console_move_cursor( &vg_console
.cursor_user
,
749 &vg_console
.cursor_pos
, +cursor_diff
, 1 );
752 VG_STATIC
void _console_down(void)
754 vg_console
.history_pos
= VG_MAX( 0, vg_console
.history_pos
-1 );
755 console_history_get( vg_console
.input
, vg_console
.history_pos
);
757 console_move_cursor( &vg_console
.cursor_user
,
758 &vg_console
.cursor_pos
,
759 vg_list_size(vg_console
.input
)-1, 1 );
762 VG_STATIC
void _console_up(void)
764 vg_console
.history_pos
= VG_MAX
769 vg_console
.history_pos
+1,
772 vg_list_size( vg_console
.history
),
773 vg_console
.history_count
- 1
778 console_history_get( vg_console
.input
, vg_console
.history_pos
);
779 console_move_cursor( &vg_console
.cursor_user
,
780 &vg_console
.cursor_pos
,
781 vg_list_size(vg_console
.input
)-1, 1);
784 VG_STATIC
void _console_backspace(void)
786 vg_console
.cursor_user
= console_delete_char( -1 );
787 vg_console
.cursor_pos
= vg_console
.cursor_user
;
789 console_update_suggestions();
792 VG_STATIC
void _console_delete(void)
794 vg_console
.cursor_user
= console_delete_char( 1 );
795 vg_console
.cursor_pos
= vg_console
.cursor_user
;
797 console_update_suggestions();
800 VG_STATIC
void _console_home_select(void)
802 console_move_cursor( &vg_console
.cursor_user
, NULL
, -10000, 0 );
805 VG_STATIC
void _console_home(void)
807 console_move_cursor( &vg_console
.cursor_user
,
808 &vg_console
.cursor_pos
, -10000, 1 );
811 VG_STATIC
void _console_end_select(void)
813 console_move_cursor( &vg_console
.cursor_user
, NULL
, 10000, 0 );
816 VG_STATIC
void _console_end(void)
818 console_move_cursor( &vg_console
.cursor_user
,
819 &vg_console
.cursor_pos
,
820 vg_list_size(vg_console
.input
)-1, 1 );
823 VG_STATIC
void _console_select_all(void)
825 console_move_cursor( &vg_console
.cursor_user
, NULL
, 10000, 0);
826 console_move_cursor( &vg_console
.cursor_pos
, NULL
, -10000, 0);
829 VG_STATIC
void _console_cut(void)
831 console_to_clipboard();
832 vg_console
.cursor_user
= console_delete_char(0);
833 vg_console
.cursor_pos
= vg_console
.cursor_user
;
836 VG_STATIC
void _console_enter(void)
838 if( !strlen( vg_console
.input
) )
841 vg_info( "%s\n", vg_console
.input
);
843 if( strcmp( vg_console
.input
,
844 vg_console
.history
[ vg_console
.history_last
]) )
846 vg_console
.history_last
= ( vg_console
.history_last
+ 1) %
847 vg_list_size(vg_console
.history
);
848 vg_console
.history_count
=
849 VG_MIN( vg_list_size( vg_console
.history
),
850 vg_console
.history_count
+ 1 );
851 strcpy( vg_console
.history
[ vg_console
.history_last
],
855 vg_console
.history_pos
= -1;
856 vg_execute_console_input( vg_console
.input
);
857 console_move_cursor( &vg_console
.cursor_user
,
858 &vg_console
.cursor_pos
, -10000, 1 );
859 vg_console
.input
[0] = '\0';
861 console_update_suggestions();
865 * Suggestion controls
867 VG_STATIC
void _console_fetch_suggestion(void)
869 char *target
= &vg_console
.input
[ vg_console
.suggestion_pastepos
];
871 if( vg_console
.suggestion_select
== -1 ){
872 strcpy( target
, vg_console
.input_copy
);
873 console_move_cursor( &vg_console
.cursor_user
,
874 &vg_console
.cursor_pos
, 10000, 1 );
878 vg_console
.suggestions
[ vg_console
.suggestion_select
].str
,
879 vg_list_size( vg_console
.input
)-1 );
881 console_move_cursor( &vg_console
.cursor_user
,
882 &vg_console
.cursor_pos
, 10000, 1 );
883 console_put_char( ' ' );
887 VG_STATIC
void _console_suggest_store_normal(void)
889 if( vg_console
.suggestion_select
== -1 ){
890 char *target
= &vg_console
.input
[ vg_console
.suggestion_pastepos
];
891 strcpy( vg_console
.input_copy
, target
);
895 VG_STATIC
void _console_suggest_next(void)
897 if( vg_console
.suggestion_count
){
898 _console_suggest_store_normal();
900 vg_console
.suggestion_select
++;
902 if( vg_console
.suggestion_select
>= vg_console
.suggestion_count
)
903 vg_console
.suggestion_select
= -1;
905 _console_fetch_suggestion();
909 VG_STATIC
void _console_suggest_prev(void)
911 if( vg_console
.suggestion_count
){
912 _console_suggest_store_normal();
914 vg_console
.suggestion_select
--;
916 if( vg_console
.suggestion_select
< -1 )
917 vg_console
.suggestion_select
= vg_console
.suggestion_count
-1;
919 _console_fetch_suggestion();
926 VG_STATIC
void console_proc_key( SDL_Keysym ev
)
928 /* Open / close console */
929 if( ev
.sym
== SDLK_BACKQUOTE
){
930 vg_console
.enabled
= !vg_console
.enabled
;
932 if( vg_console
.enabled
){
933 vg_info( "SDL_StartTextInput()\n" );
934 SDL_StartTextInput();
941 if( !vg_console
.enabled
) return;
943 struct console_mapping
948 void (*handler
)(void);
952 { 0, SDLK_LEFT
, _console_left
},
953 { KMOD_SHIFT
, SDLK_LEFT
, _console_left_select
},
954 { 0, SDLK_RIGHT
, _console_right
},
955 { KMOD_SHIFT
, SDLK_RIGHT
, _console_right_select
},
956 { 0, SDLK_DOWN
, _console_down
},
957 { 0, SDLK_UP
, _console_up
},
958 { 0, SDLK_BACKSPACE
, _console_backspace
},
959 { 0, SDLK_DELETE
, _console_delete
},
960 { 0, SDLK_HOME
, _console_home
},
961 { KMOD_SHIFT
, SDLK_HOME
, _console_home_select
},
962 { 0, SDLK_END
, _console_end
},
963 { KMOD_SHIFT
, SDLK_END
, _console_end_select
},
964 { KMOD_CTRL
, SDLK_a
, _console_select_all
},
965 { KMOD_CTRL
, SDLK_c
, console_to_clipboard
},
966 { KMOD_CTRL
, SDLK_x
, _console_cut
},
967 { KMOD_CTRL
, SDLK_v
, console_clipboard_paste
},
968 { 0, SDLK_RETURN
, _console_enter
},
969 { KMOD_CTRL
, SDLK_n
, _console_suggest_next
},
970 { KMOD_CTRL
, SDLK_p
, _console_suggest_prev
}
975 if( ev
.mod
& KMOD_SHIFT
)
978 if( ev
.mod
& KMOD_CTRL
)
981 if( ev
.mod
& KMOD_ALT
)
984 for( int i
=0; i
<vg_list_size( mappings
); i
++ ){
985 struct console_mapping
*mapping
= &mappings
[i
];
987 if( mapping
->key
== ev
.sym
){
988 if( mapping
->mod
== 0 ){
994 else if( (mod
& mapping
->mod
) == mapping
->mod
){
1003 * Callback for text entry mode
1005 VG_STATIC
void console_proc_utf8( const char *text
)
1007 const char *ptr
= text
;
1011 console_put_char( *ptr
);
1015 console_update_suggestions();
1018 #endif /* VG_CONSOLE_H */