// Fill out your copyright notice in the Description page of Project Settings. #include "KeyCaptureWidget.h" #include "Components/Button.h" #include "Components/TextBlock.h" #define LOCTEXT_NAMESPACE "Reglages" UKeyCaptureWidget::UKeyCaptureWidget(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { // Sans ce drapeau le widget ne peut pas prendre le focus clavier, et // NativeOnKeyDown ne serait jamais appele -- le voile resterait affiche sans // jamais rien capturer. Meme piege que UConfirmDialogWidget. SetIsFocusable(true); PromptFormat = LOCTEXT("CapturePrompt", "Appuie sur une touche pour « {0} »\nÉchap pour annuler"); } void UKeyCaptureWidget::NativeOnInitialized() { Super::NativeOnInitialized(); if (ConfirmButton) { ConfirmButton->OnClicked.AddDynamic(this, &UKeyCaptureWidget::HandleConfirmClicked); } if (CancelButton) { CancelButton->OnClicked.AddDynamic(this, &UKeyCaptureWidget::HandleCancelClicked); } } void UKeyCaptureWidget::BeginCapture(const FText& ActionLabel) { State = EKeyCaptureState::Capturing; if (PromptText) { PromptText->SetText(FText::Format(PromptFormat, ActionLabel)); } UpdateButtonVisibility(); SetVisibility(ESlateVisibility::Visible); // Le focus se reprend a CHAQUE ouverture : le refermer le rend a l'ecran de // reglages, et un voile visible mais sans focus ignorerait le clavier. SetKeyboardFocus(); } void UKeyCaptureWidget::ShowConflict(const FText& Message) { State = EKeyCaptureState::Conflict; if (PromptText) { PromptText->SetText(Message); } UpdateButtonVisibility(); // Le voile n'a pas bouge, mais le focus a pu partir sur un bouton qui vient // d'apparaitre : on le reprend pour qu'Echap continue de repondre. SetKeyboardFocus(); } void UKeyCaptureWidget::EndCapture() { State = EKeyCaptureState::Idle; UpdateButtonVisibility(); SetVisibility(ESlateVisibility::Collapsed); } void UKeyCaptureWidget::UpdateButtonVisibility() { // Collapsed et non Hidden : replies, les boutons ne doivent pas reserver la // place qu'ils occuperont, sinon la consigne de capture serait decentree. const ESlateVisibility ButtonVisibility = State == EKeyCaptureState::Conflict ? ESlateVisibility::Visible : ESlateVisibility::Collapsed; if (ConfirmButton) { ConfirmButton->SetVisibility(ButtonVisibility); } if (CancelButton) { CancelButton->SetVisibility(ButtonVisibility); } } FReply UKeyCaptureWidget::NativeOnKeyDown(const FGeometry& InGeometry, const FKeyEvent& InKeyEvent) { const FKey Key = InKeyEvent.GetKey(); if (State == EKeyCaptureState::Conflict) { // Echap vaut Annuler, comme partout ailleurs dans les menus. if (Key == EKeys::Escape) { OnConflictAnswered.Broadcast(false); } // Aucune autre touche n'est lue : on ne capture plus, on attend une // reponse. Sans ce garde-fou, appuyer sur une touche pour "repondre" // relancerait un remappage a l'insu du joueur. return FReply::Handled(); } return CaptureKey(Key); } FReply UKeyCaptureWidget::NativeOnMouseButtonDown(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent) { if (State == EKeyCaptureState::Conflict) { // Les clics sur les boutons ne remontent pas jusqu'ici, ils sont traites // avant. Tout le reste est avale pour garder le voile modal. return FReply::Handled(); } // La souris passe par le meme chemin que le clavier : Souris 4 et Souris 5 // sont des touches comme les autres pour Enhanced Input. return CaptureKey(InMouseEvent.GetEffectingButton()); } FReply UKeyCaptureWidget::CaptureKey(const FKey& Key) { if (Key == EKeys::Escape) { OnCaptureCancelled.Broadcast(); return FReply::Handled(); } // Les touches de modification seules ne sont pas capturees : Enhanced Input // les traite comme des touches a part entiere, mais assigner "Maj" tout court // rendrait inutilisable toute combinaison la contenant. if (Key.IsModifierKey()) { return FReply::Handled(); } // Un axe analogique n'est pas assignable a une action Digital : on ignore // plutot que de laisser MapPlayerKey echouer plus loin sans explication. if (Key.IsAxis1D() || Key.IsAxis2D() || Key.IsAxis3D()) { return FReply::Handled(); } OnKeyCaptured.Broadcast(Key); // Handled dans tous les cas : le voile est modal, rien ne doit passer a // travers pendant qu'il attend une touche. return FReply::Handled(); } void UKeyCaptureWidget::HandleConfirmClicked() { OnConflictAnswered.Broadcast(true); } void UKeyCaptureWidget::HandleCancelClicked() { OnConflictAnswered.Broadcast(false); } #undef LOCTEXT_NAMESPACE