Skip to main content

ime_support/
ime_support.rs

1//! Demonstrates IME (Input Method Editor) support for text input.
2//!
3//! IME allows users to input characters that aren't directly on their keyboard,
4//! such as Chinese, Japanese, and Korean characters.
5//!
6//! To use IME input, the system must have fonts installed that support the target script.
7//! This example uses [`FontSource::SansSerif`], which resolves to a system sans-serif font.
8//! On systems without e.g. CJK fonts installed, CJK input will render as boxes or question marks.
9use bevy::color::palettes::css::DARK_GREY;
10use bevy::color::palettes::tailwind::SLATE_300;
11use bevy::input_focus::{
12    tab_navigation::{TabGroup, TabIndex, TabNavigationPlugin},
13    InputFocus,
14};
15use bevy::prelude::*;
16use bevy::text::{EditableText, TextCursorStyle};
17
18fn main() {
19    App::new()
20        .add_plugins(DefaultPlugins)
21        .add_plugins(TabNavigationPlugin)
22        .add_systems(Startup, setup)
23        .add_systems(Update, text_submission)
24        .run();
25}
26
27#[derive(Component)]
28struct TextOutput;
29
30fn setup(mut commands: Commands) {
31    commands.spawn(Camera2d);
32
33    let instructions = commands
34        .spawn((
35            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!"),
36            TextFont {
37                font_size: FontSize::Px(20.0),
38                ..default()
39            },
40        ))
41        .id();
42
43    let text_input = commands
44        .spawn((
45            Node {
46                width: px(400),
47                height: px(250),
48                border: px(3).all(),
49                padding: px(8).all(),
50                ..default()
51            },
52            // SansSerif resolves to a system sans-serif font, which on most CJK systems
53            // includes support for Chinese, Japanese, and Korean characters.
54            // Note that using system fonts requires the "bevy/system-fonts" feature to be enabled.
55            TextFont {
56                font: FontSource::SansSerif,
57                font_size: FontSize::Px(32.0),
58                ..default()
59            },
60            BorderColor::from(Color::from(SLATE_300)),
61            EditableText {
62                allow_newlines: true,
63                ..default()
64            },
65            TextLayout::no_wrap(),
66            TextCursorStyle::default(),
67            TabIndex(0),
68            BackgroundColor(DARK_GREY.into()),
69        ))
70        .id();
71
72    let text_output = commands
73        .spawn((
74            Text::new("Your text here!"),
75            TextFont {
76                font: FontSource::SansSerif,
77                font_size: FontSize::Px(32.0),
78                ..default()
79            },
80            TextOutput,
81        ))
82        .id();
83
84    commands
85        .spawn((
86            Node {
87                flex_direction: FlexDirection::Column,
88                padding: px(24.0).all(),
89                row_gap: px(16),
90                ..default()
91            },
92            TabGroup::new(0),
93        ))
94        .add_children(&[instructions, text_input, text_output]);
95}
96
97fn text_submission(
98    input_focus: Res<InputFocus>,
99    keyboard_input: Res<ButtonInput<KeyCode>>,
100    mut text_input: Query<&mut EditableText>,
101    mut text_output: Single<&mut Text, With<TextOutput>>,
102) {
103    if keyboard_input.just_pressed(KeyCode::Enter)
104        && (keyboard_input.pressed(KeyCode::ControlLeft)
105            || keyboard_input.pressed(KeyCode::ControlRight))
106        && let Some(focused_entity) = input_focus.get()
107        && let Ok(mut input) = text_input.get_mut(focused_entity)
108    {
109        text_output.0 = input.value().to_string();
110        input.clear();
111    }
112}