2020-12-05 13:08:24 +01:00
# include "stdafx.h"
2023-02-13 19:57:38 +01:00
# include "overlay_manager.h"
2020-02-24 20:09:46 +01:00
# include "overlay_osk.h"
2020-01-07 15:12:32 +01:00
# include "Emu/RSX/RSXThread.h"
2020-03-14 22:03:56 +01:00
# include "Emu/Cell/Modules/cellSysutil.h"
2020-10-30 21:26:22 +01:00
# include "Emu/Cell/Modules/cellMsgDialog.h"
2022-04-04 22:49:59 +02:00
# include "Emu/Cell/Modules/cellKb.h"
2020-03-14 22:03:56 +01:00
LOG_CHANNEL ( osk , " OSK " ) ;
2019-01-29 17:29:55 +01:00
namespace rsx
{
namespace overlays
{
2021-04-12 23:09:23 +02:00
osk_dialog : : osk_dialog ( )
{
2022-04-04 22:49:59 +02:00
m_auto_repeat_buttons . insert ( pad_button : : L1 ) ;
m_auto_repeat_buttons . insert ( pad_button : : R1 ) ;
m_auto_repeat_buttons . insert ( pad_button : : cross ) ;
m_auto_repeat_buttons . insert ( pad_button : : triangle ) ;
m_auto_repeat_buttons . insert ( pad_button : : square ) ;
m_keyboard_input_enabled = true ;
2021-04-12 23:09:23 +02:00
}
2021-09-19 21:12:42 +02:00
void osk_dialog : : Close ( s32 status )
2019-01-29 17:29:55 +01:00
{
2023-01-24 01:15:35 +01:00
osk . notice ( " Closing osk (status=%d) " , status ) ;
2023-01-21 19:01:20 +01:00
if ( status = = FAKE_CELL_OSKDIALOG_CLOSE_TERMINATE )
{
close ( false , true ) ;
return ;
}
if ( status ! = FAKE_CELL_OSKDIALOG_CLOSE_ABORT & & m_use_separate_windows & & continuous_mode = = CELL_OSKDIALOG_CONTINUOUS_MODE_REMAIN_OPEN )
{
// Just call the on_osk_close and don't actually close the dialog.
if ( on_osk_close )
{
Emu . CallFromMainThread ( [ this , status ] ( )
{
on_osk_close ( status ) ;
} ) ;
}
return ;
}
2020-01-07 15:12:32 +01:00
fade_animation . current = color4f ( 1.f ) ;
fade_animation . end = color4f ( 0.f ) ;
fade_animation . duration = 0.5f ;
2021-09-19 21:12:42 +02:00
fade_animation . on_finish = [ this , status ]
2019-01-29 17:29:55 +01:00
{
2020-01-07 15:12:32 +01:00
if ( on_osk_close )
2019-01-29 17:29:55 +01:00
{
2022-01-20 18:44:49 +01:00
Emu . CallFromMainThread ( [ this , status ] ( )
2020-01-07 15:12:32 +01:00
{
2021-09-19 21:12:42 +02:00
on_osk_close ( status ) ;
2020-01-07 15:12:32 +01:00
} ) ;
}
2019-01-29 17:29:55 +01:00
2023-01-21 19:01:20 +01:00
set_visible ( false ) ;
// Only really close the dialog if we aren't in the continuous separate window mode
if ( ! m_use_separate_windows | | continuous_mode = = CELL_OSKDIALOG_CONTINUOUS_MODE_NONE )
{
close ( true , true ) ;
2023-01-24 01:15:35 +01:00
return ;
2023-01-21 19:01:20 +01:00
}
2020-01-07 15:12:32 +01:00
} ;
fade_animation . active = true ;
2019-01-29 17:29:55 +01:00
}
2023-01-24 01:15:35 +01:00
void osk_dialog : : Clear ( bool clear_all_data )
2023-01-24 00:13:14 +01:00
{
2023-01-24 01:15:35 +01:00
// Try to lock. Clear might be called recursively.
const bool locked = m_preview_mutex . try_lock ( ) ;
2023-01-24 00:13:14 +01:00
2023-01-24 19:38:14 +01:00
osk . notice ( " Clearing osk (clear_all_data=%d) " , clear_all_data ) ;
2023-01-24 00:13:14 +01:00
m_preview . caret_position = 0 ;
2023-01-24 01:15:35 +01:00
m_preview . set_text ( { } ) ;
if ( clear_all_data )
{
on_text_changed ( ) ;
}
if ( locked )
{
m_preview_mutex . unlock ( ) ;
}
m_update = true ;
2023-01-24 00:13:14 +01:00
}
2023-01-24 19:38:14 +01:00
void osk_dialog : : SetText ( const std : : u16string & text )
{
// Try to lock. Insert might be called recursively.
const bool locked = m_preview_mutex . try_lock ( ) ;
const std : : u16string new_str = text . length ( ) < = char_limit ? text : text . substr ( 0 , char_limit ) ;
osk . notice ( " Setting osk text (text='%s', new_str='%s', char_limit=%d) " , utf16_to_ascii8 ( text ) , utf16_to_ascii8 ( new_str ) , char_limit ) ;
m_preview . caret_position = new_str . length ( ) ;
m_preview . set_unicode_text ( utf16_to_u32string ( new_str ) ) ;
on_text_changed ( ) ;
if ( locked )
{
m_preview_mutex . unlock ( ) ;
}
m_update = true ;
}
void osk_dialog : : Insert ( const std : : u16string & text )
{
// Try to lock. Insert might be called recursively.
const bool locked = m_preview_mutex . try_lock ( ) ;
osk . notice ( " Inserting into osk at position %d (text='%s', char_limit=%d) " , m_preview . caret_position , utf16_to_ascii8 ( text ) , char_limit ) ;
// Append to output text
if ( m_preview . value . empty ( ) )
{
const std : : u16string new_str = text . length ( ) < = char_limit ? text : text . substr ( 0 , char_limit ) ;
m_preview . caret_position = new_str . length ( ) ;
m_preview . set_unicode_text ( utf16_to_u32string ( new_str ) ) ;
}
else if ( ( m_preview . value . length ( ) + text . length ( ) ) < = char_limit )
{
m_preview . insert_text ( utf16_to_u32string ( text ) ) ;
}
else
{
osk . notice ( " Can't insert into osk: Character limit reached. " ) ;
}
on_text_changed ( ) ;
if ( locked )
{
m_preview_mutex . unlock ( ) ;
}
m_update = true ;
}
2020-03-14 22:03:56 +01:00
void osk_dialog : : add_panel ( const osk_panel & panel )
{
// On PS3 apparently only 7 panels are added, the rest is ignored
if ( m_panels . size ( ) < 7 )
{
// Don't add this panel if there already exists one with the same panel mode
2021-01-12 10:59:50 +01:00
if ( std : : none_of ( m_panels . begin ( ) , m_panels . end ( ) , [ & panel ] ( const osk_panel & existing ) { return existing . osk_panel_mode = = panel . osk_panel_mode ; } ) )
2020-03-14 22:03:56 +01:00
{
2021-01-12 10:59:50 +01:00
m_panels . push_back ( panel ) ;
2020-03-14 22:03:56 +01:00
}
}
}
void osk_dialog : : step_panel ( bool next_panel )
{
2020-12-18 08:39:54 +01:00
const usz num_panels = m_panels . size ( ) ;
2020-03-14 22:03:56 +01:00
if ( num_panels > 0 )
{
if ( next_panel )
{
m_panel_index = ( m_panel_index + 1 ) % num_panels ;
}
else if ( m_panel_index > 0 )
{
m_panel_index = ( m_panel_index - 1 ) % num_panels ;
}
else
{
m_panel_index = num_panels - 1 ;
}
}
update_panel ( ) ;
}
void osk_dialog : : update_panel ( )
2019-01-29 17:29:55 +01:00
{
2020-12-09 16:04:52 +01:00
ensure ( m_panel_index < m_panels . size ( ) ) ;
2020-03-14 22:03:56 +01:00
2020-03-15 14:17:33 +01:00
const auto & panel = m_panels [ m_panel_index ] ;
2020-03-14 22:03:56 +01:00
num_rows = panel . num_rows ;
num_columns = panel . num_columns ;
2023-01-18 23:17:00 +01:00
cell_size_x = get_scaled ( panel . cell_size_x ) ;
cell_size_y = get_scaled ( panel . cell_size_y ) ;
2020-03-14 22:03:56 +01:00
update_layout ( ) ;
2019-01-29 17:29:55 +01:00
const u32 cell_count = num_rows * num_columns ;
m_grid . resize ( cell_count ) ;
2020-03-14 22:03:56 +01:00
num_shift_layers_by_charset . clear ( ) ;
2023-01-21 11:57:10 +01:00
const position2u grid_origin ( m_panel_frame . x , m_panel_frame . y ) ;
2020-03-14 22:03:56 +01:00
2020-03-15 14:17:33 +01:00
const u32 old_index = ( selected_y * num_columns ) + selected_x ;
2019-01-29 17:29:55 +01:00
u32 index = 0 ;
2020-03-14 22:03:56 +01:00
for ( const auto & props : panel . layout )
2019-01-29 17:29:55 +01:00
{
for ( u32 c = 0 ; c < props . num_cell_hz ; + + c )
{
const auto row = ( index / num_columns ) ;
const auto col = ( index % num_columns ) ;
2020-12-09 08:47:45 +01:00
ensure ( row < num_rows & & col < num_columns ) ;
2019-01-29 17:29:55 +01:00
2020-03-14 22:03:56 +01:00
auto & _cell = m_grid [ index + + ] ;
_cell . button_flag = props . type_flags ;
_cell . pos = { grid_origin . x + col * cell_size_x , grid_origin . y + row * cell_size_y } ;
2019-01-29 17:29:55 +01:00
_cell . backcolor = props . color ;
_cell . callback = props . callback ;
_cell . outputs = props . outputs ;
2019-01-31 12:01:34 +01:00
_cell . selected = false ;
2019-01-29 17:29:55 +01:00
2020-03-14 22:03:56 +01:00
// Add shift layers
for ( u32 layer = 0 ; layer < _cell . outputs . size ( ) ; + + layer )
2020-02-25 00:53:15 +01:00
{
2020-03-14 22:03:56 +01:00
// Only add a shift layer if at least one default button has content in a layer
if ( props . type_flags ! = button_flags : : _default )
2020-02-25 00:53:15 +01:00
{
2020-03-14 22:03:56 +01:00
continue ;
}
2020-12-18 08:39:54 +01:00
usz cell_shift_layers = 0 ;
2020-03-14 22:03:56 +01:00
2020-12-18 08:39:54 +01:00
for ( usz i = 0 ; i < _cell . outputs [ layer ] . size ( ) ; + + i )
2020-03-14 22:03:56 +01:00
{
if ( _cell . outputs [ layer ] [ i ] . empty ( ) = = false )
{
cell_shift_layers = i + 1 ;
}
}
if ( layer > = num_shift_layers_by_charset . size ( ) )
{
2021-04-12 22:23:24 +02:00
num_shift_layers_by_charset . push_back ( static_cast < u32 > ( cell_shift_layers ) ) ;
2020-02-25 00:53:15 +01:00
}
else
{
2021-04-12 22:23:24 +02:00
num_shift_layers_by_charset [ layer ] = std : : max ( num_shift_layers_by_charset [ layer ] , static_cast < u32 > ( cell_shift_layers ) ) ;
2020-02-25 00:53:15 +01:00
}
}
2019-01-31 12:01:34 +01:00
switch ( props . type_flags )
{
default :
case button_flags : : _default :
_cell . enabled = true ;
break ;
case button_flags : : _space :
_cell . enabled = ! ( flags & CELL_OSKDIALOG_NO_SPACE ) ;
break ;
case button_flags : : _return :
_cell . enabled = ! ( flags & CELL_OSKDIALOG_NO_RETURN ) ;
break ;
2020-02-25 00:53:15 +01:00
case button_flags : : _shift :
2020-02-26 21:13:54 +01:00
_cell . enabled | = ! _cell . outputs . empty ( ) ;
2020-02-25 00:53:15 +01:00
break ;
2020-03-14 22:03:56 +01:00
case button_flags : : _layer :
_cell . enabled | = ! num_shift_layers_by_charset . empty ( ) ;
2020-02-25 00:53:15 +01:00
break ;
2019-01-31 12:01:34 +01:00
}
2020-02-05 08:00:08 +01:00
if ( props . num_cell_hz = = 1 ) [[likely]]
2019-01-29 17:29:55 +01:00
{
_cell . flags = border_flags : : default_cell ;
}
else if ( c = = 0 )
{
// Leading cell
_cell . flags = border_flags : : start_cell ;
}
else if ( c = = ( props . num_cell_hz - 1 ) )
{
// Last cell
_cell . flags = border_flags : : end_cell ;
}
else
{
// Middle cell
_cell . flags = border_flags : : middle_cell ;
}
}
}
2020-12-09 08:47:45 +01:00
ensure ( num_shift_layers_by_charset . size ( ) ) ;
2020-02-25 00:53:15 +01:00
2020-03-14 22:03:56 +01:00
for ( u32 layer = 0 ; layer < num_shift_layers_by_charset . size ( ) ; + + layer )
2020-02-25 00:53:15 +01:00
{
2020-12-09 08:47:45 +01:00
ensure ( num_shift_layers_by_charset [ layer ] ) ;
2020-02-25 00:53:15 +01:00
}
2019-01-29 17:29:55 +01:00
2020-03-15 14:17:33 +01:00
// Reset to first shift layer in the first charset, because the panel changed and we don't know if the layers are similar between panels.
2020-03-14 22:03:56 +01:00
m_selected_charset = 0 ;
2020-03-15 14:17:33 +01:00
selected_z = 0 ;
2019-01-29 17:29:55 +01:00
2020-03-15 14:17:33 +01:00
// Enable/Disable the control buttons based on the current layout.
2020-03-14 22:03:56 +01:00
update_controls ( ) ;
2019-01-29 17:29:55 +01:00
2020-03-15 14:17:33 +01:00
// Roughly keep x and y selection in grid if possible. Jumping to (0,0) would be annoying. Needs to be done after updating the control buttons.
update_selection_by_index ( old_index ) ;
2020-03-14 22:03:56 +01:00
m_update = true ;
}
void osk_dialog : : update_layout ( )
{
2023-01-21 11:57:10 +01:00
const bool show_panel = m_show_panel | | ! m_use_separate_windows ;
2023-01-23 20:19:30 +01:00
// The title is omitted in separate window mode
const u16 title_height = m_use_separate_windows ? 0 : get_scaled ( 30 ) ;
2023-01-18 23:17:00 +01:00
const u16 preview_height = get_scaled ( ( flags & CELL_OSKDIALOG_NO_RETURN ) ? 40 : 90 ) ;
2019-01-31 12:01:34 +01:00
2019-01-29 17:29:55 +01:00
// Place elements with absolute positioning
2023-01-18 23:17:00 +01:00
const u16 button_margin = get_scaled ( 30 ) ;
const u16 button_height = get_scaled ( 30 ) ;
2023-01-21 11:57:10 +01:00
const u16 panel_w = show_panel ? ( num_columns * cell_size_x ) : 0 ;
const u16 panel_h = show_panel ? ( num_rows * cell_size_y ) : 0 ;
const u16 input_w = m_use_separate_windows ? m_input_field_window_width : panel_w ;
const u16 input_h = title_height + preview_height ;
const u16 button_h = show_panel ? ( button_height + button_margin ) : 0 ;
const u16 total_w = std : : max ( input_w , panel_w ) ;
const u16 total_h = input_h + panel_h + button_h ;
2023-01-18 22:30:00 +01:00
2023-01-23 20:02:05 +01:00
// The cellOskDialog's origin is at the center of the screen with positive values increasing toward the right and upper directions.
// The layout mode tells us which corner of the dialog we should use for positioning.
// With CELL_OSKDIALOG_LAYOUTMODE_X_ALIGN_LEFT and CELL_OSKDIALOG_LAYOUTMODE_Y_ALIGN_TOP and a point (0,0) the dialog's top left corner would be in the center of the screen.
// With CELL_OSKDIALOG_LAYOUTMODE_X_ALIGN_CENTER and CELL_OSKDIALOG_LAYOUTMODE_Y_ALIGN_CENTER and a point (0,0) the dialog would be exactly in the center of the screen.
2023-01-21 11:57:10 +01:00
2023-01-23 20:02:05 +01:00
// TODO: Make sure separate windows don't overlap.
2019-01-29 17:29:55 +01:00
2023-01-20 03:56:58 +01:00
// Calculate initial position and analog movement range.
2023-01-20 00:24:27 +01:00
constexpr f32 margin = 50.0f ; // Let's add a minimal margin on all sides
2023-01-20 03:56:58 +01:00
const u16 x_min = static_cast < u16 > ( margin ) ;
2023-01-21 11:57:10 +01:00
const u16 x_max = static_cast < u16 > ( static_cast < f32 > ( virtual_width - total_w ) - margin ) ;
2023-01-20 03:56:58 +01:00
const u16 y_min = static_cast < u16 > ( margin ) ;
2023-01-21 11:57:10 +01:00
const u16 y_max = static_cast < u16 > ( static_cast < f32 > ( virtual_height - total_h ) - margin ) ;
u16 input_x = 0 ;
u16 input_y = 0 ;
u16 panel_x = 0 ;
u16 panel_y = 0 ;
// x pos should only be 0 the first time, because we always add a margin
if ( m_x_input_pos = = 0 )
{
2023-01-23 20:02:05 +01:00
const auto get_x = [ ] ( const osk_window_layout & layout , const u16 & width ) - > f32
{
constexpr f32 origin_x = virtual_width / 2.0f ;
const f32 x = origin_x + layout . x_offset ;
switch ( layout . x_align )
{
case CELL_OSKDIALOG_LAYOUTMODE_X_ALIGN_RIGHT :
return x - width ;
case CELL_OSKDIALOG_LAYOUTMODE_X_ALIGN_CENTER :
return x - ( width / 2.0f ) ;
case CELL_OSKDIALOG_LAYOUTMODE_X_ALIGN_LEFT :
default :
return x ;
}
} ;
const auto get_y = [ ] ( const osk_window_layout & layout , const u16 & height ) - > f32
{
constexpr f32 origin_y = virtual_height / 2.0f ;
2023-01-28 22:29:10 +01:00
const f32 y = origin_y - layout . y_offset ; // Negative because we increase y towards the bottom and cellOsk increases y towards the top.
2023-01-23 20:02:05 +01:00
switch ( layout . y_align )
{
case CELL_OSKDIALOG_LAYOUTMODE_Y_ALIGN_BOTTOM :
return y - height ;
case CELL_OSKDIALOG_LAYOUTMODE_Y_ALIGN_CENTER :
return y - ( height / 2.0f ) ;
case CELL_OSKDIALOG_LAYOUTMODE_Y_ALIGN_TOP :
default :
return y ;
}
} ;
2023-01-20 03:56:58 +01:00
2023-01-21 11:57:10 +01:00
if ( m_use_separate_windows )
{
2023-01-23 20:02:05 +01:00
input_x = m_x_input_pos = static_cast < u16 > ( std : : clamp < f32 > ( get_x ( m_input_layout , input_w ) , x_min , x_max ) ) ;
input_y = m_y_input_pos = static_cast < u16 > ( std : : clamp < f32 > ( get_y ( m_input_layout , input_h ) , y_min , y_max ) ) ;
panel_x = m_x_panel_pos = static_cast < u16 > ( std : : clamp < f32 > ( get_x ( m_panel_layout , panel_w ) , x_min , x_max ) ) ;
2023-01-23 20:19:30 +01:00
panel_y = m_y_panel_pos = static_cast < u16 > ( std : : clamp < f32 > ( get_y ( m_panel_layout , panel_h ) , static_cast < f32 > ( y_min + input_h ) , static_cast < f32 > ( y_max + input_h ) ) ) ;
2023-01-21 11:57:10 +01:00
}
else
{
2023-01-23 20:02:05 +01:00
input_x = panel_x = m_x_input_pos = m_x_panel_pos = static_cast < u16 > ( std : : clamp < f32 > ( get_x ( m_layout , total_w ) , x_min , x_max ) ) ;
input_y = m_y_input_pos = static_cast < u16 > ( std : : clamp < f32 > ( get_y ( m_layout , total_h ) , y_min , y_max ) ) ;
2023-01-21 11:57:10 +01:00
panel_y = m_y_panel_pos = input_y + input_h ;
}
}
else if ( m_use_separate_windows )
2023-01-20 03:56:58 +01:00
{
2023-01-21 11:57:10 +01:00
input_x = m_x_input_pos = std : : clamp ( m_x_input_pos , x_min , x_max ) ;
input_y = m_y_input_pos = std : : clamp ( m_y_input_pos , y_min , y_max ) ;
panel_x = m_x_panel_pos = std : : clamp ( m_x_panel_pos , x_min , x_max ) ;
panel_y = m_y_panel_pos = std : : clamp < u16 > ( m_y_panel_pos , y_min + input_h , y_max + input_h ) ;
2023-01-20 03:56:58 +01:00
}
else
{
2023-01-21 11:57:10 +01:00
input_x = panel_x = m_x_input_pos = m_x_panel_pos = std : : clamp ( m_x_input_pos , x_min , x_max ) ;
input_y = m_y_input_pos = std : : clamp ( m_y_input_pos , y_min , y_max ) ;
panel_y = m_y_panel_pos = input_y + input_h ;
2023-01-20 03:56:58 +01:00
}
2023-01-20 00:24:27 +01:00
2023-01-21 11:57:10 +01:00
m_input_frame . set_pos ( input_x , input_y ) ;
m_input_frame . set_size ( input_w , input_h ) ;
m_panel_frame . set_pos ( panel_x , panel_y ) ;
m_panel_frame . set_size ( panel_w , panel_h ) ;
2019-01-29 17:29:55 +01:00
2023-01-21 11:57:10 +01:00
m_title . set_pos ( input_x , input_y ) ;
m_title . set_size ( input_w , title_height ) ;
2023-01-18 23:17:00 +01:00
m_title . set_padding ( get_scaled ( 15 ) , 0 , get_scaled ( 5 ) , 0 ) ;
2019-01-29 17:29:55 +01:00
2023-01-21 11:57:10 +01:00
m_preview . set_pos ( input_x , input_y + title_height ) ;
m_preview . set_size ( input_w , preview_height ) ;
2023-01-18 23:17:00 +01:00
m_preview . set_padding ( get_scaled ( 15 ) , 0 , get_scaled ( 10 ) , 0 ) ;
2019-01-29 17:29:55 +01:00
2023-01-21 11:57:10 +01:00
const u16 button_y = panel_y + panel_h + button_margin ;
m_btn_cancel . set_pos ( panel_x , button_y ) ;
2023-01-18 23:17:00 +01:00
m_btn_cancel . set_size ( get_scaled ( 140 ) , button_height ) ;
2020-09-02 16:20:29 +02:00
m_btn_cancel . set_text ( localized_string_id : : RSX_OVERLAYS_OSK_DIALOG_CANCEL ) ;
2023-01-18 23:17:00 +01:00
m_btn_cancel . set_text_vertical_adjust ( get_scaled ( 5 ) ) ;
2019-01-30 10:50:29 +01:00
2023-01-21 11:57:10 +01:00
m_btn_space . set_pos ( panel_x + get_scaled ( 100 ) , button_y ) ;
2023-01-18 23:17:00 +01:00
m_btn_space . set_size ( get_scaled ( 100 ) , button_height ) ;
2020-09-02 16:20:29 +02:00
m_btn_space . set_text ( localized_string_id : : RSX_OVERLAYS_OSK_DIALOG_SPACE ) ;
2023-01-18 23:17:00 +01:00
m_btn_space . set_text_vertical_adjust ( get_scaled ( 5 ) ) ;
2019-01-30 10:50:29 +01:00
2023-01-21 11:57:10 +01:00
m_btn_delete . set_pos ( panel_x + get_scaled ( 200 ) , button_y ) ;
2023-01-18 23:17:00 +01:00
m_btn_delete . set_size ( get_scaled ( 100 ) , button_height ) ;
2020-09-02 16:20:29 +02:00
m_btn_delete . set_text ( localized_string_id : : RSX_OVERLAYS_OSK_DIALOG_BACKSPACE ) ;
2023-01-18 23:17:00 +01:00
m_btn_delete . set_text_vertical_adjust ( get_scaled ( 5 ) ) ;
2019-01-30 10:50:29 +01:00
2023-01-21 11:57:10 +01:00
m_btn_shift . set_pos ( panel_x + get_scaled ( 320 ) , button_y ) ;
2023-01-18 23:17:00 +01:00
m_btn_shift . set_size ( get_scaled ( 80 ) , button_height ) ;
2020-09-02 16:20:29 +02:00
m_btn_shift . set_text ( localized_string_id : : RSX_OVERLAYS_OSK_DIALOG_SHIFT ) ;
2023-01-18 23:17:00 +01:00
m_btn_shift . set_text_vertical_adjust ( get_scaled ( 5 ) ) ;
2019-01-29 17:29:55 +01:00
2023-01-21 11:57:10 +01:00
m_btn_accept . set_pos ( panel_x + get_scaled ( 400 ) , button_y ) ;
2023-01-18 23:17:00 +01:00
m_btn_accept . set_size ( get_scaled ( 100 ) , button_height ) ;
2020-09-02 16:20:29 +02:00
m_btn_accept . set_text ( localized_string_id : : RSX_OVERLAYS_OSK_DIALOG_ACCEPT ) ;
2023-01-18 23:17:00 +01:00
m_btn_accept . set_text_vertical_adjust ( get_scaled ( 5 ) ) ;
2019-01-29 17:29:55 +01:00
2020-03-14 22:03:56 +01:00
m_update = true ;
}
2021-04-12 15:14:13 +02:00
void osk_dialog : : initialize_layout ( const std : : u32string & title , const std : : u32string & initial_text )
2020-03-14 22:03:56 +01:00
{
2023-01-18 23:17:00 +01:00
const auto scale_font = [ this ] ( overlay_element & elem )
{
if ( const font * fnt = elem . get_font ( ) )
{
elem . set_font ( fnt - > get_name ( ) . data ( ) , get_scaled ( fnt - > get_size_pt ( ) ) ) ;
}
} ;
2023-01-19 00:39:43 +01:00
m_pointer . set_color ( color4f { 1.f , 1.f , 1.f , 1.f } ) ;
2023-01-18 22:30:00 +01:00
m_background . set_size ( virtual_width , virtual_height ) ;
2020-03-14 22:03:56 +01:00
2021-04-12 15:14:13 +02:00
m_title . set_unicode_text ( title ) ;
2023-01-18 23:17:00 +01:00
scale_font ( m_title ) ;
2020-03-14 22:03:56 +01:00
2021-04-12 19:28:39 +02:00
m_preview . password_mode = m_password_mode ;
2021-04-12 15:14:13 +02:00
m_preview . set_placeholder ( get_placeholder ( ) ) ;
m_preview . set_unicode_text ( initial_text ) ;
2023-01-18 23:17:00 +01:00
scale_font ( m_preview ) ;
2021-04-12 15:14:13 +02:00
if ( m_preview . value . empty ( ) )
2020-03-14 22:03:56 +01:00
{
m_preview . caret_position = 0 ;
m_preview . fore_color . a = 0.5f ; // Muted contrast for hint text
}
else
{
2021-09-02 19:00:30 +02:00
m_preview . caret_position = m_preview . value . length ( ) ;
2020-03-14 22:03:56 +01:00
m_preview . fore_color . a = 1.f ;
}
2023-01-18 23:17:00 +01:00
scale_font ( m_btn_shift ) ;
scale_font ( m_btn_accept ) ;
scale_font ( m_btn_space ) ;
scale_font ( m_btn_delete ) ;
scale_font ( m_btn_cancel ) ;
m_btn_shift . text_horizontal_offset = get_scaled ( m_btn_shift . text_horizontal_offset ) ;
m_btn_accept . text_horizontal_offset = get_scaled ( m_btn_accept . text_horizontal_offset ) ;
m_btn_space . text_horizontal_offset = get_scaled ( m_btn_space . text_horizontal_offset ) ;
m_btn_delete . text_horizontal_offset = get_scaled ( m_btn_delete . text_horizontal_offset ) ;
m_btn_cancel . text_horizontal_offset = get_scaled ( m_btn_cancel . text_horizontal_offset ) ;
2019-01-30 10:50:29 +01:00
m_btn_shift . set_image_resource ( resource_config : : standard_image_resource : : select ) ;
m_btn_accept . set_image_resource ( resource_config : : standard_image_resource : : start ) ;
m_btn_space . set_image_resource ( resource_config : : standard_image_resource : : triangle ) ;
m_btn_delete . set_image_resource ( resource_config : : standard_image_resource : : square ) ;
2019-01-29 17:29:55 +01:00
if ( g_cfg . sys . enter_button_assignment = = enter_button_assign : : circle )
{
m_btn_cancel . set_image_resource ( resource_config : : standard_image_resource : : cross ) ;
}
else
{
m_btn_cancel . set_image_resource ( resource_config : : standard_image_resource : : circle ) ;
}
2019-01-31 12:01:34 +01:00
m_update = true ;
2023-01-21 19:01:20 +01:00
set_visible ( continuous_mode ! = CELL_OSKDIALOG_CONTINUOUS_MODE_HIDE ) ;
2022-07-29 18:00:24 +02:00
m_stop_input_loop = false ;
2019-01-29 17:29:55 +01:00
2020-01-07 15:12:32 +01:00
fade_animation . current = color4f ( 0.f ) ;
fade_animation . end = color4f ( 1.f ) ;
fade_animation . duration = 0.5f ;
fade_animation . active = true ;
2020-03-14 22:03:56 +01:00
}
2020-01-07 15:12:32 +01:00
2020-03-14 22:03:56 +01:00
void osk_dialog : : update_controls ( )
{
const bool shift_enabled = num_shift_layers_by_charset [ m_selected_charset ] > 1 ;
const bool layer_enabled = num_shift_layers_by_charset . size ( ) > 1 ;
2020-02-27 15:28:42 +01:00
2020-03-14 22:03:56 +01:00
for ( auto & cell : m_grid )
{
switch ( cell . button_flag )
2019-01-29 17:29:55 +01:00
{
2020-03-14 22:03:56 +01:00
case button_flags : : _shift :
cell . enabled = shift_enabled ;
break ;
case button_flags : : _layer :
cell . enabled = layer_enabled ;
break ;
default :
break ;
2019-01-29 17:29:55 +01:00
}
2020-03-14 22:03:56 +01:00
}
2020-02-25 21:16:55 +01:00
2020-03-14 22:03:56 +01:00
m_update = true ;
2019-01-29 17:29:55 +01:00
}
2020-03-15 14:17:33 +01:00
std : : pair < u32 , u32 > osk_dialog : : get_cell_geometry ( u32 index )
2019-01-29 17:29:55 +01:00
{
2023-01-18 23:17:00 +01:00
const u32 grid_size = num_columns * num_rows ;
2020-03-15 14:17:33 +01:00
u32 start_index = index ;
u32 count = 0 ;
2019-01-29 17:29:55 +01:00
2023-01-18 23:17:00 +01:00
while ( start_index > = grid_size & & start_index > = num_columns )
2019-01-29 17:29:55 +01:00
{
2020-03-15 14:17:33 +01:00
// Try one row above
start_index - = num_columns ;
}
2019-01-29 17:29:55 +01:00
2020-03-15 14:17:33 +01:00
// Find first cell
while ( ! ( m_grid [ start_index ] . flags & border_flags : : left ) & & start_index )
{
- - start_index ;
}
2019-01-29 17:29:55 +01:00
2020-03-15 14:17:33 +01:00
// Find last cell
while ( true )
{
2023-01-18 23:17:00 +01:00
const u32 current_index = ( start_index + count ) ;
ensure ( current_index < grid_size ) ;
2021-04-12 15:14:13 +02:00
+ + count ;
2019-01-29 17:29:55 +01:00
2020-03-15 14:17:33 +01:00
if ( m_grid [ current_index ] . flags & border_flags : : right )
{
break ;
2019-01-29 17:29:55 +01:00
}
2020-03-15 14:17:33 +01:00
}
2019-01-29 17:29:55 +01:00
2020-03-15 14:17:33 +01:00
return std : : make_pair ( start_index , count ) ;
}
void osk_dialog : : update_selection_by_index ( u32 index )
{
2021-04-12 22:23:24 +02:00
auto select_cell = [ & ] ( u32 i , bool state )
2019-01-29 17:29:55 +01:00
{
2021-04-12 22:23:24 +02:00
const auto info = get_cell_geometry ( i ) ;
2019-01-29 17:29:55 +01:00
// Tag all in range
for ( u32 _index = info . first , _ctr = 0 ; _ctr < info . second ; + + _index , + + _ctr )
{
m_grid [ _index ] . selected = state ;
}
} ;
2020-03-15 14:17:33 +01:00
// 1. Deselect current
const auto current_index = ( selected_y * num_columns ) + selected_x ;
select_cell ( current_index , false ) ;
// 2. Select new
selected_y = index / num_columns ;
selected_x = index % num_columns ;
select_cell ( index , true ) ;
}
2023-01-21 19:01:20 +01:00
void osk_dialog : : set_visible ( bool visible )
{
if ( m_use_separate_windows )
{
if ( visible & & continuous_mode = = CELL_OSKDIALOG_CONTINUOUS_MODE_HIDE )
{
continuous_mode = CELL_OSKDIALOG_CONTINUOUS_MODE_SHOW ;
}
else if ( ! visible & & continuous_mode = = CELL_OSKDIALOG_CONTINUOUS_MODE_SHOW )
{
continuous_mode = CELL_OSKDIALOG_CONTINUOUS_MODE_HIDE ;
}
}
if ( this - > visible ! = visible )
{
this - > visible = visible ;
if ( m_use_separate_windows )
{
osk . notice ( " set_visible: sending CELL_SYSUTIL_OSKDIALOG_DISPLAY_CHANGED with %s " , visible ? " CELL_OSKDIALOG_DISPLAY_STATUS_SHOW " : " CELL_OSKDIALOG_DISPLAY_STATUS_HIDE " ) ;
sysutil_send_system_cmd ( CELL_SYSUTIL_OSKDIALOG_DISPLAY_CHANGED , visible ? CELL_OSKDIALOG_DISPLAY_STATUS_SHOW : CELL_OSKDIALOG_DISPLAY_STATUS_HIDE ) ;
}
}
}
2023-05-20 17:30:09 +02:00
void osk_dialog : : on_button_pressed ( pad_button button_press , bool is_auto_repeat )
2020-03-15 14:17:33 +01:00
{
2023-01-22 17:01:33 +01:00
if ( ! pad_input_enabled )
2022-04-19 20:27:32 +02:00
return ;
2023-01-22 17:01:33 +01:00
if ( ! ignore_device_events & & input_device . exchange ( CELL_OSKDIALOG_INPUT_DEVICE_PAD ) ! = CELL_OSKDIALOG_INPUT_DEVICE_PAD )
2023-01-21 15:42:10 +01:00
{
2023-01-21 19:01:20 +01:00
osk . notice ( " on_button_pressed: sending CELL_SYSUTIL_OSKDIALOG_INPUT_DEVICE_CHANGED with CELL_OSKDIALOG_INPUT_DEVICE_PAD " ) ;
2023-01-21 15:42:10 +01:00
sysutil_send_system_cmd ( CELL_SYSUTIL_OSKDIALOG_INPUT_DEVICE_CHANGED , CELL_OSKDIALOG_INPUT_DEVICE_PAD ) ;
}
2023-01-22 17:01:33 +01:00
if ( input_device ! = CELL_OSKDIALOG_INPUT_DEVICE_PAD )
{
return ;
}
2023-01-21 15:42:10 +01:00
// Always show the pad input panel if the pad is enabled and in use.
if ( ! m_show_panel )
{
m_show_panel = true ;
update_panel ( ) ;
}
2023-01-24 00:25:33 +01:00
// Make sure to show the dialog and send necessary events
set_visible ( true ) ;
2023-01-24 00:13:14 +01:00
std : : lock_guard lock ( m_preview_mutex ) ;
2023-01-18 23:17:00 +01:00
const u32 grid_size = num_columns * num_rows ;
2019-01-29 17:29:55 +01:00
2021-03-09 20:40:14 +01:00
const auto on_accept = [ this ] ( )
2019-01-29 17:29:55 +01:00
{
const u32 current_index = ( selected_y * num_columns ) + selected_x ;
2020-02-25 00:53:15 +01:00
const auto & current_cell = m_grid [ current_index ] ;
u32 output_count = 0 ;
2020-03-14 22:03:56 +01:00
if ( m_selected_charset < current_cell . outputs . size ( ) )
2020-02-25 00:53:15 +01:00
{
2020-03-14 22:03:56 +01:00
output_count = : : size32 ( current_cell . outputs [ m_selected_charset ] ) ;
2020-02-25 00:53:15 +01:00
}
2019-01-29 17:29:55 +01:00
if ( output_count )
{
const auto _z = std : : clamp < u32 > ( selected_z , 0u , output_count - 1u ) ;
2020-03-14 22:03:56 +01:00
const auto & str = current_cell . outputs [ m_selected_charset ] [ _z ] ;
2019-01-29 17:29:55 +01:00
2020-02-25 00:53:15 +01:00
if ( current_cell . callback )
2019-01-29 17:29:55 +01:00
{
2020-02-25 00:53:15 +01:00
current_cell . callback ( str ) ;
2019-01-29 17:29:55 +01:00
}
else
{
on_default_callback ( str ) ;
}
}
} ;
2023-01-20 03:56:58 +01:00
// Increase auto repeat interval for some buttons
switch ( button_press )
{
case pad_button : : rs_left :
case pad_button : : rs_right :
case pad_button : : rs_down :
case pad_button : : rs_up :
m_auto_repeat_ms_interval = 10 ;
break ;
default :
m_auto_repeat_ms_interval = m_auto_repeat_ms_interval_default ;
break ;
}
2021-10-31 00:48:41 +02:00
bool play_cursor_sound = true ;
2019-01-29 17:29:55 +01:00
switch ( button_press )
{
2019-01-31 12:01:34 +01:00
case pad_button : : L1 :
{
m_preview . move_caret ( edit_text : : direction : : left ) ;
m_update = true ;
break ;
}
case pad_button : : R1 :
{
m_preview . move_caret ( edit_text : : direction : : right ) ;
m_update = true ;
break ;
}
2019-01-29 17:29:55 +01:00
case pad_button : : dpad_right :
2021-11-15 22:21:21 +01:00
case pad_button : : ls_right :
2019-01-29 17:29:55 +01:00
{
u32 current_index = ( selected_y * num_columns ) + selected_x ;
2019-01-31 12:01:34 +01:00
while ( true )
{
const auto current = get_cell_geometry ( current_index ) ;
current_index = current . first + current . second ;
2019-01-29 17:29:55 +01:00
2023-01-18 23:17:00 +01:00
if ( current_index > = grid_size )
2019-01-31 12:01:34 +01:00
{
break ;
}
2019-01-29 17:29:55 +01:00
2019-01-31 12:01:34 +01:00
if ( m_grid [ get_cell_geometry ( current_index ) . first ] . enabled )
{
2020-03-15 14:17:33 +01:00
update_selection_by_index ( current_index ) ;
2019-01-31 12:01:34 +01:00
break ;
}
2019-01-29 17:29:55 +01:00
}
2021-03-09 20:40:14 +01:00
m_reset_pulse = true ;
2019-01-29 17:29:55 +01:00
break ;
}
case pad_button : : dpad_left :
2021-11-15 22:21:21 +01:00
case pad_button : : ls_left :
2019-01-29 17:29:55 +01:00
{
u32 current_index = ( selected_y * num_columns ) + selected_x ;
2019-01-31 12:01:34 +01:00
while ( current_index > 0 )
2019-01-29 17:29:55 +01:00
{
const auto current = get_cell_geometry ( current_index ) ;
if ( current . first )
{
current_index = current . first - 1 ;
2019-01-31 12:01:34 +01:00
if ( m_grid [ get_cell_geometry ( current_index ) . first ] . enabled )
{
2020-03-15 14:17:33 +01:00
update_selection_by_index ( current_index ) ;
2019-01-31 12:01:34 +01:00
break ;
}
}
else
{
break ;
2019-01-29 17:29:55 +01:00
}
}
2021-03-09 20:40:14 +01:00
m_reset_pulse = true ;
2019-01-29 17:29:55 +01:00
break ;
}
case pad_button : : dpad_down :
2021-11-15 22:21:21 +01:00
case pad_button : : ls_down :
2019-01-29 17:29:55 +01:00
{
u32 current_index = ( selected_y * num_columns ) + selected_x ;
2019-01-31 12:01:34 +01:00
while ( true )
2019-01-29 17:29:55 +01:00
{
2019-01-31 12:01:34 +01:00
current_index + = num_columns ;
2023-01-18 23:17:00 +01:00
if ( current_index > = grid_size )
2019-01-31 12:01:34 +01:00
{
break ;
}
if ( m_grid [ get_cell_geometry ( current_index ) . first ] . enabled )
{
2020-03-15 14:17:33 +01:00
update_selection_by_index ( current_index ) ;
2019-01-31 12:01:34 +01:00
break ;
}
2019-01-29 17:29:55 +01:00
}
2021-03-09 20:40:14 +01:00
m_reset_pulse = true ;
2019-01-29 17:29:55 +01:00
break ;
}
case pad_button : : dpad_up :
2021-11-15 22:21:21 +01:00
case pad_button : : ls_up :
2019-01-29 17:29:55 +01:00
{
u32 current_index = ( selected_y * num_columns ) + selected_x ;
2019-01-31 12:01:34 +01:00
while ( current_index > = num_columns )
2019-01-29 17:29:55 +01:00
{
current_index - = num_columns ;
2019-01-31 12:01:34 +01:00
if ( m_grid [ get_cell_geometry ( current_index ) . first ] . enabled )
{
2020-03-15 14:17:33 +01:00
update_selection_by_index ( current_index ) ;
2019-01-31 12:01:34 +01:00
break ;
}
2019-01-29 17:29:55 +01:00
}
2021-03-09 20:40:14 +01:00
m_reset_pulse = true ;
2019-01-29 17:29:55 +01:00
break ;
}
2019-01-30 10:50:29 +01:00
case pad_button : : select :
{
2020-02-24 17:03:19 +01:00
on_shift ( U " " ) ;
2019-01-30 10:50:29 +01:00
break ;
}
case pad_button : : start :
{
2022-02-05 21:15:45 +01:00
Emu . GetCallbacks ( ) . play_sound ( fs : : get_config_dir ( ) + " sounds/snd_oskenter.wav " ) ;
2021-09-19 21:12:42 +02:00
Close ( CELL_OSKDIALOG_CLOSE_CONFIRM ) ;
2021-10-31 00:48:41 +02:00
play_cursor_sound = false ;
2019-01-30 10:50:29 +01:00
break ;
}
2019-01-29 17:29:55 +01:00
case pad_button : : triangle :
{
2020-02-24 17:03:19 +01:00
on_space ( U " " ) ;
2019-01-29 17:29:55 +01:00
break ;
}
case pad_button : : square :
{
2020-02-24 17:03:19 +01:00
on_backspace ( U " " ) ;
2019-01-29 17:29:55 +01:00
break ;
}
case pad_button : : cross :
{
2022-02-05 21:15:45 +01:00
Emu . GetCallbacks ( ) . play_sound ( fs : : get_config_dir ( ) + " sounds/snd_oskenter.wav " ) ;
2019-09-19 19:06:35 +02:00
on_accept ( ) ;
2021-03-09 20:40:14 +01:00
m_reset_pulse = true ;
2021-10-31 00:48:41 +02:00
play_cursor_sound = false ;
2019-01-29 17:29:55 +01:00
break ;
}
case pad_button : : circle :
{
2022-02-05 21:15:45 +01:00
Emu . GetCallbacks ( ) . play_sound ( fs : : get_config_dir ( ) + " sounds/snd_oskcancel.wav " ) ;
2021-09-19 21:12:42 +02:00
Close ( CELL_OSKDIALOG_CLOSE_CANCEL ) ;
2021-10-31 00:48:41 +02:00
play_cursor_sound = false ;
2019-01-29 17:29:55 +01:00
break ;
}
2020-03-14 22:03:56 +01:00
case pad_button : : L2 :
{
step_panel ( false ) ;
break ;
}
case pad_button : : R2 :
{
step_panel ( true ) ;
break ;
}
2023-01-20 03:56:58 +01:00
case pad_button : : rs_left :
case pad_button : : rs_right :
case pad_button : : rs_down :
case pad_button : : rs_up :
{
if ( ! ( flags & CELL_OSKDIALOG_NO_INPUT_ANALOG ) )
{
switch ( button_press )
{
2023-01-21 11:57:10 +01:00
case pad_button : : rs_left : m_x_input_pos - = 5 ; m_x_panel_pos - = 5 ; break ;
case pad_button : : rs_right : m_x_input_pos + = 5 ; m_x_panel_pos + = 5 ; break ;
case pad_button : : rs_down : m_y_input_pos + = 5 ; m_y_panel_pos + = 5 ; break ;
case pad_button : : rs_up : m_y_input_pos - = 5 ; m_y_panel_pos - = 5 ; break ;
2023-01-20 03:56:58 +01:00
default : break ;
}
update_panel ( ) ;
}
play_cursor_sound = false ;
break ;
}
2019-05-11 07:36:16 +02:00
default :
break ;
2019-01-29 17:29:55 +01:00
}
2021-03-09 20:40:14 +01:00
2023-05-20 17:30:09 +02:00
// Play a sound unless this is a fast auto repeat which would induce a nasty noise
if ( play_cursor_sound & & ( ! is_auto_repeat | | m_auto_repeat_ms_interval > = m_auto_repeat_ms_interval_default ) )
2021-10-31 00:48:41 +02:00
{
Emu . GetCallbacks ( ) . play_sound ( fs : : get_config_dir ( ) + " sounds/snd_cursor.wav " ) ;
}
2021-03-09 20:40:14 +01:00
if ( m_reset_pulse )
{
m_update = true ;
}
2019-01-29 17:29:55 +01:00
}
2022-04-04 22:49:59 +02:00
2022-10-29 11:29:38 +02:00
void osk_dialog : : on_key_pressed ( u32 led , u32 mkey , u32 key_code , u32 out_key_code , bool pressed , std : : u32string key )
2022-04-04 22:49:59 +02:00
{
2023-01-22 17:01:33 +01:00
if ( ! pressed | | ! keyboard_input_enabled )
2022-04-04 22:49:59 +02:00
return ;
2023-01-22 17:01:33 +01:00
if ( ! ignore_device_events & & input_device . exchange ( CELL_OSKDIALOG_INPUT_DEVICE_KEYBOARD ) ! = CELL_OSKDIALOG_INPUT_DEVICE_KEYBOARD )
2023-01-21 15:42:10 +01:00
{
2023-01-21 19:01:20 +01:00
osk . notice ( " on_key_pressed: sending CELL_SYSUTIL_OSKDIALOG_INPUT_DEVICE_CHANGED with CELL_OSKDIALOG_INPUT_DEVICE_KEYBOARD " ) ;
2023-01-21 15:42:10 +01:00
sysutil_send_system_cmd ( CELL_SYSUTIL_OSKDIALOG_INPUT_DEVICE_CHANGED , CELL_OSKDIALOG_INPUT_DEVICE_KEYBOARD ) ;
}
2023-01-22 17:01:33 +01:00
if ( input_device ! = CELL_OSKDIALOG_INPUT_DEVICE_KEYBOARD )
{
return ;
}
2023-01-21 15:42:10 +01:00
if ( m_use_separate_windows & & m_show_panel )
{
// Hide the pad input panel if the keyboard is in use during separate windows.
m_show_panel = false ;
update_panel ( ) ;
}
2023-01-24 00:25:33 +01:00
// Make sure to show the dialog and send necessary events
set_visible ( true ) ;
2023-01-24 00:30:23 +01:00
std : : lock_guard lock ( m_preview_mutex ) ;
2022-10-29 11:29:38 +02:00
const bool use_key_string_fallback = ! key . empty ( ) ;
2022-04-04 22:49:59 +02:00
2023-01-21 15:42:10 +01:00
osk . notice ( " osk_dialog::on_key_pressed(led=%d, mkey=%d, key_code=%d, out_key_code=%d, pressed=%d, use_key_string_fallback=%d) " , led , mkey , key_code , out_key_code , pressed , use_key_string_fallback ) ;
2022-10-29 11:29:38 +02:00
if ( ! use_key_string_fallback )
2022-04-04 22:49:59 +02:00
{
2022-10-29 11:29:38 +02:00
// Get keyboard layout
2022-10-29 22:35:27 +02:00
const u32 kb_mapping = static_cast < u32 > ( g_cfg . sys . keyboard_type . get ( ) ) ;
2022-10-29 11:29:38 +02:00
// Convert key to its u32string presentation
const u16 converted_out_key = cellKbCnvRawCode ( kb_mapping , mkey , led , out_key_code ) ;
std : : u16string utf16_string ;
utf16_string . push_back ( converted_out_key ) ;
key = utf16_to_u32string ( utf16_string ) ;
}
2022-04-04 22:49:59 +02:00
// Find matching key in the OSK
2022-10-29 11:29:38 +02:00
const auto find_key = [ & ] ( ) - > bool
2022-04-04 22:49:59 +02:00
{
2022-10-29 11:29:38 +02:00
for ( const cell & current_cell : m_grid )
2022-04-04 22:49:59 +02:00
{
2022-10-29 11:29:38 +02:00
for ( const auto & output : current_cell . outputs )
2022-04-04 22:49:59 +02:00
{
2022-10-29 11:29:38 +02:00
for ( const auto & str : output )
2022-04-04 22:49:59 +02:00
{
2022-10-29 11:29:38 +02:00
if ( str = = key )
2022-04-04 22:49:59 +02:00
{
2022-10-29 11:29:38 +02:00
// Apply key press
if ( current_cell . callback )
{
current_cell . callback ( str ) ;
}
else
{
on_default_callback ( str ) ;
}
return true ;
2022-04-04 22:49:59 +02:00
}
}
}
}
2022-10-29 11:29:38 +02:00
return false ;
} ;
const bool found_key = find_key ( ) ;
if ( use_key_string_fallback )
{
// We don't have a keycode, so there we can't process any of the following code anyway
return ;
2022-04-04 22:49:59 +02:00
}
// Handle special input
2022-04-25 19:17:33 +02:00
if ( ! found_key )
2022-04-04 22:49:59 +02:00
{
2022-04-25 19:17:33 +02:00
switch ( out_key_code )
2022-04-04 22:49:59 +02:00
{
2022-04-25 19:17:33 +02:00
case CELL_KEYC_SPACE :
2022-10-29 11:29:38 +02:00
on_space ( key ) ;
2022-04-19 23:36:18 +02:00
break ;
2022-04-25 19:17:33 +02:00
case CELL_KEYC_BS :
2022-10-29 11:29:38 +02:00
on_backspace ( key ) ;
2022-04-19 23:36:18 +02:00
break ;
2022-10-29 22:17:24 +02:00
case CELL_KEYC_DELETE :
on_delete ( key ) ;
break ;
2022-04-25 19:17:33 +02:00
case CELL_KEYC_ESCAPE :
Close ( CELL_OSKDIALOG_CLOSE_CANCEL ) ;
break ;
2022-10-29 22:28:21 +02:00
case CELL_KEYC_RIGHT_ARROW :
on_move_cursor ( key , edit_text : : direction : : right ) ;
break ;
case CELL_KEYC_LEFT_ARROW :
on_move_cursor ( key , edit_text : : direction : : left ) ;
break ;
case CELL_KEYC_DOWN_ARROW :
on_move_cursor ( key , edit_text : : direction : : down ) ;
break ;
case CELL_KEYC_UP_ARROW :
on_move_cursor ( key , edit_text : : direction : : up ) ;
break ;
2022-04-25 19:17:33 +02:00
case CELL_KEYC_ENTER :
if ( ( flags & CELL_OSKDIALOG_NO_RETURN ) )
{
Close ( CELL_OSKDIALOG_CLOSE_CONFIRM ) ;
}
else
{
2022-10-29 11:29:38 +02:00
on_enter ( key ) ;
2022-04-25 19:17:33 +02:00
}
2022-04-19 23:36:18 +02:00
break ;
2022-04-04 22:49:59 +02:00
default :
break ;
}
}
2022-04-19 23:36:18 +02:00
if ( on_osk_key_input_entered )
{
CellOskDialogKeyMessage key_message { } ;
key_message . led = led ;
key_message . mkey = mkey ;
key_message . keycode = key_code ;
on_osk_key_input_entered ( key_message ) ;
}
2022-04-04 22:49:59 +02:00
}
2019-01-29 17:29:55 +01:00
void osk_dialog : : on_text_changed ( )
{
2023-01-24 01:15:35 +01:00
const std : : u16string ws = u32string_to_utf16 ( m_preview . value ) ;
2023-01-24 00:13:14 +01:00
const usz length = std : : min ( osk_text . size ( ) , ws . length ( ) + 1 ) * sizeof ( char16_t ) ;
memcpy ( osk_text . data ( ) , ws . c_str ( ) , length ) ;
2019-01-29 17:29:55 +01:00
2023-01-24 01:15:35 +01:00
osk . notice ( " on_text_changed: osk_text='%s' " , utf16_to_ascii8 ( ws ) ) ;
2021-04-12 15:14:13 +02:00
// Muted contrast for placeholder text
m_preview . fore_color . a = m_preview . value . empty ( ) ? 0.5f : 1.f ;
2019-01-29 17:29:55 +01:00
m_update = true ;
}
2020-02-24 17:03:19 +01:00
void osk_dialog : : on_default_callback ( const std : : u32string & str )
2019-01-29 17:29:55 +01:00
{
2020-03-15 12:27:15 +01:00
if ( str . empty ( ) )
{
return ;
}
2019-01-29 17:29:55 +01:00
// Append to output text
2021-04-12 15:14:13 +02:00
if ( m_preview . value . empty ( ) )
2019-01-29 17:29:55 +01:00
{
2021-09-02 19:00:30 +02:00
m_preview . caret_position = str . length ( ) ;
2021-04-12 15:14:13 +02:00
m_preview . set_unicode_text ( str ) ;
2019-01-29 17:29:55 +01:00
}
else
{
2023-01-24 19:38:14 +01:00
if ( m_preview . value . length ( ) > = char_limit )
2019-01-29 17:29:55 +01:00
{
return ;
}
2023-01-24 19:38:14 +01:00
if ( ( m_preview . value . length ( ) + str . length ( ) ) < = char_limit )
2019-01-29 17:29:55 +01:00
{
2019-01-31 12:01:34 +01:00
m_preview . insert_text ( str ) ;
2019-01-29 17:29:55 +01:00
}
}
on_text_changed ( ) ;
}
2020-02-24 17:03:19 +01:00
void osk_dialog : : on_shift ( const std : : u32string & )
2019-01-29 17:29:55 +01:00
{
2020-03-14 22:03:56 +01:00
const u32 max = num_shift_layers_by_charset [ m_selected_charset ] ;
selected_z = ( selected_z + 1 ) % max ;
2020-02-25 00:53:15 +01:00
m_update = true ;
}
2020-03-14 22:03:56 +01:00
void osk_dialog : : on_layer ( const std : : u32string & )
2020-02-25 00:53:15 +01:00
{
2020-03-14 22:03:56 +01:00
const u32 num_charsets = std : : max < u32 > ( : : size32 ( num_shift_layers_by_charset ) , 1 ) ;
m_selected_charset = ( m_selected_charset + 1 ) % num_charsets ;
const u32 max_z_layer = num_shift_layers_by_charset [ m_selected_charset ] - 1 ;
if ( selected_z > max_z_layer )
{
selected_z = max_z_layer ;
}
update_controls ( ) ;
2019-01-29 17:29:55 +01:00
m_update = true ;
}
2020-02-24 17:03:19 +01:00
void osk_dialog : : on_space ( const std : : u32string & )
2019-01-29 17:29:55 +01:00
{
if ( ! ( flags & CELL_OSKDIALOG_NO_SPACE ) )
{
2020-02-24 17:03:19 +01:00
on_default_callback ( U " " ) ;
2019-01-29 17:29:55 +01:00
}
else
{
// Beep or give some other kind of visual feedback
}
}
2020-02-24 17:03:19 +01:00
void osk_dialog : : on_backspace ( const std : : u32string & )
2019-01-29 17:29:55 +01:00
{
2020-03-14 22:03:56 +01:00
m_preview . erase ( ) ;
2019-01-29 17:29:55 +01:00
on_text_changed ( ) ;
}
2022-10-29 22:17:24 +02:00
void osk_dialog : : on_delete ( const std : : u32string & )
{
m_preview . del ( ) ;
on_text_changed ( ) ;
}
2020-02-24 17:03:19 +01:00
void osk_dialog : : on_enter ( const std : : u32string & )
2019-01-29 17:29:55 +01:00
{
2019-01-31 12:01:34 +01:00
if ( ! ( flags & CELL_OSKDIALOG_NO_RETURN ) )
{
2020-02-24 17:03:19 +01:00
on_default_callback ( U " \n " ) ;
2019-01-31 12:01:34 +01:00
}
else
{
// Beep or give some other kind of visual feedback
}
2019-01-29 17:29:55 +01:00
}
2022-10-29 22:28:21 +02:00
void osk_dialog : : on_move_cursor ( const std : : u32string & , edit_text : : direction dir )
{
m_preview . move_caret ( dir ) ;
m_update = true ;
}
2021-04-09 21:12:47 +02:00
std : : u32string osk_dialog : : get_placeholder ( ) const
2020-03-14 22:03:56 +01:00
{
2020-09-02 16:20:29 +02:00
const localized_string_id id = m_password_mode
? localized_string_id : : RSX_OVERLAYS_OSK_DIALOG_ENTER_PASSWORD
: localized_string_id : : RSX_OVERLAYS_OSK_DIALOG_ENTER_TEXT ;
return get_localized_u32string ( id ) ;
2020-03-14 22:03:56 +01:00
}
2020-01-07 15:12:32 +01:00
void osk_dialog : : update ( )
{
if ( fade_animation . active )
{
fade_animation . update ( rsx : : get_current_renderer ( ) - > vblank_count ) ;
m_update = true ;
}
2023-01-19 00:39:43 +01:00
2023-01-20 22:43:24 +01:00
osk_info & info = g_fxo - > get < osk_info > ( ) ;
if ( const bool pointer_enabled = info . pointer_enabled ; pointer_enabled ! = m_pointer . visible ( ) )
2023-01-19 00:39:43 +01:00
{
2023-01-20 22:43:24 +01:00
m_pointer . set_expiration ( pointer_enabled ? u64 { umax } : 0 ) ;
2023-01-19 00:39:43 +01:00
m_pointer . update_visibility ( get_system_time ( ) ) ;
m_update = true ;
}
2023-01-20 22:43:24 +01:00
if ( m_pointer . visible ( ) & & m_pointer . set_position ( static_cast < u16 > ( info . pointer_x ) , static_cast < u16 > ( info . pointer_y ) ) )
2023-01-19 00:39:43 +01:00
{
m_update = true ;
}
2020-01-07 15:12:32 +01:00
}
2019-01-29 17:29:55 +01:00
compiled_resource osk_dialog : : get_compiled ( )
{
2020-02-24 17:30:42 +01:00
if ( ! visible )
2019-01-29 17:29:55 +01:00
{
return { } ;
}
2023-01-21 11:57:10 +01:00
if ( ! m_update )
{
fade_animation . apply ( m_cached_resource ) ;
return m_cached_resource ;
}
m_cached_resource . clear ( ) ;
m_cached_resource . add ( m_background . get_compiled ( ) ) ;
if ( m_use_separate_windows & & ! m_show_panel )
{
2023-01-24 00:30:23 +01:00
std : : lock_guard lock ( m_preview_mutex ) ;
2023-01-21 11:57:10 +01:00
m_cached_resource . add ( m_preview . get_compiled ( ) ) ;
}
else
2019-01-29 17:29:55 +01:00
{
2023-01-21 11:57:10 +01:00
m_cached_resource . add ( m_panel_frame . get_compiled ( ) ) ;
2023-01-23 20:19:30 +01:00
if ( ! m_use_separate_windows )
{
// The title is omitted in separate window mode
2023-01-24 00:30:23 +01:00
m_cached_resource . add ( m_input_frame . get_compiled ( ) ) ;
2023-01-23 20:19:30 +01:00
m_cached_resource . add ( m_title . get_compiled ( ) ) ;
}
2023-01-24 00:30:23 +01:00
{
std : : lock_guard lock ( m_preview_mutex ) ;
m_cached_resource . add ( m_preview . get_compiled ( ) ) ;
}
2019-01-29 17:29:55 +01:00
m_cached_resource . add ( m_btn_accept . get_compiled ( ) ) ;
m_cached_resource . add ( m_btn_cancel . get_compiled ( ) ) ;
m_cached_resource . add ( m_btn_shift . get_compiled ( ) ) ;
2019-01-30 10:50:29 +01:00
m_cached_resource . add ( m_btn_space . get_compiled ( ) ) ;
m_cached_resource . add ( m_btn_delete . get_compiled ( ) ) ;
2019-01-29 17:29:55 +01:00
overlay_element tmp ;
2023-01-18 22:30:00 +01:00
u16 buffered_cell_count = 0 ;
bool render_label = false ;
2019-01-29 17:29:55 +01:00
2019-01-31 12:01:34 +01:00
const color4f disabled_back_color = { 0.3f , 0.3f , 0.3f , 1.f } ;
const color4f disabled_fore_color = { 0.8f , 0.8f , 0.8f , 1.f } ;
const color4f normal_fore_color = { 0.f , 0.f , 0.f , 1.f } ;
2023-01-18 22:30:00 +01:00
label label ;
label . back_color = { 0.f , 0.f , 0.f , 0.f } ;
2023-01-18 23:17:00 +01:00
label . set_padding ( 0 , 0 , get_scaled ( 10 ) , 0 ) ;
const auto scale_font = [ this ] ( overlay_element & elem )
{
if ( const font * fnt = elem . get_font ( ) )
{
elem . set_font ( fnt - > get_name ( ) . data ( ) , get_scaled ( fnt - > get_size_pt ( ) ) ) ;
}
} ;
scale_font ( label ) ;
2019-01-29 17:29:55 +01:00
2021-03-09 20:40:14 +01:00
if ( m_reset_pulse )
{
// Reset the pulse slightly above 0 falling on each user interaction
m_key_pulse_cache . set_sinus_offset ( 0.6f ) ;
}
2019-01-29 17:29:55 +01:00
for ( const auto & c : m_grid )
{
2021-04-12 22:23:24 +02:00
u16 x = static_cast < u16 > ( c . pos . x ) ;
u16 y = static_cast < u16 > ( c . pos . y ) ;
2019-01-29 17:29:55 +01:00
u16 w = cell_size_x ;
u16 h = cell_size_y ;
if ( c . flags & border_flags : : left )
{
x + + ;
w - - ;
buffered_cell_count = 0 ;
}
if ( c . flags & border_flags : : right )
{
w - - ;
2020-02-25 00:53:15 +01:00
u32 output_count = 0 ;
2020-03-14 22:03:56 +01:00
if ( m_selected_charset < c . outputs . size ( ) )
2020-02-25 00:53:15 +01:00
{
2020-03-14 22:03:56 +01:00
output_count = : : size32 ( c . outputs [ m_selected_charset ] ) ;
2020-02-25 00:53:15 +01:00
}
if ( output_count )
2019-01-29 17:29:55 +01:00
{
2021-04-12 22:23:24 +02:00
const u16 offset_x = static_cast < u16 > ( buffered_cell_count * cell_size_x ) ;
const u16 full_width = static_cast < u16 > ( offset_x + cell_size_x ) ;
2019-01-29 17:29:55 +01:00
2023-01-18 22:30:00 +01:00
label . set_pos ( x - offset_x , y ) ;
label . set_size ( full_width , cell_size_y ) ;
label . fore_color = c . enabled ? normal_fore_color : disabled_fore_color ;
2019-01-29 17:29:55 +01:00
2020-03-14 22:03:56 +01:00
const auto _z = ( selected_z < output_count ) ? selected_z : output_count - 1u ;
2023-01-18 22:30:00 +01:00
label . set_unicode_text ( c . outputs [ m_selected_charset ] [ _z ] ) ;
label . align_text ( rsx : : overlays : : overlay_element : : text_align : : center ) ;
2019-01-29 17:29:55 +01:00
render_label = true ;
}
}
if ( c . flags & border_flags : : top )
{
y + + ;
h - - ;
}
if ( c . flags & border_flags : : bottom )
{
h - - ;
}
buffered_cell_count + + ;
2019-01-31 12:01:34 +01:00
tmp . back_color = c . enabled ? c . backcolor : disabled_back_color ;
2019-01-29 17:29:55 +01:00
tmp . set_pos ( x , y ) ;
tmp . set_size ( w , h ) ;
tmp . pulse_effect_enabled = c . selected ;
2021-03-09 20:40:14 +01:00
tmp . pulse_sinus_offset = m_key_pulse_cache . pulse_sinus_offset ;
2019-01-29 17:29:55 +01:00
m_cached_resource . add ( tmp . get_compiled ( ) ) ;
if ( render_label )
{
2023-01-18 22:30:00 +01:00
label . pulse_effect_enabled = c . selected ;
label . pulse_sinus_offset = m_key_pulse_cache . pulse_sinus_offset ;
m_cached_resource . add ( label . get_compiled ( ) ) ;
2019-01-29 17:29:55 +01:00
}
}
2023-01-19 00:39:43 +01:00
m_cached_resource . add ( m_pointer . get_compiled ( ) ) ;
2021-03-09 20:40:14 +01:00
m_reset_pulse = false ;
2019-01-29 17:29:55 +01:00
}
2023-01-21 11:57:10 +01:00
m_update = false ;
2020-01-07 15:12:32 +01:00
fade_animation . apply ( m_cached_resource ) ;
2019-01-29 17:29:55 +01:00
return m_cached_resource ;
}
2023-01-18 20:14:42 +01:00
void osk_dialog : : Create ( const osk_params & params )
2019-01-29 17:29:55 +01:00
{
state = OskDialogState : : Open ;
2023-01-18 20:14:42 +01:00
flags = params . prohibit_flags ;
char_limit = params . charlimit ;
2023-01-21 11:57:10 +01:00
m_layout = params . layout ;
m_input_layout = params . input_layout ;
m_panel_layout = params . panel_layout ;
m_input_field_window_width = params . input_field_window_width ;
2023-01-18 23:17:00 +01:00
m_scaling = params . initial_scale ;
2023-01-21 11:57:10 +01:00
m_input_frame . back_color . r = params . base_color . r ;
m_input_frame . back_color . g = params . base_color . g ;
m_input_frame . back_color . b = params . base_color . b ;
m_input_frame . back_color . a = params . base_color . a ;
m_panel_frame . back_color = m_input_frame . back_color ;
2023-01-18 20:14:42 +01:00
m_background . back_color . a = params . dimmer_enabled ? 0.8f : 0.0f ;
m_start_pad_interception = params . intercept_input ;
2023-01-21 11:57:10 +01:00
m_use_separate_windows = params . use_separate_windows ;
if ( m_use_separate_windows )
{
2023-01-21 15:42:10 +01:00
// When using separate windows, we show the text field, but hide the pad input panel if the input device is a pad.
m_show_panel = pad_input_enabled & & input_device = = CELL_OSKDIALOG_INPUT_DEVICE_PAD ;
2023-01-21 11:57:10 +01:00
m_preview . back_color . a = std : : clamp ( params . input_field_background_transparency , 0.0f , 1.0f ) ;
}
else
{
m_title . back_color . a = 0.7f ; // Uses the dimmed color of the frame background
}
2019-01-29 17:29:55 +01:00
2021-04-12 22:23:24 +02:00
const callback_t shift_cb = [ this ] ( const std : : u32string & text ) { on_shift ( text ) ; } ;
const callback_t layer_cb = [ this ] ( const std : : u32string & text ) { on_layer ( text ) ; } ;
const callback_t space_cb = [ this ] ( const std : : u32string & text ) { on_space ( text ) ; } ;
const callback_t delete_cb = [ this ] ( const std : : u32string & text ) { on_backspace ( text ) ; } ;
const callback_t enter_cb = [ this ] ( const std : : u32string & text ) { on_enter ( text ) ; } ;
2020-03-14 22:03:56 +01:00
2023-01-18 20:14:42 +01:00
const auto is_supported = [ & ] ( u32 mode ) - > bool
{
switch ( mode )
{
case CELL_OSKDIALOG_PANELMODE_POLISH :
case CELL_OSKDIALOG_PANELMODE_KOREAN :
case CELL_OSKDIALOG_PANELMODE_TURKEY :
case CELL_OSKDIALOG_PANELMODE_TRADITIONAL_CHINESE :
case CELL_OSKDIALOG_PANELMODE_SIMPLIFIED_CHINESE :
case CELL_OSKDIALOG_PANELMODE_PORTUGUESE_BRAZIL :
case CELL_OSKDIALOG_PANELMODE_DANISH :
case CELL_OSKDIALOG_PANELMODE_SWEDISH :
case CELL_OSKDIALOG_PANELMODE_NORWEGIAN :
case CELL_OSKDIALOG_PANELMODE_FINNISH :
return ( params . panel_flag & mode ) & & ( params . support_language & mode ) ;
default :
return ( params . panel_flag & mode ) ;
}
} ;
const auto has_language_support = [ & ] ( CellSysutilLang language )
{
switch ( language )
{
case CELL_SYSUTIL_LANG_KOREAN : return is_supported ( CELL_OSKDIALOG_PANELMODE_KOREAN ) ;
case CELL_SYSUTIL_LANG_FINNISH : return is_supported ( CELL_OSKDIALOG_PANELMODE_FINNISH ) ;
case CELL_SYSUTIL_LANG_SWEDISH : return is_supported ( CELL_OSKDIALOG_PANELMODE_SWEDISH ) ;
case CELL_SYSUTIL_LANG_DANISH : return is_supported ( CELL_OSKDIALOG_PANELMODE_DANISH ) ;
case CELL_SYSUTIL_LANG_NORWEGIAN : return is_supported ( CELL_OSKDIALOG_PANELMODE_NORWEGIAN ) ;
case CELL_SYSUTIL_LANG_POLISH : return is_supported ( CELL_OSKDIALOG_PANELMODE_POLISH ) ;
case CELL_SYSUTIL_LANG_PORTUGUESE_BR : return is_supported ( CELL_OSKDIALOG_PANELMODE_PORTUGUESE_BRAZIL ) ;
case CELL_SYSUTIL_LANG_TURKISH : return is_supported ( CELL_OSKDIALOG_PANELMODE_TURKEY ) ;
case CELL_SYSUTIL_LANG_CHINESE_T : return is_supported ( CELL_OSKDIALOG_PANELMODE_TRADITIONAL_CHINESE ) ;
case CELL_SYSUTIL_LANG_CHINESE_S : return is_supported ( CELL_OSKDIALOG_PANELMODE_SIMPLIFIED_CHINESE ) ;
default : return true ;
}
} ;
if ( params . panel_flag & CELL_OSKDIALOG_PANELMODE_PASSWORD )
2020-03-14 22:03:56 +01:00
{
// If password was requested, then password has to be the only osk panel mode available to the user
// first_view_panel can be ignored
add_panel ( osk_panel_password ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
m_password_mode = true ;
}
2023-01-18 20:14:42 +01:00
else if ( params . panel_flag = = CELL_OSKDIALOG_PANELMODE_DEFAULT | | params . panel_flag = = CELL_OSKDIALOG_PANELMODE_DEFAULT_NO_JAPANESE )
2020-03-14 22:03:56 +01:00
{
// Prefer the systems settings
// first_view_panel is ignored
2023-01-18 20:14:42 +01:00
CellSysutilLang language = g_cfg . sys . language ;
// Fall back to english if the panel is not supported
if ( ! has_language_support ( language ) )
{
language = CELL_SYSUTIL_LANG_ENGLISH_US ;
}
2020-03-14 22:03:56 +01:00
switch ( g_cfg . sys . language )
{
case CELL_SYSUTIL_LANG_JAPANESE :
2023-01-18 20:14:42 +01:00
if ( params . panel_flag = = CELL_OSKDIALOG_PANELMODE_DEFAULT_NO_JAPANESE )
2020-03-14 22:03:56 +01:00
add_panel ( osk_panel_english ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
else
add_panel ( osk_panel_japanese ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
break ;
case CELL_SYSUTIL_LANG_FRENCH :
2020-03-24 15:57:58 +01:00
add_panel ( osk_panel_french ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
break ;
2020-03-14 22:03:56 +01:00
case CELL_SYSUTIL_LANG_SPANISH :
2020-03-24 15:57:58 +01:00
add_panel ( osk_panel_spanish ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
break ;
2020-03-14 22:03:56 +01:00
case CELL_SYSUTIL_LANG_GERMAN :
2020-03-24 15:57:58 +01:00
add_panel ( osk_panel_german ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
break ;
2020-03-14 22:03:56 +01:00
case CELL_SYSUTIL_LANG_ITALIAN :
2020-03-24 15:57:58 +01:00
add_panel ( osk_panel_italian ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
break ;
case CELL_SYSUTIL_LANG_DANISH :
add_panel ( osk_panel_danish ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
break ;
case CELL_SYSUTIL_LANG_NORWEGIAN :
add_panel ( osk_panel_norwegian ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
break ;
2020-03-14 22:03:56 +01:00
case CELL_SYSUTIL_LANG_DUTCH :
2020-03-24 15:57:58 +01:00
add_panel ( osk_panel_dutch ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
break ;
2020-03-14 22:03:56 +01:00
case CELL_SYSUTIL_LANG_FINNISH :
2020-03-24 15:57:58 +01:00
add_panel ( osk_panel_finnish ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
break ;
2020-03-14 22:03:56 +01:00
case CELL_SYSUTIL_LANG_SWEDISH :
2020-03-24 15:57:58 +01:00
add_panel ( osk_panel_swedish ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
break ;
case CELL_SYSUTIL_LANG_PORTUGUESE_PT :
add_panel ( osk_panel_portuguese_pt ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
break ;
2020-03-14 22:03:56 +01:00
case CELL_SYSUTIL_LANG_PORTUGUESE_BR :
2020-03-24 15:57:58 +01:00
add_panel ( osk_panel_portuguese_br ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
break ;
case CELL_SYSUTIL_LANG_TURKISH :
add_panel ( osk_panel_turkey ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
break ;
case CELL_SYSUTIL_LANG_POLISH :
add_panel ( osk_panel_polish ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
break ;
case CELL_SYSUTIL_LANG_RUSSIAN :
add_panel ( osk_panel_russian ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
break ;
case CELL_SYSUTIL_LANG_KOREAN :
add_panel ( osk_panel_korean ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
break ;
case CELL_SYSUTIL_LANG_CHINESE_T :
add_panel ( osk_panel_traditional_chinese ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
break ;
case CELL_SYSUTIL_LANG_CHINESE_S :
add_panel ( osk_panel_simplified_chinese ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
break ;
2020-03-14 22:03:56 +01:00
case CELL_SYSUTIL_LANG_ENGLISH_US :
case CELL_SYSUTIL_LANG_ENGLISH_GB :
default :
add_panel ( osk_panel_english ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
break ;
}
}
else
{
// Append osk modes.
// TODO: find out the exact order
2019-01-29 17:29:55 +01:00
2023-01-18 20:14:42 +01:00
if ( is_supported ( CELL_OSKDIALOG_PANELMODE_LATIN ) )
2020-03-24 15:57:58 +01:00
{
add_panel ( osk_panel_latin ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
}
2023-01-18 20:14:42 +01:00
if ( is_supported ( CELL_OSKDIALOG_PANELMODE_ENGLISH ) )
2020-03-14 22:03:56 +01:00
{
add_panel ( osk_panel_english ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
}
2023-01-18 20:14:42 +01:00
if ( is_supported ( CELL_OSKDIALOG_PANELMODE_FRENCH ) )
2020-03-24 15:57:58 +01:00
{
add_panel ( osk_panel_french ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
}
2023-01-18 20:14:42 +01:00
if ( is_supported ( CELL_OSKDIALOG_PANELMODE_SPANISH ) )
2020-03-24 15:57:58 +01:00
{
add_panel ( osk_panel_spanish ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
}
2023-01-18 20:14:42 +01:00
if ( is_supported ( CELL_OSKDIALOG_PANELMODE_ITALIAN ) )
2020-03-24 15:57:58 +01:00
{
add_panel ( osk_panel_italian ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
}
2023-01-18 20:14:42 +01:00
if ( is_supported ( CELL_OSKDIALOG_PANELMODE_GERMAN ) )
2020-03-24 15:57:58 +01:00
{
add_panel ( osk_panel_german ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
}
2023-01-18 20:14:42 +01:00
if ( is_supported ( CELL_OSKDIALOG_PANELMODE_TURKEY ) )
2020-03-24 15:57:58 +01:00
{
add_panel ( osk_panel_turkey ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
}
2023-01-18 20:14:42 +01:00
if ( is_supported ( CELL_OSKDIALOG_PANELMODE_POLISH ) )
2020-03-24 15:57:58 +01:00
{
add_panel ( osk_panel_polish ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
}
2023-01-18 20:14:42 +01:00
if ( is_supported ( CELL_OSKDIALOG_PANELMODE_RUSSIAN ) )
2020-03-24 15:57:58 +01:00
{
add_panel ( osk_panel_russian ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
}
2023-01-18 20:14:42 +01:00
if ( is_supported ( CELL_OSKDIALOG_PANELMODE_DANISH ) )
2020-03-24 15:57:58 +01:00
{
add_panel ( osk_panel_danish ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
}
2023-01-18 20:14:42 +01:00
if ( is_supported ( CELL_OSKDIALOG_PANELMODE_NORWEGIAN ) )
2020-03-24 15:57:58 +01:00
{
add_panel ( osk_panel_norwegian ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
}
2023-01-18 20:14:42 +01:00
if ( is_supported ( CELL_OSKDIALOG_PANELMODE_DUTCH ) )
2020-03-24 15:57:58 +01:00
{
add_panel ( osk_panel_dutch ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
}
2023-01-18 20:14:42 +01:00
if ( is_supported ( CELL_OSKDIALOG_PANELMODE_SWEDISH ) )
2020-03-24 15:57:58 +01:00
{
add_panel ( osk_panel_swedish ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
}
2023-01-18 20:14:42 +01:00
if ( is_supported ( CELL_OSKDIALOG_PANELMODE_FINNISH ) )
2020-03-24 15:57:58 +01:00
{
add_panel ( osk_panel_finnish ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
}
2023-01-18 20:14:42 +01:00
if ( is_supported ( CELL_OSKDIALOG_PANELMODE_PORTUGUESE ) )
2020-03-24 15:57:58 +01:00
{
add_panel ( osk_panel_portuguese_pt ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
}
2023-01-18 20:14:42 +01:00
if ( is_supported ( CELL_OSKDIALOG_PANELMODE_PORTUGUESE_BRAZIL ) )
2020-03-24 15:57:58 +01:00
{
add_panel ( osk_panel_portuguese_br ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
}
2023-01-18 20:14:42 +01:00
if ( is_supported ( CELL_OSKDIALOG_PANELMODE_KOREAN ) )
2020-03-24 15:57:58 +01:00
{
add_panel ( osk_panel_korean ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
}
2023-01-18 20:14:42 +01:00
if ( is_supported ( CELL_OSKDIALOG_PANELMODE_TRADITIONAL_CHINESE ) )
2020-03-24 15:57:58 +01:00
{
add_panel ( osk_panel_traditional_chinese ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
}
2023-01-18 20:14:42 +01:00
if ( is_supported ( CELL_OSKDIALOG_PANELMODE_SIMPLIFIED_CHINESE ) )
2020-03-24 15:57:58 +01:00
{
add_panel ( osk_panel_simplified_chinese ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
}
2023-01-18 20:14:42 +01:00
if ( is_supported ( CELL_OSKDIALOG_PANELMODE_JAPANESE ) )
2020-03-14 22:03:56 +01:00
{
add_panel ( osk_panel_japanese ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
}
2023-01-18 20:14:42 +01:00
if ( is_supported ( CELL_OSKDIALOG_PANELMODE_JAPANESE_HIRAGANA ) )
2020-03-14 22:03:56 +01:00
{
add_panel ( osk_panel_japanese_hiragana ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
}
2023-01-18 20:14:42 +01:00
if ( is_supported ( CELL_OSKDIALOG_PANELMODE_JAPANESE_KATAKANA ) )
2020-03-14 22:03:56 +01:00
{
add_panel ( osk_panel_japanese_katakana ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
}
2023-01-18 20:14:42 +01:00
if ( is_supported ( CELL_OSKDIALOG_PANELMODE_ALPHABET ) )
2020-03-14 22:03:56 +01:00
{
add_panel ( osk_panel_alphabet_half_width ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
}
2023-01-18 20:14:42 +01:00
if ( is_supported ( CELL_OSKDIALOG_PANELMODE_ALPHABET_FULL_WIDTH ) )
2020-03-14 22:03:56 +01:00
{
add_panel ( osk_panel_alphabet_full_width ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
}
2023-01-18 20:14:42 +01:00
if ( is_supported ( CELL_OSKDIALOG_PANELMODE_NUMERAL ) )
2020-03-14 22:03:56 +01:00
{
add_panel ( osk_panel_numeral_half_width ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
}
2023-01-18 20:14:42 +01:00
if ( is_supported ( CELL_OSKDIALOG_PANELMODE_NUMERAL_FULL_WIDTH ) )
2020-03-14 22:03:56 +01:00
{
add_panel ( osk_panel_numeral_full_width ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
}
2023-01-18 20:14:42 +01:00
if ( is_supported ( CELL_OSKDIALOG_PANELMODE_URL ) )
2020-03-14 22:03:56 +01:00
{
add_panel ( osk_panel_url ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
}
// Get initial panel based on first_view_panel
2020-12-18 08:39:54 +01:00
for ( usz i = 0 ; i < m_panels . size ( ) ; + + i )
2020-03-14 22:03:56 +01:00
{
2023-01-18 20:14:42 +01:00
if ( params . first_view_panel = = m_panels [ i ] . osk_panel_mode )
2020-03-14 22:03:56 +01:00
{
m_panel_index = i ;
break ;
}
}
}
// Fallback to english in case we forgot something
if ( m_panels . empty ( ) )
{
osk . error ( " No OSK panel found. Using english panel. " ) ;
add_panel ( osk_panel_english ( shift_cb , layer_cb , space_cb , delete_cb , enter_cb ) ) ;
}
2023-01-18 20:14:42 +01:00
initialize_layout ( utf16_to_u32string ( params . message ) , utf16_to_u32string ( params . init_text ) ) ;
2020-03-14 22:03:56 +01:00
update_panel ( ) ;
2021-09-09 21:23:04 +02:00
const auto notify = std : : make_shared < atomic_t < bool > > ( false ) ;
2023-02-13 19:57:38 +01:00
auto & overlayman = g_fxo - > get < display_manager > ( ) ;
2021-09-09 21:23:04 +02:00
2023-02-13 19:57:38 +01:00
overlayman . attach_thread_input (
2023-02-14 00:41:26 +01:00
uid , " OSK " ,
2023-02-27 13:07:35 +01:00
[ notify ] ( ) { * notify = true ; notify - > notify_one ( ) ; }
2023-02-13 19:57:38 +01:00
) ;
2020-03-14 22:03:56 +01:00
2023-02-13 19:57:38 +01:00
while ( ! Emu . IsStopped ( ) & & ! * notify )
2021-09-09 21:23:04 +02:00
{
notify - > wait ( false , atomic_wait_timeout { 1'000'000 } ) ;
}
2019-01-29 17:29:55 +01:00
}
}
}