//! Demonstrates IME (Input Method Editor) support for text input. //! //! IME allows users to input characters that aren't directly on their keyboard, //! such as Chinese, Japanese, and Korean characters. //! //! To use IME input, the system must have fonts installed that support the target script. //! This example uses [`FontSource::SansSerif`], which resolves to a system sans-serif font. //! On systems without e.g. CJK fonts installed, CJK input will render as boxes or question marks. use bevy::color::palettes::css::DARK_GREY; use bevy::color::palettes::tailwind::SLATE_300; use bevy::input_focus::{ tab_navigation::{TabGroup, TabIndex, TabNavigationPlugin}, InputFocus, }; use bevy::prelude::*; use bevy::text::{EditableText, TextCursorStyle}; use bevy::ui_widgets::TextInput; fn main() { App::new() .add_plugins(DefaultPlugins) .add_plugins(TabNavigationPlugin) .add_systems(Startup, setup) .add_systems(Update, text_submission) .run(); } #[derive(Component)] struct TextOutput; fn setup(mut commands: Commands) { commands.spawn(Camera2d); let instructions = commands .spawn(( Text::new("Type using your IME, then press Ctrl+Enter to submit. Your system default sans-serif font will be used, so make sure you have fonts installed that support the characters you want to input!"), TextFont { font_size: FontSize::Px(20.0), ..default() }, )) .id(); let text_input = commands .spawn(( Node { width: px(400), height: px(250), border: px(3).all(), padding: px(8).all(), ..default() }, // SansSerif resolves to a system sans-serif font, which on most CJK systems // includes support for Chinese, Japanese, and Korean characters. // Note that using system fonts requires the "bevy/system-fonts" feature to be enabled. TextFont { font: FontSource::sans_serif(), font_size: FontSize::Px(32.0), ..default() }, BorderColor::from(Color::from(SLATE_300)), TextInput, EditableText { allow_newlines: true, ..default() }, TextLayout::no_wrap(), TextCursorStyle::default(), TabIndex(0), BackgroundColor(DARK_GREY.into()), )) .id(); let text_output = commands .spawn(( Text::new("Your text here!"), TextFont { font: FontSource::sans_serif(), font_size: FontSize::Px(32.0), ..default() }, TextOutput, )) .id(); commands .spawn(( Node { flex_direction: FlexDirection::Column, padding: px(24.0).all(), row_gap: px(16), ..default() }, TabGroup::new(0), )) .add_children(&[instructions, text_input, text_output]); } fn text_submission( input_focus: Res, keyboard_input: Res>, mut text_input: Query<&mut EditableText>, mut text_output: Single<&mut Text, With>, ) { if keyboard_input.just_pressed(KeyCode::Enter) && (keyboard_input.pressed(KeyCode::ControlLeft) || keyboard_input.pressed(KeyCode::ControlRight)) && let Some(focused_entity) = input_focus.get() && let Ok(mut input) = text_input.get_mut(focused_entity) { text_output.0 = input.value().to_string(); input.clear(); } }