Split ImGuiKey_MouseWheelX into two keys for Plus and Minus #9583

Open
opened 2026-10-14 16:46:05 +00:00 by Pix3lP3rf3ct · 4 comments
Pix3lP3rf3ct commented 2026-10-14 16:46:05 +00:00 (Migrated from github.com)

Version/Branch of Dear ImGui:

1.93.0 WIP (19297) Docking

Back-ends:

Custom

Compiler, OS:

clang_version=17.0.0 (clang-1700.6.3.2)

Full config/build information:

// (Copy from the next line. Keep the ``` markers for formatting.)

Dear ImGui 1.93.0 WIP (19297)
--------------------------------
sizeof(size_t): 8, sizeof(ImDrawIdx): 2, sizeof(ImDrawVert): 20
define: __cplusplus=202002
define: IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
define: IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
define: IMGUI_DISABLE_FILE_FUNCTIONS
define: IMGUI_DISABLE_DEFAULT_ALLOCATORS
define: __APPLE__
define: __GNUC__=4
define: __clang_version__=17.0.0 (clang-1700.6.3.2)
define: IMGUI_HAS_VIEWPORT
define: IMGUI_HAS_DOCK
IM_ASSERT: runs expression: OK. expand size: OK
--------------------------------
io.BackendPlatformName: NULL
io.BackendRendererName: imgui_impl_TGCEngine
io.ConfigFlags: 0x00000081
 NavEnableKeyboard
 DockingEnable
io.ConfigViewportsNoDecoration
io.ConfigViewportsNoDefaultParent
io.ConfigMacOSXBehaviors
io.ConfigNavCaptureKeyboard
io.ConfigInputTextCursorBlink
io.ConfigWindowsResizeFromEdges
io.ConfigWindowsMoveFromTitleBarOnly
io.ConfigMemoryCompactTimer = 60.0
io.BackendFlags: 0x00000C18
 PlatformHasViewports
 RendererHasVtxOffset
 RendererHasTextures
 RendererHasViewports
--------------------------------
io.Fonts: 1 fonts, Flags: 0x00000000, TexSize: 512,512
io.Fonts->FontLoaderName: stb_truetype
io.DisplaySize: 2759.00,1577.00
io.DisplayFramebufferScale: 2.00,2.00
--------------------------------
style.WindowPadding: 8.00,8.00
style.WindowBorderSize: 1.00
style.FramePadding: 6.00,6.00
style.FrameRounding: 4.00
style.FrameBorderSize: 1.00
style.ItemSpacing: 6.00,6.00
style.ItemInnerSpacing: 4.00,4.00

Details:

We have a command system where commands will execute some code. It's a typical CanExecute() Execute() class. A command is hooked up to an Action which holds an ImGuiKeyChord. When the shortcut is pressed we call the Execute function. I want to create a keyChord using the mouse wheel Control+MouseWheel+ to "SelectParentEntities" and Control+MouseWheel- to "UndoSelectParents".

The issue is that we can't properly map those actions without writing special code. Is there any way we can treat the scroll direction as a key press?

I assume this is somewhat easy on windows. On a mac with a trackpad it might be hard as there is so much resolution.

