diff --git a/power-apps/keyboard/README.md b/power-apps/keyboard/README.md new file mode 100644 index 0000000..6817ec7 --- /dev/null +++ b/power-apps/keyboard/README.md @@ -0,0 +1,39 @@ +# Keyboard + +This custom PowerApps component provides a fully functional virtual keyboard supporting letters, numbers, and special characters. It offers seamless language switching between French and English, making it ideal for multilingual applications and touch-based interfaces. Designed for flexibility and ease of integration, it enhances user input across a wide range of scenarios. + +This component is designed to complement the default keyboard, especially on large tablets or touchscreen kiosks 🖥️. It lets you position the keyboard wherever you want 📍, adjust its size 📐, and even customize the keys and colors 🎨 to fit your needs. +Flexibility and user experience first! 🚀 + + + +![keyboard](./assets/keyboard.gif) + + +## Authors + +Snippet|Author +--------|--------- +Steve Bourdin | [GitHub](https://github.com/SteveBourdin) ([LinkedIn](https://www.linkedin.com/in/steve-bourdin-ab998762/) ) + +## Minimal path to awesome + +Copy the provided **[YAML-file](./source/keyboard.yaml)** code into the Component section of your PowerApps project. +Use the Default property of the component to set an initial text value. +The current value typed using the keyboard is accessible via the component’s Value property. + +Once the component is placed on a canvas screen, to test it: +- Add a text input control. +- Set the Value property of the input to keyboard.Value. +- Set the Default property of the keyboard component to the value of the input control (e.g., TextInput1.Text). + + +## Code + **[YAML-file](./source/keyboard.yaml)** + + +## Disclaimer + +**THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.** + + diff --git a/power-apps/keyboard/assets/keyboard.gif b/power-apps/keyboard/assets/keyboard.gif new file mode 100644 index 0000000..68224b7 Binary files /dev/null and b/power-apps/keyboard/assets/keyboard.gif differ diff --git a/power-apps/keyboard/assets/sample.json b/power-apps/keyboard/assets/sample.json new file mode 100644 index 0000000..6f29dcb --- /dev/null +++ b/power-apps/keyboard/assets/sample.json @@ -0,0 +1,52 @@ +[ + { + "$schema": "https://developer.microsoft.com/en-us/json-schemas/pnp/samples/v1.0/metadata-schema.json", + "name": "pnp-powerplatform-snippets-keyboard", + "version": "1.0.0.0", + "source": "pnp", + "creationDateTime": "2025-04-29T00:00:00.000Z", + "updateDateTime": "2025-04-29T00:00:00.000Z", + "title": "Keyboard", + "shortDescription": "A keyboard for PowerApps", + "longDescription": [ + "This custom PowerApps component provides a fully functional virtual keyboard supporting letters, numbers, and special characters. It offers seamless language switching between French and English, making it ideal for multilingual applications and touch-based interfaces. Designed for flexibility and ease of integration, it enhances user input across a wide range of scenarios." + ], + "url": "https://github.com/pnp/powerplatform-snippets/tree/main/power-apps/keyboard/", + "products": [ + "Power Platform", + "Power Apps", + "powerplatform-snippets", + "power-apps-snippets" + ], + "tags": [ + ], + "categories": [ + ], + "metadata": [ + { + "key": "Product", + "value": "Power Apps" + }, + { + "key": "Type", + "value": "Snippet" + } + ], + "thumbnails": [ + { + "type": "image", + "order": 100, + "url": "https://raw.githubusercontent.com/pnp/powerplatform-snippets/62453fde084d0904826ecec20b9f54bf05acee38/power-apps/keyboard/assets/keyboard.gif", + "alt": "Preview PNG" + } + ], + "authors": [ + { + "gitHubAccount": "SteveBourdin", + "name": "Steve Bourdin", + "pictureUrl": "https://github.com/SteveBourdin.png" + } + ] + } + +] diff --git a/power-apps/keyboard/source/keyboard.yaml b/power-apps/keyboard/source/keyboard.yaml new file mode 100644 index 0000000..b7cc015 --- /dev/null +++ b/power-apps/keyboard/source/keyboard.yaml @@ -0,0 +1,480 @@ +ComponentDefinitions: + keyboard: + DefinitionType: CanvasComponent + CustomProperties: + Default: + PropertyKind: Input + DisplayName: Default + Description: Propriété personnalisée + DataType: Text + Default: ="Texte" + French: + PropertyKind: Input + DisplayName: French + Description: Propriété personnalisée + DataType: Boolean + Default: =false + Value: + PropertyKind: Output + DisplayName: Value + Description: Propriété personnalisée + DataType: Text + Properties: + ChildTabPriority: |- + =/*Steve BOURDIN - MOCA by ASI*/ + true + Height: =338 + Value: =varKeyboard + Width: =412 + Children: + - cont_keyboard: + Control: GroupContainer@1.3.0 + Variant: AutoLayout + Properties: + DropShadow: =DropShadow.Regular + Height: =Parent.Height-10 + LayoutAlignItems: =LayoutAlignItems.Center + LayoutDirection: =LayoutDirection.Vertical + LayoutJustifyContent: =LayoutJustifyContent.Center + PaddingBottom: =8 + PaddingLeft: =8 + PaddingRight: =8 + PaddingTop: =8 + Width: =Parent.Width-10 + X: =5 + Y: =5 + Children: + - cont_line1: + Control: GroupContainer@1.3.0 + Variant: AutoLayout + Properties: + AlignInContainer: =AlignInContainer.SetByContainer + DropShadow: =DropShadow.None + LayoutDirection: =LayoutDirection.Horizontal + LayoutMinHeight: =0 + Width: =Parent.Width-Parent.PaddingRight-Parent.PaddingLeft + Children: + - gal_line1: + Control: Gallery@2.15.0 + Variant: Horizontal + Properties: + AlignInContainer: =AlignInContainer.SetByContainer + BorderColor: =RGBA(0, 18, 107, 1) + Height: =Parent.Height + Items: =["1","2","3","4","5","6","7","8","9","0"] + LayoutMinWidth: =0 + ShowScrollbar: =false + TemplateSize: =(Self.Width/If(Self.AllItemsCount>0,Self.AllItemsCount,1))-Self.TemplatePadding + Width: =Parent.Width + Children: + - btn_line1: + Control: Classic/Button@2.2.0 + Properties: + BorderColor: =ColorFade(Self.Fill, -15%) + BorderThickness: =0 + Color: =Color.Black + DisabledBorderColor: =RGBA(166, 166, 166, 1) + Fill: =RGBA(247, 242, 250, 1) + Font: =Font.'Open Sans' + FontWeight: =FontWeight.Normal + Height: =Parent.TemplateHeight + HoverBorderColor: =ColorFade(Self.BorderColor, 20%) + HoverColor: =RGBA(255, 255, 255, 1) + HoverFill: =RGBA(208,188,255,1) + OnSelect: |- + =Set( + varKeyboard, + Concatenate( + keyboard.Default, + Self.Text + ) + ) + PressedBorderColor: =Self.Fill + PressedColor: =Self.Fill + PressedFill: =Self.Color + RadiusBottomLeft: =6 + RadiusBottomRight: =6 + RadiusTopLeft: =6 + RadiusTopRight: =6 + Size: =20 + Text: =If(varKeyboardMaj=true,Upper(ThisItem.Value),Lower(ThisItem.Value)) + Width: =Parent.TemplateWidth + - cont_line2: + Control: GroupContainer@1.3.0 + Variant: AutoLayout + Properties: + AlignInContainer: =AlignInContainer.SetByContainer + DropShadow: =DropShadow.None + LayoutDirection: =LayoutDirection.Horizontal + LayoutMinHeight: =0 + Width: =Parent.Width-Parent.PaddingRight-Parent.PaddingLeft + Children: + - gal_line2: + Control: Gallery@2.15.0 + Variant: Horizontal + Properties: + AlignInContainer: =AlignInContainer.SetByContainer + BorderColor: =RGBA(0, 18, 107, 1) + Height: =Parent.Height + Items: =If(varKeyboardSpec=true,["+","*","/","=","\","_","€","£","~","`"],If(keyboard.French,["a","z","e","r","t","y","u","i","o","p"], ["q","w","e","r","t","y","u","i","o","p"])) + LayoutMinWidth: =0 + ShowScrollbar: =false + TemplateSize: =(Self.Width/If(Self.AllItemsCount>0,Self.AllItemsCount,1))-Self.TemplatePadding + Width: =Parent.Width + Children: + - btn_line2: + Control: Classic/Button@2.2.0 + Properties: + BorderColor: =ColorFade(Self.Fill, -15%) + BorderThickness: =0 + Color: =Color.Black + DisabledBorderColor: =RGBA(166, 166, 166, 1) + Fill: =RGBA(247, 242, 250, 1) + Font: =Font.'Open Sans' + FontWeight: =FontWeight.Normal + Height: =Parent.TemplateHeight + HoverBorderColor: =ColorFade(Self.BorderColor, 20%) + HoverColor: =RGBA(255, 255, 255, 1) + HoverFill: =RGBA(208,188,255,1) + OnSelect: |- + =Set( + varKeyboard, + Concatenate( + keyboard.Default, + Self.Text + ) + ) + PressedBorderColor: =Self.Fill + PressedColor: =Self.Fill + PressedFill: =Self.Color + RadiusBottomLeft: =6 + RadiusBottomRight: =6 + RadiusTopLeft: =6 + RadiusTopRight: =6 + Size: =20 + Text: =If(varKeyboardMaj=true,Upper(ThisItem.Value),Lower(ThisItem.Value)) + Width: =Parent.TemplateWidth + - cont_line3: + Control: GroupContainer@1.3.0 + Variant: AutoLayout + Properties: + AlignInContainer: =AlignInContainer.SetByContainer + DropShadow: =DropShadow.None + LayoutDirection: =LayoutDirection.Horizontal + LayoutJustifyContent: =LayoutJustifyContent.Center + LayoutMinHeight: =0 + Width: =Parent.Width-Parent.PaddingRight-Parent.PaddingLeft + Children: + - gal_line3: + Control: Gallery@2.15.0 + Variant: Horizontal + Properties: + AlignInContainer: =AlignInContainer.Center + BorderColor: =RGBA(0, 18, 107, 1) + FillPortions: =0 + Height: =Parent.Height + Items: =If(varKeyboardSpec=true,["!","@","#","$","%","^","&","*","(",")"],If(keyboard.French,["q","s","d","f","g","h","j","k","l","m"],["a","s","d","f","g","h","j","k","l"])) + LayoutMinWidth: =0 + ShowScrollbar: =false + TemplateSize: =gal_line2.TemplateWidth + Width: =Self.AllItemsCount*(gal_line2.TemplateWidth+gal_line2.TemplatePadding) + Children: + - btn_line3: + Control: Classic/Button@2.2.0 + Properties: + BorderColor: =ColorFade(Self.Fill, -15%) + BorderThickness: =0 + Color: =Color.Black + DisabledBorderColor: =RGBA(166, 166, 166, 1) + Fill: =RGBA(247, 242, 250, 1) + Font: =Font.'Open Sans' + FontWeight: =FontWeight.Normal + Height: =Parent.TemplateHeight + HoverBorderColor: =ColorFade(Self.BorderColor, 20%) + HoverColor: =RGBA(255, 255, 255, 1) + HoverFill: =ColorFade(RGBA(56, 96, 178, 1), -20%) + OnSelect: |- + =Set( + varKeyboard, + Concatenate( + keyboard.Default, + Self.Text + ) + ) + PressedBorderColor: =Self.Fill + PressedColor: =Self.Fill + PressedFill: =Self.Color + RadiusBottomLeft: =6 + RadiusBottomRight: =6 + RadiusTopLeft: =6 + RadiusTopRight: =6 + Size: =20 + Text: =If(varKeyboardMaj=true,Upper(ThisItem.Value),Lower(ThisItem.Value)) + Width: =Parent.TemplateWidth + - cont_line4: + Control: GroupContainer@1.3.0 + Variant: AutoLayout + Properties: + AlignInContainer: =AlignInContainer.SetByContainer + DropShadow: =DropShadow.None + LayoutDirection: =LayoutDirection.Horizontal + LayoutJustifyContent: =LayoutJustifyContent.Center + LayoutMinHeight: =0 + Width: =Parent.Width-Parent.PaddingRight-Parent.PaddingLeft + Children: + - img_upshift: + Control: Image@2.2.3 + Properties: + BorderColor: =RGBA(0, 18, 107, 1) + Height: =Parent.Height + Image: |- + ="data:image/svg+xml;utf8," & EncodeUrl( + " + + + " + ) + ImagePosition: =ImagePosition.Center + OnSelect: =Set(varKeyboardMaj,Not varKeyboardMaj) + PaddingBottom: =5 + PaddingRight: =5 + PaddingTop: =5 + Tooltip: =Self.Width + Width: =(Parent.Width-gal_line5.Width)/2 + - gal_line5: + Control: Gallery@2.15.0 + Variant: Horizontal + Properties: + AlignInContainer: =AlignInContainer.Center + BorderColor: =RGBA(0, 18, 107, 1) + FillPortions: =0 + Height: =Parent.Height + Items: =If(varKeyboardSpec=true,["-","'","""",":",";",",","?"],If(keyboard.French,["w","x","c","v","b","n"],["z","x","c","v","b","n","m"])) + LayoutMinWidth: =0 + ShowScrollbar: =false + TemplateSize: =gal_line2.TemplateWidth + Width: =Self.AllItemsCount*(gal_line2.TemplateWidth+gal_line2.TemplatePadding) + Children: + - btn_line5: + Control: Classic/Button@2.2.0 + Properties: + BorderColor: =ColorFade(Self.Fill, -15%) + BorderThickness: =0 + Color: =Color.Black + DisabledBorderColor: =RGBA(166, 166, 166, 1) + Fill: =RGBA(247, 242, 250, 1) + Font: =Font.'Open Sans' + FontWeight: =FontWeight.Normal + Height: =Parent.TemplateHeight + HoverBorderColor: =ColorFade(Self.BorderColor, 20%) + HoverColor: =RGBA(255, 255, 255, 1) + HoverFill: =ColorFade(RGBA(56, 96, 178, 1), -20%) + OnSelect: |- + =Set( + varKeyboard, + Concatenate( + keyboard.Default, + Self.Text + ) + ) + PressedBorderColor: =Self.Fill + PressedColor: =Self.Fill + PressedFill: =Self.Color + RadiusBottomLeft: =6 + RadiusBottomRight: =6 + RadiusTopLeft: =6 + RadiusTopRight: =6 + Size: =20 + Text: =If(varKeyboardMaj=true,Upper(ThisItem.Value),Lower(ThisItem.Value)) + Width: =Parent.TemplateWidth + - img_erase: + Control: Image@2.2.3 + Properties: + BorderColor: =RGBA(0, 18, 107, 1) + Height: =Parent.Height + Image: |- + ="data:image/svg+xml;utf8," & EncodeUrl( + " + + + + + " + ) + ImagePosition: =ImagePosition.Stretch + OnSelect: =If(Len(varKeyboard)>0, Set(varKeyboard,Left(varKeyboard, Len(varKeyboard)-1))) + PaddingBottom: =5 + PaddingLeft: =5 + PaddingTop: =5 + Width: =(Parent.Width-gal_line5.Width)/2 + - cont_line5: + Control: GroupContainer@1.3.0 + Variant: AutoLayout + Properties: + AlignInContainer: =AlignInContainer.SetByContainer + DropShadow: =DropShadow.None + LayoutAlignItems: =LayoutAlignItems.Center + LayoutDirection: =LayoutDirection.Horizontal + LayoutGap: =5 + LayoutJustifyContent: =LayoutJustifyContent.Center + LayoutMinHeight: =0 + Width: =Parent.Width-Parent.PaddingRight-Parent.PaddingLeft + Children: + - btn_spec: + Control: Classic/Button@2.2.0 + Properties: + BorderColor: =ColorFade(Self.Fill, -15%) + BorderThickness: =0 + Color: =Color.Black + DisabledBorderColor: =RGBA(166, 166, 166, 1) + Fill: =RGBA(208, 188, 255, 1) + Font: =Font.'Open Sans' + FontWeight: =FontWeight.Normal + Height: =Parent.Height-gal_line2.TemplatePadding*2-1 + HoverBorderColor: =ColorFade(Self.BorderColor, 20%) + HoverColor: =RGBA(255, 255, 255, 1) + HoverFill: =ColorFade(RGBA(56, 96, 178, 1), -20%) + OnSelect: |- + =Set( + varKeyboardSpec, + Not varKeyboardSpec + ) + PaddingBottom: =10 + PaddingLeft: =10 + PaddingRight: =10 + PaddingTop: =10 + PressedBorderColor: =Self.Fill + PressedColor: =Self.Fill + PressedFill: =Self.Color + RadiusBottomLeft: =20 + RadiusBottomRight: =20 + RadiusTopLeft: =20 + RadiusTopRight: =20 + Size: =14 + Text: =If(varKeyboardSpec=true,"ABC","?#@") + Width: =img_return.Width + - btn_comma: + Control: Classic/Button@2.2.0 + Properties: + BorderColor: =ColorFade(Self.Fill, -15%) + BorderThickness: =0 + Color: =Color.Black + DisabledBorderColor: =RGBA(166, 166, 166, 1) + Fill: =RGBA(247, 242, 250, 1) + Font: =Font.'Open Sans' + FontWeight: =FontWeight.Normal + Height: =Parent.Height-gal_line2.TemplatePadding*2 + HoverBorderColor: =ColorFade(Self.BorderColor, 20%) + HoverColor: =RGBA(255, 255, 255, 1) + HoverFill: =ColorFade(RGBA(56, 96, 178, 1), -20%) + OnSelect: |- + =Set( + varKeyboard, + Concatenate( + keyboard.Default, + Self.Text + ) + ) + PressedBorderColor: =Self.Fill + PressedColor: =Self.Fill + PressedFill: =Self.Color + RadiusBottomLeft: =6 + RadiusBottomRight: =6 + RadiusTopLeft: =6 + RadiusTopRight: =6 + Size: =20 + Text: ="," + Width: =gal_line2.TemplateWidth + - btn_space: + Control: Classic/Button@2.2.0 + Properties: + BorderColor: =ColorFade(Self.Fill, -15%) + BorderThickness: =0 + Color: =Color.Black + DisabledBorderColor: =RGBA(166, 166, 166, 1) + Fill: =RGBA(247, 242, 250, 1) + FillPortions: =1 + Font: =Font.'Open Sans' + FontWeight: =FontWeight.Normal + Height: =Parent.Height-gal_line2.TemplatePadding*2 + HoverBorderColor: =ColorFade(Self.BorderColor, 20%) + HoverColor: =RGBA(255, 255, 255, 1) + HoverFill: =ColorFade(RGBA(56, 96, 178, 1), -20%) + OnSelect: |- + =Set( + varKeyboard, + Concatenate( + keyboard.Default, + Self.Text + ) + ) + PressedBorderColor: =Self.Fill + PressedColor: =Self.Fill + PressedFill: =Self.Color + RadiusBottomLeft: =6 + RadiusBottomRight: =6 + RadiusTopLeft: =6 + RadiusTopRight: =6 + Size: =20 + Text: =" " + Width: =Parent.Width + - btn_dot: + Control: Classic/Button@2.2.0 + Properties: + BorderColor: =ColorFade(Self.Fill, -15%) + BorderThickness: =0 + Color: =Color.Black + DisabledBorderColor: =RGBA(166, 166, 166, 1) + Fill: =RGBA(247, 242, 250, 1) + Font: =Font.'Open Sans' + FontWeight: =FontWeight.Normal + Height: =Parent.Height-gal_line2.TemplatePadding*2 + HoverBorderColor: =ColorFade(Self.BorderColor, 20%) + HoverColor: =RGBA(255, 255, 255, 1) + HoverFill: =ColorFade(RGBA(56, 96, 178, 1), -20%) + OnSelect: |- + =Set( + varKeyboard, + Concatenate( + keyboard.Default, + Self.Text + ) + ) + PressedBorderColor: =Self.Fill + PressedColor: =Self.Fill + PressedFill: =Self.Color + RadiusBottomLeft: =6 + RadiusBottomRight: =6 + RadiusTopLeft: =6 + RadiusTopRight: =6 + Size: =20 + Text: ="." + Width: =gal_line2.TemplateWidth + - img_return: + Control: Image@2.2.3 + Properties: + BorderColor: =RGBA(0, 18, 107, 1) + Height: =Parent.Height + Image: |- + ="data:image/svg+xml;utf8," & EncodeUrl( + " + + + + + " + ) + ImagePosition: =ImagePosition.Stretch + OnSelect: |- + =Set( + varKeyboard, + Concatenate( + keyboard.Default, + " + " + ) + ) + PaddingBottom: =5 + PaddingLeft: =5 + PaddingTop: =5 + Width: =(Parent.Width-gal_line5.Width)/2