using UnityEngine; using UnityEngine.UI; using UnityEngine.EventSystems; using TMPro; // Clavier interne lettres + chiffres pour un TMP_InputField (code postal de SUPPLIERS). // A poser sur le champ lui-meme. // // Sur mobile / WebGL, toucher un TMP_InputField donne le focus a un input HTML cache : le // navigateur ouvre son clavier ET fait defiler la page pour amener cet input a l'ecran. // On refuse donc le focus natif des la selection et on affiche ce clavier a la place. [RequireComponent(typeof(TMP_InputField))] public class PostalKeyboard : MonoBehaviour { [Tooltip("Longueur maximale saisie, espace compris (ex: H2X 1Y4)")] public int MaxLength = 7; static readonly string[] Rows = { "1234567890", "QWERTYUIOP", "ASDFGHJKL", "ZXCVBNM" }; const string PanelName = "POSTALKEYBOARD"; const float RowHeight = 58f; const float RowSpacing = 6f; const float SideMargin = 10f; TMP_InputField Field; GameObject Panel; void Awake() { Field = GetComponent(); Field.onSelect.AddListener(_ => OnFieldSelected()); } void OnDisable() { if (Panel != null) Panel.SetActive(false); } void OnFieldSelected() { // Sur poste de travail le clavier physique fait le travail : on ne change rien. if (!Application.isMobilePlatform && Application.platform != RuntimePlatform.WebGLPlayer) return; Field.DeactivateInputField(); if (EventSystem.current != null) EventSystem.current.SetSelectedGameObject(null); Show(true); } void Show(bool On) { if (Panel == null) { if (!On) return; Panel = Build(); } Panel.SetActive(On); } //--------------------------SAISIE---------------------------------------- void Type(string Key) { string Value = Field.text ?? ""; if (Value.Length >= MaxLength) return; Field.text = Value + Key; } void Back() { string Value = Field.text ?? ""; if (Value.Length > 0) Field.text = Value[..^1]; } //--------------------------CONSTRUCTION---------------------------------------- // Le clavier est cree sous HIDER : c'est le dernier enfant du Canvas, donc dessine // par-dessus les panneaux, et il survit au changement de page. GameObject Build() { Transform Parent = Get.o1("HIDER") != null ? Get.o1("HIDER").transform : Get.o1("Canvas").transform; GameObject Root = new(PanelName, typeof(RectTransform), typeof(CanvasRenderer), typeof(Image)); Root.transform.SetParent(Parent, false); RectTransform Rt = (RectTransform)Root.transform; Rt.anchorMin = new Vector2(0f, 0f); Rt.anchorMax = new Vector2(1f, 0f); Rt.pivot = new Vector2(0.5f, 0f); Rt.anchoredPosition = Vector2.zero; Rt.sizeDelta = new Vector2(0f, Rows.Length * (RowHeight + RowSpacing) + RowHeight + RowSpacing * 2f); Root.GetComponent().color = new Color(0.12f, 0.12f, 0.12f, 0.95f); Font KeyFont = PanelFont(); // Les touches sont ancrees en fractions de largeur : le clavier suit la taille de l'ecran. for (int r = 0; r < Rows.Length; r++) { string Row = Rows[r]; float Y = -(r * (RowHeight + RowSpacing)) - RowSpacing; for (int k = 0; k < Row.Length; k++) { string Key = Row[k].ToString(); AddKey(Root.transform, Key, Key, KeyFont, k / (float)Row.Length, (k + 1) / (float)Row.Length, Y, () => Type(Key)); } } // Derniere rangee : espace, effacer, valider. float LastY = -(Rows.Length * (RowHeight + RowSpacing)) - RowSpacing; AddKey(Root.transform, "Space", "___", KeyFont, 0f, 0.5f, LastY, () => Type(" ")); AddKey(Root.transform, "Back", "<", KeyFont, 0.5f, 0.75f, LastY, Back); AddKey(Root.transform, "Done", "OK", KeyFont, 0.75f, 1f, LastY, () => Show(false)); return Root; } void AddKey(Transform Parent, string GoName, string Label, Font KeyFont, float XMin, float XMax, float Y, UnityEngine.Events.UnityAction OnClick) { GameObject Key = new(GoName, typeof(RectTransform), typeof(CanvasRenderer), typeof(Image), typeof(Button)); Key.transform.SetParent(Parent, false); RectTransform Rt = (RectTransform)Key.transform; Rt.anchorMin = new Vector2(XMin, 1f); Rt.anchorMax = new Vector2(XMax, 1f); Rt.pivot = new Vector2(0.5f, 1f); Rt.sizeDelta = new Vector2(-2f * SideMargin, RowHeight); Rt.anchoredPosition = new Vector2(0f, Y); Key.GetComponent().color = Color.white; Key.GetComponent