2025-08-02 12:09:34 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								---
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								title: CommonUI
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								date: 2023-03-31 09:53:26
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								excerpt: 摘要
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								tags: 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								rating: ⭐
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								---
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								# 前言
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								CommonUI主要解决了**层叠式UI**输入事件处理以及**多平台**多输入设备管理问题。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								其中比较重要的机制是CommonUI实现的**输入路由**功能,其代码位于:`CommonGameViewportClient.h`  和 `CommonUIActionRouterBase.h`  。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								## 官方教学
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								-  文档
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									-  https://docs.unrealengine.com/5.1/en-US/common-ui-quickstart-guide-for-unreal-engine/
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									-  https://docs.unrealengine.com/5.1/en-US/overview-of-advanced-multiplatform-user-interfaces-with-common-ui-for-unreal-engine/
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								-  视频
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									-  [Introduction to Common UI | Inside Unreal ](https://www.youtube.com/live/TTB5y-03SnE?feature=share )
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									-  [Lyra Cross-platform UI Development | Tech Talk ](https://www.bilibili.com/video/BV1mT4y167Fm/?spm_id_from=333.999.0.0&vd_source=d47c0bb42f9c72fd7d74562185cee290 )
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								# CommonUI
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								-  数据表
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
									-  CommonInputActionDataBase:  各平台输入绑定。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								-  蓝图类资产
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
									-  CommonInputBaseControllerData:  各平台按键数据(  图标指定、鼠标键盘/手柄按键绑定)。在`ProjectSettings - Game - CommonInputSettings - PlatformInput - XX - Default - ControllerData` 中指定。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
									-  CommonUIInputData:  UI Click/Back Action 绑定用数据。之后在`ProjectSettings - Game - CommonInputSettings - InputData - ` 中指定。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
										-  Comfirm/Cancel DataTable需要填写CommonInputActionDataBase数据表。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								## CommonUI特有功能
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								1.  ⭐⭐**自带过渡效果**:  在Stack控件的`Detail-Transition` 中可以设置控件激活/注销时过渡效果,同时还可以设置效果曲线类型与曲线数值。默认是**渐隐(Fade Only)**。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								2.  ⭐⭐⭐**CommonActivatableWidgetStack**:  会自动激活Stack顶部Widget。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								3.  ⭐BackHandle:  后退动作处理,  除了勾选BackHandle与IsModel之外,  需要还需重写OnHandleBackAction(), 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								## CommonUI Setup&Data
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								1.  启用CommonUI插件。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								2.  `Engine - GeneralSettings - DefaultClasses - GameViewportClientClass` 将其指定为**CommonGameViewportClient**或其子类。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								3.  创建一个基于CommonInputActionDataBase的数据表,  并且创建按键事件映射表。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								4.  创建新的按钮类继承自`CommonButtonbase,  并在TriggeringInputAction应用数据表
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								5.  创建一个继承自`CommonActivatbleWidget` 的界面并设置为自动激活,并将按钮放入其中。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									1.  响应按键映射的前提是自己或某一Parent为已经激活的`CommonActivatbleWidget` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								### CommonInputActionDataBase
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								默认的数据表可以填写**键盘**、**手柄**、**平板**的输入事件表。但对于其他主机平台(PS、Xbox、Switch)往往需要调换手柄按键位置,这个时候可以通过**GamepadInputOverrides**对指定平台进行按键修改。需要**安装主机平台SDK**后才会显示对应选项。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								### CommonBaseControllerData
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								用于指定对应平台的**图标**资源。之后在`ProjectSettings - Game - CommonInputSettings - PlatformInput - XX - Default - ControllerData` 中指定。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								### CommonUIInputData
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								UI Click/Back Action 绑定用数据。之后在`ProjectSettings - Game - CommonInputSettings - InputData - ` 中指定。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								## CommonStyle
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								与UMG、Slate不同,  CommonUI没有通过**SlateWidgetStyle**而是通过继承对应的类来创建。每个CommonUI空间都有一个对应的Style类。之后可以在`ProjectSettings - Plugins - CommonUIEditor` 的**TemplateTextStyle**、**TemplateButtonStyle**、**TemplateBorderStyle**指定CommonUI的默认风格。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								## CommonUI控件
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								### UCommonUserWidget
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								CommonUI控件基类主要定义了: 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								1.  `TArray<FUIActionBindingHandle> ActionBindings` :  来管理控件的ActionBindings。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								2.  `TArray<TWeakObjectPtr<const UWidget>> ScrollRecipients` :滚动条控件。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								3.  `bool bConsumePointerInput` :  鼠标滑过控件时是否会产生反应。(  为true时返回FReply::Handled()) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								其他都是相关虚函数以及工具函数。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								### CommonActivatableWidget
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								大致翻译官方注释的话:
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								CommonActivatableWidget的基础,  是能够在其生命周期内被 "**activated** "和 "**deactivated**"而不被其他方式修改或销毁。通常是为了以下几个目的:
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								1.  该控件可以自由打开或者关闭,  同时不会被从层次结构(  WidgetTree)  中移除。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								2.  能从其他控件“退回”到这个控件(  例如使用SwitchWidget或者StackWidget)  。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								3.  这个部件在层次结构中的位置是这样的:它在可激活的部件树中定义了一个有意义的结点,通过这个结点,输入被路由到所有部件。(不太懂这条,应该是不会破坏输入路由的意思)
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								同时它还具备以下性质:
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								1.  创建后不会自动激活,需要调用函数手动**activated**。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								2.  默认情况下不会注册BackAction。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								3.  如果注册了BackAction,  那会在执行BackAction后自动**deactivated**。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								主要实现了"**activated** "和 "**deactivated**"的相关逻辑,主要是可见性以及输入路由。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								### UCommonActivatableWidgetContainerBase
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								添加的控件使用`FUserWidgetPool GeneratedWidgetsPool` 控件池进行创建与生命周期管理。`TArray<TObjectPtr<UCommonActivatableWidget>> WidgetList` 存储添加的控件指针。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								内部使用SOverlay,  来显示SCommonAnimatedSwitcher(  用于显示控件)  与SSpacer。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								### CommonButtonBase
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								与其他的CommonUI组件不同,  需要手动实现内部构造。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								与普通的Button相比,  拥有更好的可定制性,  比如: 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								-  其Style增加了设置各种事件发出声音的选项。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								-  拥有一个**Selectable**选项可以用来实现CheckBox或者多选框。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								### 其他控件
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								-  CommonActionWidget:  继承自UWidget,  用来显示指定游戏平台对应键盘/手柄按键图标。需要注意ProjectSettings-Game-CommonInputSettings中的DefaultGamepadName需要与CommonInputBaseControllerData资产的GamepadName相同,  否则无法显示对应的按键图标。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								-  CommonActivatableWidgetSwitcher:  继承自UCommonAnimatedSwitcher,  重写几个虚函数来管理内部CommonActivatableWidget的 "**activated** "和 "**deactivated**"。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
									-  CommonAnimatedSwitcher:  继承自UWidgetSwitcher,  主要实现了过渡动画(  具体在Slate控件里)  以及OnActiveWidgetIndexChanged、OnTransitioningChanged委托。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								-  CommonActivaableWidgetStack:  继承自UCommonActivatableWidgetContainerBase,  重写OnWidgetAddedToList(),添加控件时并显示末尾控件。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								-  CommonActivaableWidgetQueue:  继承自UCommonActivatableWidgetContainerBase,  重写OnWidgetAddedToList(),添加控件时并显示第一个控件。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								-  CommonBorder:  继承UBorder,  主要适配了CommonStyle。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								-  CommonHardwareVisibilityBorder:  继承CommonBorder,  重写OnWidgetRebuilt(),  根据CommonInputSubsystem(  ULocalPlayerSubsystem)  的ComputedVisibilityTags,  来决定是否显示。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								-  CommonCustomNavigation:  继承UBorder,  暴露一个FOnCustomNavigationEvent委托,  用于定义自定义的Navigation行为。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								-  CommonTextBlock:  继承自UTextBlock,  主要适配了CommonStyle,  并且添加了TextScroll。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								-  CommonDateTimeTextBlock:  继承自UCommonTextBlock,  主要存储了时间(  FDateTime、int32、float)并对文字进行格式化,  位于UpdateUnderlyingText(),  提供了若干DateTime相关的方法。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								-  CommonNumericTextBlock:  继承自UCommonTextBlock,  实现了Number、Percentage、Seconds、Distance相关数字文字的格式化方法。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								-  CommonLazyImage:  继承自UImage,  使用异步加载Image或者Material,  并在加载完之后替换图片。控制载入的函数为SetBrushFromLazyMaterial()、SetBrushFromLazyDisplayAsset(),  在加载完成前显示默认图片。本质是使用UAssetManager::GetStreamableManager().RequestAsyncLoad()进行加载。其中MyLoadGuard(  SLoadGuard)  为旋转载入图标控件。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								-  CommonLazyWidget:  继承自UWidget,  默认Visibility为SelfHitTestInvisible。控制载入的函数为SetLazyContent(),  本质是使用UAssetManager::GetStreamableManager().RequestAsyncLoad()进行加载。在RebuildWidget()与OnStreamingComplete()中设置MyLoadGuard与Content的可见性。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								-  CommonListVIew:  继承自UListView,  主要是重写OnGenerateEntryWidgetInternal()针对UCommonButtonBase进行适配;  内部使用SCommonListView控件。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								-  CommonLoadGuard:  继承自UContentWidget,  维护一个MyLoadGuard(SLoadGuard)。并且暴露样式、委托以及SetLoadingText()、SetIsLoading()、IsLoading()。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								-  CommonVisibilitySwitcher:  继承自UOverlay,  一个适配了UCommonActivatableWidget的基础控件切换器。控件存在`TArray<TObjectPtr<UPanelSlot>> Slots;` 。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								-  CommonBoundActionBar:  继承自UDynamicEntryBoxBase,  适配CommonUI输入控制的版本。主要在OnWidgetRebuilt()中调用MonitorPlayerActions()绑定CommonUI输入路由的OnBoundActionsUpdated委托。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								-  CommonWidgetCarousel:  继承自UPanelWidget,  卡片旋转式的WidgetSwitcher。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								-  CommonWidgetCarouselNavBar:  继承自UWidget,  控制CommonWidgetCarousel控件用的导航栏。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								-  List
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
									-  CommonTileView:  继承自UTileView,  替换了内部使用的Slate控件为SCommonTileView。并且重写OnGenerateEntryWidgetInternal()对UCommonButtonBase进行适配(  替换成SCommonButtonTableRow)  。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
									-  CommonTreeView:  继承自UTreeView,  替换了内部使用的Slate控件为SCommonTreeView。并且重写OnGenerateEntryWidgetInternal()对UCommonButtonBase进行适配(  替换成SCommonButtonTableRow)  。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								-  Pannel 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
									-  CommonHierarchicalScrollBox:  继承自UScrollBox,  替换了内部使用的Slate控件为SCommonHierarchicalScrollBox。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
									-  CommonVisualAttachment:  继承自USizeBox,  使用Slate控件为SVisualAttachmentBox。添加一个Widget作为另一个Widget的零尺寸附件。其设计目的为不改变Widget的尺寸计算。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								# 输入路由相关
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								## UCommonGameViewportClient
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								主要重写InputKey()、InputAxis()、InputTouch(),  之后通过HandleRerouteInput() 、HandleRerouteAxis()、HandleRerouteTouch()进行输入路由判断。其路由逻辑主要编写在
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								UCommonUIActionRouterBase,  是一个ULocalPlayerSubsystem子类。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								## UCommonUIActionRouterBase
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								主要用于处理注册/卸载ActionBindings、维护ActivateTree以及输入控制。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								## Input Binding & Process
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								### Process
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								以ProcessInput()为例,其关键代码为:
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								```c++
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								PersistentActions->ProcessHoldInput(ActiveMode, Key, InputEvent);
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								ActiveRootNode->ProcessHoldInput(ActiveMode, Key, InputEvent);
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								PersistentActions->ProcessNormalInput(ActiveMode, Key, Event);
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								ActiveRootNode->ProcessNormalInput(ActiveMode, Key, Event);
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								```
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								在对各种结果**依次**进行判断处理之后,  最终返回结果:  ERouteUIInputResult枚举。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								```c++
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								bool FActionRouterBindingCollection::ProcessNormalInput(ECommonInputMode ActiveInputMode, FKey Key, EInputEvent InputEvent) const
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								{
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									for (FUIActionBindingHandle BindingHandle : ActionBindings)
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									{
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
										if (TSharedPtr< FUIActionBinding >  Binding = FUIActionBinding::FindBinding(BindingHandle))
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
										{
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
											if (ActiveInputMode == ECommonInputMode::All || ActiveInputMode == Binding->InputMode)
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
											{
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
												for (const FUIActionKeyMapping&  KeyMapping : Binding->NormalMappings)
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
												{
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
													// A persistent displayed action skips the normal rules for reachability, since it'll always appear in a bound action bar
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
													const bool bIsDisplayedPersistentAction = Binding->bIsPersistent & &  Binding->bDisplayInActionBar;
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
													if (KeyMapping.Key == Key & &  Binding->InputEvent == InputEvent & &  (bIsDisplayedPersistentAction || IsWidgetReachableForInput(Binding->BoundWidget.Get())))
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
													{
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
														// Just in case this was in the middle of a hold process with a different key, reset now
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
														Binding->CancelHold();
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
														Binding->OnExecuteAction.ExecuteIfBound();
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
														if (Binding->bConsumesInput)
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
														{
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
															return true;
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
														}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
													}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
												}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
											}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									return false;
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								bool FActivatableTreeNode::ProcessNormalInput(ECommonInputMode ActiveInputMode, FKey Key, EInputEvent InputEvent) const  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								{  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									if (IsReceivingInput())  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									{  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
										for (const FActivatableTreeNodeRef&  ChildNode : Children)  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
										{  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
											if (ChildNode->ProcessNormalInput(ActiveInputMode, Key, InputEvent))  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
											{  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
												return true;  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
											}  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
										}  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
										return FActionRouterBindingCollection::ProcessNormalInput(ActiveInputMode, Key, InputEvent);  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									}  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									return false;  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								```
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								### Binding
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								可以看得出主要是ActionBindings,  而其注册逻辑位于UCommonUIActionRouterBase::Tick()=>ProcessRebuiltWidgets=>RegisterWidgetBindings(),  之后依次对构建的FActivatableTree中**CommonUserWidget**的绑定数据进行注册(  RegisterWidgetBindings、RegisterInputTreeNode)  。每个**CommonUserWidget**都使用这个RegisterUIActionBinding()来注册绑定信息。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								```c++
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								FUIActionBindingHandle UCommonUserWidget::RegisterUIActionBinding(const FBindUIActionArgs&  BindActionArgs)
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								{
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									if (UCommonUIActionRouterBase* ActionRouter = UCommonUIActionRouterBase::Get(*this))
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									{
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
										FBindUIActionArgs FinalBindActionArgs = BindActionArgs;
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
										if (bDisplayInActionBar & &  !BindActionArgs.bDisplayInActionBar)
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
										{
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
											FinalBindActionArgs.bDisplayInActionBar = true;
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
										FUIActionBindingHandle BindingHandle = ActionRouter->RegisterUIActionBinding(*this, FinalBindActionArgs);
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
										ActionBindings.Add(BindingHandle);
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
										return BindingHandle;
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									return FUIActionBindingHandle();
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								```
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								其绑定参数`FBindUIActionArgs` 数据为:
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								|                        |                                                                   |
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								| ---------------------- | ----------------------------------------------------------------- |
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								| ActionTag              | 目前没找到用处,  可能用于按下时给角色添加按下的Tag                 |
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								| LegacyActionTableRow   | 按键的映射表行                                                    |
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								| InputMode              | 输入模式,  只有当当前输入模式覆盖了Key的输入模式才触发事件,默认all |
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								| KeyEvent               | 什么状态下触发(按下、松开、etc...)                                |
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								| bIsPersistent          | 持久化,  为true则无视Activate规则始终响应按键输入                  |
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								| bConsumeInput          | 是否消耗掉本次输入(相同按键绑定不再能触发),  默认为true            |
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								| bDisplayInActionBar    | 是否在CommonActionBar上实时显示按键提示                           |
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								| OverrideDisplayName    | 新的显示名                                                        |
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								| OnExecuteAction        | 当按键触发时执行的回调函数                                        |
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								| OnHoldActionProgressed | 当按住时的回调                                                    |
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								# Lyra中的用法
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								-  Safe-Zone
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								创建了若干控件:
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								-  MaterialProgressBar:  继承自UCommonUserWidget
							 
						 
					
						
							
								
									
										
										
										
											2025-08-31 22:06:51 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								-  LyraBoundActionButton:  继承自UCommonBoundActionButton
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								# # CommonUI Navigating  
 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-02 17:49:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
								
									
								 
							
							
								- [x]  [How to Handle Input and Navigation in Unreal Motion Graphics (UMG) | Unreal Fest Gold Coast 2024 ](https://www.youtube.com/watch?v=kZUwEEtkItg )
							 
						 
					
						
							
								
									
										
										
										
											2025-09-04 11:49:18 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
								
									
								 
							
							
								- [ ]  [# UE5 - Common Ui: Enhanced Input Action Setup (Short Version) ](https://www.youtube.com/watch?v=17nARa4jruc )
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								- [ ]  [# UE5 - Common UI: Keyboard Controls Setup ](https://www.youtube.com/watch?v=aDoNLyUVy2o )
							 
						 
					
						
							
								
									
										
										
										
											2025-09-02 12:08:31 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								PS:
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								1.  针对含有子Widget的控件(  CommonActivatedWidget)  需要勾选Auto Activate
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								## 相关属性
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								-  Auto Activate:  针对含有子Widget的控件(  CommonActivatedWidget)  需要勾选Auto Activate
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								-  Autp Restore Focus:  这样Widget可以自动恢复焦点位置。
							 
						 
					
						
							
								
									
										
										
										
											2025-09-02 15:59:13 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
								
									
								 
							
							
								-  CommonActivatableWidget 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									-  IsBackHandler
							 
						 
					
						
							
								
									
										
										
										
											2025-09-02 16:47:32 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								-  IsFocusable:  勾选true
							 
						 
					
						
							
								
									
										
										
										
											2025-09-02 12:08:31 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								## 相关事件
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								-  OnActivated: 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								-  OnDeactivated: 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-02 17:49:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								-  OnAddedToFocusPath: 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-03 11:07:14 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								-  OnRemoveFromFocusPath: 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								## 函数?
 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-03 13:52:28 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
								
									
								 
							
							
								KeyBoardFocus
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								```c++
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								void UWidget::SetKeyboardFocus()
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								{
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									TSharedPtr< SWidget >  SafeWidget = GetCachedWidget();
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									if (SafeWidget.IsValid())
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									{
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
										if ( !SafeWidget->SupportsKeyboardFocus() )
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
										{
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
											FMessageLog("PIE").Warning(FText::Format(LOCTEXT("ThisWidgetDoesntSupportFocus", "The widget {0} does not support focus. If this is a UserWidget, you should set bIsFocusable to true."), FText::FromString(GetNameSafe(this))));
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								#endif
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
										if ( !FSlateApplication::Get().SetKeyboardFocus(SafeWidget) )
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
										{
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
											if ( UWorld* World = GetWorld() )
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
											{
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
												if ( ULocalPlayer* LocalPlayer = World->GetFirstLocalPlayerFromController() )
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
												{
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
													LocalPlayer->GetSlateOperations().SetUserFocus(SafeWidget.ToSharedRef(), EFocusCause::SetDirectly);
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
												}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
											}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								void UWidget::SetFocus()  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								{  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								    SetUserFocus(GetOwningPlayer());  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								void UWidget::SetUserFocus(APlayerController* PlayerController)
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								{
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									if ( PlayerController == nullptr || !PlayerController->IsLocalPlayerController() || PlayerController->Player == nullptr )
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									{
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
										FMessageLog("PIE").Error()->AddToken(FTextToken::Create(LOCTEXT("NoPlayerControllerToFocus", "The PlayerController is not a valid local player so it can't focus on ")))->AddToken(FUObjectToken::Create(this));
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								#endif
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
										return;
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									TSharedPtr< SWidget >  SafeWidget = GetCachedWidget();
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									if ( SafeWidget.IsValid() )
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									{
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
										if ( !SafeWidget->SupportsKeyboardFocus() )
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
										{
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
											TSharedRef< FTokenizedMessage >  Message = FMessageLog("PIE").Warning()->AddToken(FUObjectToken::Create(this));
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								#if WITH_EDITORONLY_DATA
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
											if(UObject* GeneratedBy = WidgetGeneratedBy.Get())
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
											{
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
												Message->AddToken(FTextToken::Create(FText::FromString(TEXT(" in "))))->AddToken(FUObjectToken::Create(GeneratedBy));
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
											}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								#endif
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
											if (IsA(UUserWidget::StaticClass()))
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
											{
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
												Message->AddToken(FTextToken::Create(LOCTEXT("UserWidgetDoesntSupportFocus", " does not support focus, you should set bIsFocusable to true.")));
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
											}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
											else
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
											{
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
												Message->AddToken(FTextToken::Create(LOCTEXT("NonUserWidgetDoesntSupportFocus", " does not support focus.")));
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
											}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
											
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								#endif
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
										if ( ULocalPlayer* LocalPlayer = PlayerController->GetLocalPlayer() )
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
										{
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
											TOptional< int32 >  UserIndex = FSlateApplication::Get().GetUserIndexForController(LocalPlayer->GetControllerId());
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
											if (UserIndex.IsSet())
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
											{
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
												FReply&  DelayedSlateOperations = LocalPlayer->GetSlateOperations();
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
												if (FSlateApplication::Get().SetUserFocus(UserIndex.GetValue(), SafeWidget))
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
												{
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
													DelayedSlateOperations.CancelFocusRequest();
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
												}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
												else
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
												{
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
													DelayedSlateOperations.SetUserFocus(SafeWidget.ToSharedRef());
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
												}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
												
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
											}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								}
							 
						 
					
						
							
								
									
										
										
										
											2025-09-03 15:53:16 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
								
									
								 
							
							
								```
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-09-04 18:14:03 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
								
									
								 
							
							
								# CommonUI Use Enhanced Input
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								-  官方文档
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									-  [Using CommonUI With Enhanced Input ](https://dev.epicgames.com/documentation/en-us/unreal-engine/using-commonui-with-enhnaced-input-in-unreal-engine )
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								-  视频
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									-  [UE5 - Common Ui: Enhanced Input Action Setup (Short Version) ](https://www.youtube.com/watch?v=17nARa4jruc )
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								1.  创建InputAction资产。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								2.  创建DataAesset(CommonMappingContextMetaData),  为每个控制器都创建一个,  比如Generic、PS5等
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									1.  EnhancedInputMetaData 选择 Common Input MetaData
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
									2.  设置NavBarPriority(  Epic的教程推荐为10,  这样流出一些空余给后续更高优先级的输入) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
									3.  根据需求勾选IsGenericInputAction,  **这个输入是否在被UI接收的同时,  发送到Character或者PlayerController中,  并执行事件**。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									4.  添加创建的InputAction到PerActionEnhancedInputMetaData中。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								3.  在InputAction的UserSettings - PlayerMappableKeySettings的MetaData中添加上一步创建CommonMappingContextMetaData
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								4.  创建IMC,  添加InputAction并且设置按键。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								5.  在ProjectSettings - Enginge - EnhancedInput中的DefaultMappingContext中添加上一步创建的IMC,  并且勾选RegisterWithUserSettings。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								6.  在CommonUI控件中添加IMC
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									1.  在CommonButton的TriggerEnhancedInputAction中添加InputAction。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
									2.  另一个可以添加的就是TabList控件,  TabList - Previous / Next Tab Input Action 中添加。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								PS. CommonUI开启输入增强后,  **CommonUI InputData**中也可以添加InputAction了。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								主要是作为CommonUI中InputActionDataTable的补充(  DataTable面向多平台通用输入) ,  一些犄角旮旯的还是通过InputAction设置比较方便。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-09-03 15:53:16 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
								
									
								 
							
							
								# TODO
 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-04 11:49:18 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
								
									
								 
							
							
								1.  [x] 解决一些Button Release方面的颜色bug
							 
						 
					
						
							
								
									
										
										
										
											2025-09-05 10:05:55 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								2.  [ ] ~~修复KeyBoard UI Nav的bug,  鼠标&键盘同时使用问题~~  逻辑就是判断在OnHovered事件中判断当前控件是否有UserFocus,  没有的话就设置一个Hovered颜色与Normal颜色相同的Style。
							 
						 
					
						
							
								
									
										
										
										
											2025-09-04 13:17:54 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
								
									
								 
							
							
								3.  [ ] ~~鼠标点击空白区域会导致丢失Focus的问题~~ 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-04 19:43:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
								
									
								 
							
							
									1.  [ ] 需要通过c++扩展来获得Focus, https://georgy.dev/posts/get-focused-widget/
							 
						 
					
						
							
								
									
										
										
										
											2025-09-05 10:36:51 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								4.  UI 控件扩展:  KeySelector扩展,  添加图标模型以及只有GamePad输入模式。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								5.  UI 控件扩展:  CommonActivatedWidget => CommonActivatedInputActionWidget,  参考CommonButton.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								6.  声音没有保存设置。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								7.  给其他控件实现类似CommonButton的bShouldUseFallbackDefaultInputAction的功能
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								8.  Settings 界面添加设置说明
							 
						 
					
						
							
								
									
										
										
										
											2025-09-12 10:17:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
								
									
								 
							
							
								9.  建造模式 设置颜色与材质 UI。
							 
						 
					
						
							
								
									
										
										
										
											2025-09-04 10:01:12 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								## 其他手柄输出
 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-04 11:49:18 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
								
									
								 
							
							
								-  GameInput for Windows Plugin (需要[Microsoft Game Development Kit ](https://learn.microsoft.com/en-us/gaming/gdk/_content/gc/input/overviews/input-overview ) 权限,需要填表注册)
							 
						 
					
						
							
								
									
										
										
										
											2025-09-04 10:01:12 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
								
									
								 
							
							
								-  Dualshock Input Plugin
							 
						 
					
						
							
								
									
										
										
										
											2025-09-04 11:49:18 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
								
									
								 
							
							
								-  其他传统Input插件
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									-  XInput(只支持XInput 手柄)
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
									-  Raw Input Plugin
							 
						 
					
						
							
								
									
										
										
										
											2025-09-04 10:01:12 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
										 
									
								 
							
							
								现在,  我们通过新的“Game Input for Windows”插件,  在虚幻引擎中更轻松地支持 PS4/5 控制器:[Game Input for Windows - Experimental Release Notes ](https://dev.epicgames.com/community/learning/tutorials/EpZ4/unreal-engine-game-input-for-windows-experimental-release-notes )
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								我想澄清一下关于虚幻引擎中的 **Dualshock 输入插件**的一些内容。不幸的是,目前这仅适用于开发人员安装了 **PlayStation SDK**  的项目,只有在 Sony PlayStation 开发网络上注册的工作室才能做到这一点。
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
								
									
								 
							
							
								如果您无法访问 Sony PlayStation 开发网络,目前没有简单的方法可以让 PS5 控制器“即插即用”,与我所知道的虚幻引擎游戏配合使用。