### Version/Branch of Dear ImGui: 1.93.0 WIP (19297) Docking ### Back-ends: Custom ### Compiler, OS: __clang_version__=17.0.0 (clang-1700.6.3.2) ### Full config/build information: // (Copy from the next line. Keep the ``` markers for formatting.) ```cpp Dear ImGui 1.93.0 WIP (19297) -------------------------------- sizeof(size_t): 8, sizeof(ImDrawIdx): 2, sizeof(ImDrawVert): 20 define: __cplusplus=202002 define: IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS define: IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS define: IMGUI_DISABLE_FILE_FUNCTIONS define: IMGUI_DISABLE_DEFAULT_ALLOCATORS define: __APPLE__ define: __GNUC__=4 define: __clang_version__=17.0.0 (clang-1700.6.3.2) define: IMGUI_HAS_VIEWPORT define: IMGUI_HAS_DOCK IM_ASSERT: runs expression: OK. expand size: OK -------------------------------- io.BackendPlatformName: NULL io.BackendRendererName: imgui_impl_TGCEngine io.ConfigFlags: 0x00000081 NavEnableKeyboard DockingEnable io.ConfigViewportsNoDecoration io.ConfigViewportsNoDefaultParent io.ConfigMacOSXBehaviors io.ConfigNavCaptureKeyboard io.ConfigInputTextCursorBlink io.ConfigWindowsResizeFromEdges io.ConfigWindowsMoveFromTitleBarOnly io.ConfigMemoryCompactTimer = 60.0 io.BackendFlags: 0x00000C18 PlatformHasViewports RendererHasVtxOffset RendererHasTextures RendererHasViewports -------------------------------- io.Fonts: 1 fonts, Flags: 0x00000000, TexSize: 512,512 io.Fonts->FontLoaderName: stb_truetype io.DisplaySize: 2759.00,1577.00 io.DisplayFramebufferScale: 2.00,2.00 -------------------------------- style.WindowPadding: 8.00,8.00 style.WindowBorderSize: 1.00 style.FramePadding: 6.00,6.00 style.FrameRounding: 4.00 style.FrameBorderSize: 1.00 style.ItemSpacing: 6.00,6.00 style.ItemInnerSpacing: 4.00,4.00 ``` ### Details: We have a command system where commands will execute some code. It's a typical CanExecute() Execute() class. A command is hooked up to an Action which holds an ImGuiKeyChord. When the shortcut is pressed we call the Execute function. I want to create a keyChord using the mouse wheel `Control+MouseWheel+` to "SelectParentEntities" and `Control+MouseWheel-` to "UndoSelectParents". The issue is that we can't properly map those actions without writing special code. Is there any way we can treat the scroll direction as a key press? I assume this is somewhat easy on windows. On a mac with a trackpad it might be hard as there is so much resolution.
ocornut commented 2026-10-14 16:55:20 +00:00 (Migrated from github.com)

FYI using GetKeyData(ImGuiKey_MouseWheelX)->AnalogValue you can access the value/sign information already.
Could your code/interface to map actions read the sign of this when mapping selected keys, and check it when polling after e..g the Shortcut() call.
Or does that count as the writing special code you would want to avoid?

FYI using `GetKeyData(ImGuiKey_MouseWheelX)->AnalogValue` you can access the value/sign information already. Could your code/interface to map actions read the sign of this when mapping selected keys, and check it when polling after e..g the `Shortcut()` call. Or does that count as the writing special code you would want to avoid?
Pix3lP3rf3ct commented 2026-10-14 17:11:08 +00:00 (Migrated from github.com)

Kind of. Here is some of the code so you that have more context on the systems we have.

Here is how we register actions. This registration allows the user to change the keybindings associated with this action. Actions can have two shortcuts similar to VSCode.

	inline EditorAction SelectParents( 
		ActionEditCategory, "Select Parents", ICON_FA_CIRCLE_ARROW_UP,
		ImGuiMod_Ctrl | ImGuiKey_UpArrow,
		ImGuiMod_Ctrl | ImGuiKey_MouseWheelY_Positive );                            // <-- what I'm trying to do

	inline EditorAction UndoSelectParents(
		ActionEditCategory, "Undo Select Parents", ICON_FA_ROTATE_LEFT,
		ImGuiMod_Ctrl | ImGuiKey_DownArrow,
		ImGuiMod_Ctrl | ImGuiKey_MouseWheelY_Negative );                            // <-- what I'm trying to do

Here is how we create our Commands

		m_commands.Create< DelegateCommand >( 
			Actions::SelectParents,
			[ this ](){ SelectParentEntities(); } );

		m_commands.Create< DelegateCommand >( 
			Actions::UndoSelectParents,
			[ this ](){ UndoSelectParentEntities(); } );

These commands are added to a CommandList. The command list is executed at a very specific place in the UI where these should execute.

m_commands.ProcessShortcuts();

For each command in the CommandList we run this code:

