diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown index 704c6ef..a16bd3a 100644 --- a/CHANGELOG.markdown +++ b/CHANGELOG.markdown @@ -26,6 +26,10 @@ - Upgrade to [Dear ImGui v1.81](https://github.com/ocornut/imgui/releases/tag/v1.81) - BREAKING: `imgui::ListBox::calculate_size(items_count: ..., height_in_items: ...)` has been removed as the function backing it has been marked as obsolete. The recommended approach is to calculate the size yourself and use `.size(...)` (or use the default auto-calculated size) +- Restored methods to access keyboard based on backend-defined keyboard map indexes. These allow access to most keys, not just those defined in the small subset of `imgui::Keys` (note the available keys may be expanded in future by [imgui PR #2625](https://github.com/ocornut/imgui/pull/2625)) + - The new methods on `imgui::Ui` are `is_key_index_down`, `is_key_index_pressed`, `is_key_index_pressed_no_repeat`, `is_key_index_released`, `is_key_index_released` + - For example `ui.is_key_released(imgui::Key::A)` is same as `ui.is_key_index_released(winit::events::VirtualKeyCode::A as i32)` when using the winit backend + ## [0.7.0] - 2021-02-04 - Upgrade to [Dear ImGui v1.80](https://github.com/ocornut/imgui/releases/tag/v1.80). (Note that the new table functionality is not yet supported, however) diff --git a/imgui-examples/examples/keyboard.rs b/imgui-examples/examples/keyboard.rs new file mode 100644 index 0000000..d857ce7 --- /dev/null +++ b/imgui-examples/examples/keyboard.rs @@ -0,0 +1,141 @@ +use imgui::*; + +mod support; + +fn main() { + let system = support::init(file!()); + let mut press_counter = 0u32; + let mut press_no_repeat_counter = 0u32; + let mut release_counter = 0u32; + let mut ctrl_a_counter = 0u32; + let mut uncaptured_counter = 0u32; + let mut home_counter = 0u32; + let mut f1_release_count = 0u32; + let mut text_buffer = ImString::new(""); + + system.main_loop(move |_, ui| { + Window::new(im_str!("Means of accessing key state")) + .size([500.0, 300.0], Condition::FirstUseEver) + .build(ui, || { + // You can check if a key is currently held down + if ui.is_key_down(Key::A) { + ui.text("The A key is down!"); + } else { + ui.text("The A key is not down"); + } + + // You can also check if the key has been pressed + // down, which is true for one frame. This has "key + // repeat" so will be true again based on the repeat + // delay and rate. + if ui.is_key_pressed(Key::A) { + press_counter += 1; + } + ui.text(format!( + "The A key has been pressed {} times", + press_counter + )); + + // You can also check if the key has been pressed + // down, which is true for one frame. This has "key + // repeat" so will be true again based on the repeat + // delay and rate. + if ui.is_key_pressed_no_repeat(Key::A) { + press_no_repeat_counter += 1; + } + ui.text(format!( + "The A key has been pressed {} times (ignoring key repeat)", + press_no_repeat_counter + )); + + // Note due to the key-repeat behaviour that the key + // may be pressed more often than it is released. + if ui.is_key_released(Key::A) { + release_counter += 1; + } + ui.text(format!( + "The A key has been released {} times", + release_counter + )); + + // Modifiers are accessed via bools on the `imgui::Io` + // struct, + if ui.io().key_ctrl { + ui.text("Ctrl is down!"); + } else { + ui.text("Ctrl is up!"); + } + + // Using modifiers in conjunction with key press + // events is simple: + if ui.io().key_ctrl && ui.is_key_released(Key::A) { + ctrl_a_counter += 1; + } + ui.text(format!( + "The Ctrl+A key has been released {} times", + ctrl_a_counter + )); + + // Note that `is_key_released` gives the state of the + // key regardless of what widget has focus, for + // example, if you try to type into this input, the + // above interaction still counts the key presses. + ui.input_text(im_str!("##Dummy text input widget"), &mut text_buffer) + .resize_buffer(true) // Auto-resize ImString as required + .hint(im_str!("Example text input")) + .build(); + + // If you want to check if a widget is capturing + // keyboard input, you can check + // `Io::want_capture_keyboard` + if !ui.io().want_capture_keyboard && ui.is_key_pressed(Key::A) { + uncaptured_counter += 1; + } + ui.text(format!( + "There has been {} uncaptured A key presses", + uncaptured_counter + )); + + // These examples all use `Key::A`. The `imgui::Key` + // enum only contains the few keys which imgui + // internally uses (such as for the `Ctrl + A` select + // all shortcut). This may expand in future versions + // of imgui, but will likely never contain every + // possible key + // + // Instead we can use keys using an index, the meaning + // of which is defined by the implementation of "IO" + // backend. + // + // For example, in the `WinitPlatform` backend each + // key is indexed by it's integer value of + // `winit::VirtualKeyCode`. So we can query if a key + // is down based on it's virtual key code, + + let home_key_idx = 65; // Hardcoded for imgui-examples only, instead use `winit::event::VirtualKeyCode::Home` + if ui.io().keys_down[home_key_idx as usize] { + home_counter += 1; + } + ui.text(format!("Home has been pressed for {} frames", home_counter)); + // It is important to remember that unlike using + // `imgui::Key`, there is nothing enforcing the index + // is the key you expect. For example if you hardcode + // your key ID's and switch backends, you may be + // querying different keys! + if ui.io().keys_down[123] { + // A mystery key is down! + } + + // It is also possible to use the `is_key_...` methods + // with arbitrary key indexes. For example, to check + // if the F1 key is been pressed + + if ui.is_key_index_released(37) { + // Index is hardcoded for imgui-examples only, instead do this: + //if ui.is_key_index_released(winit::event::VirtualKeyCode::F1 as i32) { + f1_release_count += 1; + } + ui.text(format!("F1 has been released {} times", f1_release_count)); + }); + }); +} diff --git a/imgui/src/input/keyboard.rs b/imgui/src/input/keyboard.rs index c58ff5e..204e435 100644 --- a/imgui/src/input/keyboard.rs +++ b/imgui/src/input/keyboard.rs @@ -107,6 +107,14 @@ impl<'ui> Ui<'ui> { #[doc(alias = "IsKeyDown")] pub fn is_key_down(&self, key: Key) -> bool { let key_index = self.key_index(key); + self.is_key_index_down(key_index) + } + + /// Same as [`is_key_down`] but takes a key index. The meaning of + /// index is defined by your backend implementation. + #[inline] + #[doc(alias = "IsKeyDown")] + pub fn is_key_index_down(&self, key_index: i32) -> bool { unsafe { sys::igIsKeyDown(key_index) } } @@ -117,6 +125,16 @@ impl<'ui> Ui<'ui> { #[doc(alias = "IsKeyPressed")] pub fn is_key_pressed(&self, key: Key) -> bool { let key_index = self.key_index(key); + self.is_key_index_pressed(key_index) + } + + /// Same as [`is_key_pressed`] but takes a key index. + /// + /// The meaning of index is defined by your backend + /// implementation. + #[inline] + #[doc(alias = "IsKeyPressed")] + pub fn is_key_index_pressed(&self, key_index: i32) -> bool { unsafe { sys::igIsKeyPressed(key_index, true) } } @@ -124,8 +142,19 @@ impl<'ui> Ui<'ui> { /// /// Is **not** affected by key repeat settings (`io.key_repeat_delay`, `io.key_repeat_rate`) #[inline] + #[doc(alias = "IsKeyPressed")] pub fn is_key_pressed_no_repeat(&self, key: Key) -> bool { let key_index = self.key_index(key); + self.is_key_index_pressed_no_repeat(key_index) + } + + /// Same as [`is_key_pressed_no_repeat`] but takes a key index. + /// + /// The meaning of index is defined by your backend + /// implementation. + #[inline] + #[doc(alias = "IsKeyPressed")] + pub fn is_key_index_pressed_no_repeat(&self, key_index: i32) -> bool { unsafe { sys::igIsKeyPressed(key_index, false) } } @@ -134,6 +163,16 @@ impl<'ui> Ui<'ui> { #[doc(alias = "IsKeyReleased")] pub fn is_key_released(&self, key: Key) -> bool { let key_index = self.key_index(key); + self.is_key_index_released(key_index) + } + + /// Same as [`is_key_released`] but takes a key index. + /// + /// The meaning of index is defined by your backend + /// implementation. + #[inline] + #[doc(alias = "IsKeyReleased")] + pub fn is_key_index_released(&self, key_index: i32) -> bool { unsafe { sys::igIsKeyReleased(key_index) } } @@ -145,6 +184,12 @@ impl<'ui> Ui<'ui> { #[doc(alias = "GetKeyPressedAmount")] pub fn key_pressed_amount(&self, key: Key, repeat_delay: f32, rate: f32) -> u32 { let key_index = self.key_index(key); + self.key_index_pressed_amount(key_index, repeat_delay, rate) + } + + #[inline] + #[doc(alias = "GetKeyPressedAmount")] + pub fn key_index_pressed_amount(&self, key_index: i32, repeat_delay: f32, rate: f32) -> u32 { unsafe { sys::igGetKeyPressedAmount(key_index, repeat_delay, rate) as u32 } }