bool ActionShortcut( const EditorAction& action, bool canExecute )
{
	if( action.PrimaryKeyChord != ImGuiKey_None )
	{
		if( ImGui::Shortcut( action.PrimaryKeyChord, ImGuiInputFlags_Repeat ) && canExecute )
			return true;
	}

	if( action.SecondaryKeyChord != ImGuiKey_None )
	{
		if( ImGui::Shortcut( action.SecondaryKeyChord, ImGuiInputFlags_Repeat ) && canExecute )
			return true;
	}

	return false;
}
Kind of. Here is some of the code so you that have more context on the systems we have. Here is how we register actions. This registration allows the user to change the keybindings associated with this action. Actions can have two shortcuts similar to VSCode. ``` inline EditorAction SelectParents( ActionEditCategory, "Select Parents", ICON_FA_CIRCLE_ARROW_UP, ImGuiMod_Ctrl | ImGuiKey_UpArrow, ImGuiMod_Ctrl | ImGuiKey_MouseWheelY_Positive ); // <-- what I'm trying to do inline EditorAction UndoSelectParents( ActionEditCategory, "Undo Select Parents", ICON_FA_ROTATE_LEFT, ImGuiMod_Ctrl | ImGuiKey_DownArrow, ImGuiMod_Ctrl | ImGuiKey_MouseWheelY_Negative ); // <-- what I'm trying to do ``` Here is how we create our Commands ``` m_commands.Create< DelegateCommand >( Actions::SelectParents, [ this ](){ SelectParentEntities(); } ); m_commands.Create< DelegateCommand >( Actions::UndoSelectParents, [ this ](){ UndoSelectParentEntities(); } ); ``` These commands are added to a CommandList. The command list is executed at a very specific place in the UI where these should execute. ``` m_commands.ProcessShortcuts(); ``` For each command in the CommandList we run this code: ``` bool ActionShortcut( const EditorAction& action, bool canExecute ) { if( action.PrimaryKeyChord != ImGuiKey_None ) { if( ImGui::Shortcut( action.PrimaryKeyChord, ImGuiInputFlags_Repeat ) && canExecute ) return true; } if( action.SecondaryKeyChord != ImGuiKey_None ) { if( ImGui::Shortcut( action.SecondaryKeyChord, ImGuiInputFlags_Repeat ) && canExecute ) return true; } return false; } ```
ocornut commented 2026-10-14 17:32:37 +00:00 (Migrated from github.com)

Looks like you could add an extra parameter to EditorAction, and then store the sign in that structure and add an additional check in the ActionShortcut() function?

Or as a trick/helper, declare dummy large value for ImGuiKey_MouseWheelY_Positive and ImGuiKey_MouseWheelY_Negative and translate them to ImGuiKey_MouseWheelY + stored sign in EditorAction ?

Seems like either would solve your problem with <10 lines of code. The later has the advantage hiding the extra param from the EditorAction() constructor, since it's so rarely used.

The joystick enums works the way you wanted already, so arguably it is a bit inconsistent that MouseWheel don't, but I found that MouseWheel value was frequently easier to use as a single signed value. Adding two extra enums for each of them would technically be consistent, albeit only confuse code that does a full range scan. I could do that as well.

Looks like you could add an extra parameter to `EditorAction`, and then store the sign in that structure and add an additional check in the `ActionShortcut()` function? Or as a trick/helper, declare dummy large value for `ImGuiKey_MouseWheelY_Positive` and `ImGuiKey_MouseWheelY_Negative` and translate them to `ImGuiKey_MouseWheelY` + stored sign in `EditorAction` ? Seems like either would solve your problem with <10 lines of code. The later has the advantage hiding the extra param from the `EditorAction()` constructor, since it's so rarely used. The joystick enums works the way you wanted already, so arguably it is a bit inconsistent that MouseWheel don't, but I found that MouseWheel value was frequently easier to use as a single signed value. Adding two extra enums for each of them would technically be consistent, albeit only confuse code that does a full range scan. I could do that as well.
ocornut commented 2026-10-14 17:42:47 +00:00 (Migrated from github.com)

My worry about adding separate enums values for those is figuring of the key ownership would propagate, e.g. if some code takes ownership of MouseWheelY it should apply to MouseWheelY_Positive as well (but not necessarily the opposite).
I will experiment with this later, in order to figure out if it can be implemented without problems.

My worry about adding separate enums values for those is figuring of the key ownership would propagate, e.g. if some code takes ownership of `MouseWheelY` it should apply to `MouseWheelY_Positive` as well (but not necessarily the opposite). I will experiment with this later, in order to figure out if it can be implemented without problems.
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
ocornut/imgui#9583
No description provided.