diff --git a/Compile.ps1 b/Compile.ps1
index 1bb5b03f..4e5cc278 100644
--- a/Compile.ps1
+++ b/Compile.ps1
@@ -1,6 +1,9 @@
$OFS = "`r`n"
$scriptname = "winutil.ps1"
-
+# Variable to sync between runspaces
+$sync = [Hashtable]::Synchronized(@{})
+$sync.PSScriptRoot = $PSScriptRoot
+$sync.configs = @{}
if (Test-Path -Path "$($scriptname)")
{
@@ -21,15 +24,24 @@ Get-ChildItem .\functions -Recurse -File | ForEach-Object {
Get-Content $psitem.FullName | Out-File ./$scriptname -Append -Encoding ascii
}
-Get-ChildItem .\xaml | ForEach-Object {
- $xaml = (Get-Content $psitem.FullName).replace("'","''")
- Write-output "`$$($psitem.BaseName) = '$xaml'" | Out-File ./$scriptname -Append -Encoding ascii
-}
+$xaml = (Get-Content .\xaml\inputXML.xaml).replace("'","''")
+Write-output "`$inputXML = '$xaml'" | Out-File ./$scriptname -Append -Encoding ascii
Get-ChildItem .\config | Where-Object {$psitem.extension -eq ".json"} | ForEach-Object {
$json = (Get-Content $psitem.FullName).replace("'","''")
-
+ $sync.configs.$($psitem.BaseName) = $json | convertfrom-json
Write-output "`$sync.configs.$($psitem.BaseName) = '$json' `| convertfrom-json" | Out-File ./$scriptname -Append -Encoding ascii
}
-Get-Content .\scripts\main.ps1 | Out-File ./$scriptname -Append -Encoding ascii
+# Dot-source the Get-TabXaml function
+. .\functions\private\Get-TabXaml.ps1
+
+## Xaml Manipulation
+$tabColumns = Get-TabXaml "applications" 5
+$tabColumns | Out-File -FilePath ".\xaml\inputApp.xaml" -Encoding ascii
+$tabColumns = Get-TabXaml "tweaks"
+$tabColumns | Out-File -FilePath ".\xaml\inputTweaks.xaml" -Encoding ascii
+$tabColumns = Get-TabXaml "feature"
+$tabColumns | Out-File -FilePath ".\xaml\inputFeatures.xaml" -Encoding ascii
+
+Get-Content .\scripts\main.ps1 | Out-File ./$scriptname -Append -Encoding ascii
\ No newline at end of file
diff --git a/config/applications.json b/config/applications.json
index 29f505c3..7cd07eb2 100755
--- a/config/applications.json
+++ b/config/applications.json
@@ -324,7 +324,7 @@
"choco": "devToys",
"content": "Devtoys",
"description": "Devtoys is a collection of development-related utilities and tools for Windows. It includes tools for file management, code formatting, and productivity enhancements for developers.",
- "link": "https://dev.to/devtoys",
+ "link": "https://devtoys.app/",
"winget": "devtoys"
},
"WPFInstalldigikam": {
@@ -1108,7 +1108,7 @@
"choco": "na",
"content": "Neofetch",
"description": "Neofetch is a command-line utility for displaying system information in a visually appealing way.",
- "link": "https://github.com/dylanaraps/neofetch",
+ "link": "https://github.com/nepnep39/neofetch-win",
"winget": "nepnep.neofetch-win"
},
"WPFInstallneovim": {
diff --git a/functions/private/Get-TabXaml.ps1 b/functions/private/Get-TabXaml.ps1
new file mode 100644
index 00000000..a420e344
--- /dev/null
+++ b/functions/private/Get-TabXaml.ps1
@@ -0,0 +1,125 @@
+function Get-TabXaml {
+ <#
+ .SYNOPSIS
+ Generates XAML for a tab in the WinUtil GUI
+ This function is used to generate the XAML for the applications tab in the WinUtil GUI
+ It takes the tabname and the number of columns to display the applications in as input and returns the XAML for the tab as output
+ .PARAMETER tabname
+ The name of the tab to generate XAML for
+ .PARAMETER columncount
+ The number of columns to display the applications in
+ .OUTPUTS
+ The XAML for the tab
+ .EXAMPLE
+ Get-TabXaml "applications" 3
+ #>
+
+
+ param( [Parameter(Mandatory=$true)]
+ $tabname,
+ $columncount = 0
+ )
+ $organizedData = @{}
+ # Iterate through JSON data and organize by panel and category
+ foreach ($appName in $sync.configs.$tabname.PSObject.Properties.Name) {
+ $appInfo = $sync.configs.$tabname.$appName
+
+ # Create an object for the application
+ $appObject = [PSCustomObject]@{
+ Name = $appName
+ Category = $appInfo.Category
+ Content = $appInfo.Content
+ Choco = $appInfo.choco
+ Winget = $appInfo.winget
+ Panel = if ($columncount -gt 0 ) { "0" } else {$appInfo.panel}
+ Link = $appInfo.link
+ Description = $appInfo.description
+ # Type is (Checkbox,Toggle,Button,Combobox ) (Default is Checkbox)
+ Type = $appInfo.type
+ ComboItems = $appInfo.ComboItems
+ # Checked is the property to set startup checked status of checkbox (Default is false)
+ Checked = $appInfo.Checked
+ }
+
+ if (-not $organizedData.ContainsKey($appObject.panel)) {
+ $organizedData[$appObject.panel] = @{}
+ }
+
+ if (-not $organizedData[$appObject.panel].ContainsKey($appObject.Category)) {
+ $organizedData[$appObject.panel][$appObject.Category] = @{}
+ }
+
+ # Store application data in a sub-array under the category
+ # Add Order property to keep the original order of tweaks and features
+ $organizedData[$appObject.panel][$appInfo.Category]["$($appInfo.order)$appName"] = $appObject
+ }
+ $panelcount=0
+ $paneltotal = $organizedData.Keys.Count
+ if ($columncount -gt 0) {
+ $appcount = $sync.configs.$tabname.PSObject.Properties.Name.count + $organizedData["0"].Keys.count
+ $maxcount = [Math]::Round( $appcount / $columncount + 0.5)
+ $paneltotal = $columncount
+ }
+ # add ColumnDefinitions to evenly draw colums
+ $blockXml="`n"+("`n"*($paneltotal))+"`n"
+ # Iterate through organizedData by panel, category, and application
+ $count = 0
+ foreach ($panel in ($organizedData.Keys | Sort-Object)) {
+ $blockXml += "`n`n"
+ $panelcount++
+ foreach ($category in ($organizedData[$panel].Keys | Sort-Object)) {
+ $count++
+ if ($columncount -gt 0) {
+ $panelcount2 = [Int](($count)/$maxcount-0.5)
+ if ($panelcount -eq $panelcount2 ) {
+ $blockXml +="`n`n`n"
+ $blockXml += "`n`n"
+ $panelcount++
+ }
+ }
+ $blockXml += "`n"
+ $sortedApps = $organizedData[$panel][$category].Keys | Sort-Object
+ foreach ($appName in $sortedApps) {
+ $count++
+ if ($columncount -gt 0) {
+ $panelcount2 = [Int](($count)/$maxcount-0.5)
+ if ($panelcount -eq $panelcount2 ) {
+ $blockXml +="`n`n`n"
+ $blockXml += "`n`n"
+ $panelcount++
+ }
+ }
+ $appInfo = $organizedData[$panel][$category][$appName]
+ if ("Toggle" -eq $appInfo.Type) {
+ $blockXml += "`n`n"
+ $blockXml += "`n`n"
+ } elseif ("Combobox" -eq $appInfo.Type) {
+ $blockXml += "`n"
+ # If it is a digit, type is button and button length is digits
+ } elseif ($appInfo.Type -match "^[\d\.]+$") {
+ $blockXml += "`n"
+ # else it is a checkbox
+ } else {
+ $checkedStatus = If ($null -eq $appInfo.Checked) {""} Else {"IsChecked=`"$($appInfo.Checked)`" "}
+ if ($null -eq $appInfo.Link)
+ {
+ $blockXml += "`n"
+ }
+ else
+ {
+ $blockXml += "`n`n`n"
+ }
+ }
+ }
+ }
+ $blockXml +="`n`n`n"
+ }
+ return ($blockXml)
+}
diff --git a/functions/public/Invoke-WPFButton.ps1 b/functions/public/Invoke-WPFButton.ps1
index 3bd0428f..7fa8638a 100644
--- a/functions/public/Invoke-WPFButton.ps1
+++ b/functions/public/Invoke-WPFButton.ps1
@@ -47,7 +47,7 @@ function Invoke-WPFButton {
"WPFFixesNetwork" {Invoke-WPFFixesNetwork}
"WPFUpdatesdisable" {Invoke-WPFUpdatesdisable}
"WPFUpdatessecurity" {Invoke-WPFUpdatessecurity}
- "WPFWinUtilShortcut" {Invoke-WPFShortcut -ShortcutToAdd "WinUtil"}
+ "WPFWinUtilShortcut" {Invoke-WPFShortcut -ShortcutToAdd "WinUtil" -RunAsAdmin $true}
"WPFGetInstalled" {Invoke-WPFGetInstalled -CheckBox "winget"}
"WPFGetInstalledTweaks" {Invoke-WPFGetInstalled -CheckBox "tweaks"}
"WPFGetIso" {Invoke-WPFGetIso}
diff --git a/functions/public/Invoke-WPFShortcut.ps1 b/functions/public/Invoke-WPFShortcut.ps1
index f195ca9a..4eab2dc6 100644
--- a/functions/public/Invoke-WPFShortcut.ps1
+++ b/functions/public/Invoke-WPFShortcut.ps1
@@ -8,8 +8,14 @@ function Invoke-WPFShortcut {
.PARAMETER ShortcutToAdd
The name of the shortcut to add
+ .PARAMETER RunAsAdmin
+ A boolean value to make 'Run as administrator' property on (true) or off (false), defaults to off
+
#>
- param($ShortcutToAdd)
+ param(
+ $ShortcutToAdd,
+ [bool]$RunAsAdmin = $false
+ )
$iconPath = $null
Switch ($ShortcutToAdd) {
@@ -42,5 +48,12 @@ function Invoke-WPFShortcut {
}
$Shortcut.Save()
- Write-Host "Shortcut for $ShortcutToAdd has been saved to $($FileBrowser.FileName)"
+ if ($RunAsAdmin -eq $true) {
+ $bytes = [System.IO.File]::ReadAllBytes($FileBrowser.FileName)
+ # Set byte value at position 0x15 in hex, or 21 in decimal, from the value 0x00 to 0x20 in hex
+ $bytes[0x15] = $bytes[0x15] -bor 0x20
+ [System.IO.File]::WriteAllBytes($FileBrowser.FileName, $bytes)
+ }
+
+ Write-Host "Shortcut for $ShortcutToAdd has been saved to $($FileBrowser.FileName) with 'Run as administrator' set to $RunAsAdmin"
}
\ No newline at end of file
diff --git a/scripts/main.ps1 b/scripts/main.ps1
index 7549acaf..16151242 100644
--- a/scripts/main.ps1
+++ b/scripts/main.ps1
@@ -52,122 +52,21 @@ $sync.runspace.Open()
$inputXML = $inputXML -replace 'mc:Ignorable="d"', '' -replace "x:N", 'N' -replace '^`n"+("`n"*($paneltotal))+"`n"
- # Iterate through organizedData by panel, category, and application
- $count = 0
- foreach ($panel in ($organizedData.Keys | Sort-Object)) {
- $blockXml += "`n`n"
- $panelcount++
- foreach ($category in ($organizedData[$panel].Keys | Sort-Object)) {
- $count++
- if ($columncount -gt 0) {
- $panelcount2 = [Int](($count)/$maxcount-0.5)
- if ($panelcount -eq $panelcount2 ) {
- $blockXml +="`n`n`n"
- $blockXml += "`n`n"
- $panelcount++
- }
- }
- $blockXml += "`n"
- $sortedApps = $organizedData[$panel][$category].Keys | Sort-Object
- foreach ($appName in $sortedApps) {
- $count++
- if ($columncount -gt 0) {
- $panelcount2 = [Int](($count)/$maxcount-0.5)
- if ($panelcount -eq $panelcount2 ) {
- $blockXml +="`n`n`n"
- $blockXml += "`n`n"
- $panelcount++
- }
- }
- $appInfo = $organizedData[$panel][$category][$appName]
- if ("Toggle" -eq $appInfo.Type) {
- $blockXml += "`n`n"
- $blockXml += "`n`n"
- } elseif ("Combobox" -eq $appInfo.Type) {
- $blockXml += "`n"
- # If it is a digit, type is button and button length is digits
- } elseif ($appInfo.Type -match "^[\d\.]+$") {
- $blockXml += "`n"
- # else it is a checkbox
- } else {
- $checkedStatus = If ($null -eq $appInfo.Checked) {""} Else {"IsChecked=`"$($appInfo.Checked)`" "}
- if ($null -eq $appInfo.Link)
- {
- $blockXml += "`n"
- }
- else
- {
- $blockXml += "`n`n`n"
- }
- }
- }
- }
- $blockXml +="`n`n`n"
- }
- return ($blockXml)
-}
-
-$tabcolums=Get-TabXaml "applications" 5
-$inputXML = $inputXML -replace "{{InstallPanel_applications}}", ($tabcolums)
-$tabcolums=Get-TabXaml "tweaks"
-$inputXML = $inputXML -replace "{{InstallPanel_tweaks}}", ($tabcolums)
-$tabcolums=Get-TabXaml "feature"
-$inputXML = $inputXML -replace "{{InstallPanel_features}}", ($tabcolums)
if ((Get-WinUtilToggleStatus WPFToggleDarkMode) -eq $True) {
$ctttheme = 'Matrix'
diff --git a/winutil.ps1 b/winutil.ps1
index 2ec7e27d..30d5b78d 100644
--- a/winutil.ps1
+++ b/winutil.ps1
@@ -10,7 +10,7 @@
Author : Chris Titus @christitustech
Runspace Author: @DeveloperDurp
GitHub : https://github.com/ChrisTitusTech
- Version : 24.02.20
+ Version : 24.02.22
#>
param (
[switch]$Debug,
@@ -47,7 +47,7 @@ Add-Type -AssemblyName System.Windows.Forms
# Variable to sync between runspaces
$sync = [Hashtable]::Synchronized(@{})
$sync.PSScriptRoot = $PSScriptRoot
-$sync.version = "24.02.20"
+$sync.version = "24.02.22"
$sync.configs = @{}
$sync.ProcessRunning = $false
@@ -258,6 +258,131 @@ function Get-Oscdimg {
Write-Host "Hashes do not match. File may be corrupted or tampered with."
}
}
+function Get-TabXaml {
+ <#
+ .SYNOPSIS
+ Generates XAML for a tab in the WinUtil GUI
+ This function is used to generate the XAML for the applications tab in the WinUtil GUI
+ It takes the tabname and the number of columns to display the applications in as input and returns the XAML for the tab as output
+ .PARAMETER tabname
+ The name of the tab to generate XAML for
+ .PARAMETER columncount
+ The number of columns to display the applications in
+ .OUTPUTS
+ The XAML for the tab
+ .EXAMPLE
+ Get-TabXaml "applications" 3
+ #>
+
+
+ param( [Parameter(Mandatory=$true)]
+ $tabname,
+ $columncount = 0
+ )
+ $organizedData = @{}
+ # Iterate through JSON data and organize by panel and category
+ foreach ($appName in $sync.configs.$tabname.PSObject.Properties.Name) {
+ $appInfo = $sync.configs.$tabname.$appName
+
+ # Create an object for the application
+ $appObject = [PSCustomObject]@{
+ Name = $appName
+ Category = $appInfo.Category
+ Content = $appInfo.Content
+ Choco = $appInfo.choco
+ Winget = $appInfo.winget
+ Panel = if ($columncount -gt 0 ) { "0" } else {$appInfo.panel}
+ Link = $appInfo.link
+ Description = $appInfo.description
+ # Type is (Checkbox,Toggle,Button,Combobox ) (Default is Checkbox)
+ Type = $appInfo.type
+ ComboItems = $appInfo.ComboItems
+ # Checked is the property to set startup checked status of checkbox (Default is false)
+ Checked = $appInfo.Checked
+ }
+
+ if (-not $organizedData.ContainsKey($appObject.panel)) {
+ $organizedData[$appObject.panel] = @{}
+ }
+
+ if (-not $organizedData[$appObject.panel].ContainsKey($appObject.Category)) {
+ $organizedData[$appObject.panel][$appObject.Category] = @{}
+ }
+
+ # Store application data in a sub-array under the category
+ # Add Order property to keep the original order of tweaks and features
+ $organizedData[$appObject.panel][$appInfo.Category]["$($appInfo.order)$appName"] = $appObject
+ }
+ $panelcount=0
+ $paneltotal = $organizedData.Keys.Count
+ if ($columncount -gt 0) {
+ $appcount = $sync.configs.$tabname.PSObject.Properties.Name.count + $organizedData["0"].Keys.count
+ $maxcount = [Math]::Round( $appcount / $columncount + 0.5)
+ $paneltotal = $columncount
+ }
+ # add ColumnDefinitions to evenly draw colums
+ $blockXml="`n"+("`n"*($paneltotal))+"`n"
+ # Iterate through organizedData by panel, category, and application
+ $count = 0
+ foreach ($panel in ($organizedData.Keys | Sort-Object)) {
+ $blockXml += "`n`n"
+ $panelcount++
+ foreach ($category in ($organizedData[$panel].Keys | Sort-Object)) {
+ $count++
+ if ($columncount -gt 0) {
+ $panelcount2 = [Int](($count)/$maxcount-0.5)
+ if ($panelcount -eq $panelcount2 ) {
+ $blockXml +="`n`n`n"
+ $blockXml += "`n`n"
+ $panelcount++
+ }
+ }
+ $blockXml += "`n"
+ $sortedApps = $organizedData[$panel][$category].Keys | Sort-Object
+ foreach ($appName in $sortedApps) {
+ $count++
+ if ($columncount -gt 0) {
+ $panelcount2 = [Int](($count)/$maxcount-0.5)
+ if ($panelcount -eq $panelcount2 ) {
+ $blockXml +="`n`n`n"
+ $blockXml += "`n`n"
+ $panelcount++
+ }
+ }
+ $appInfo = $organizedData[$panel][$category][$appName]
+ if ("Toggle" -eq $appInfo.Type) {
+ $blockXml += "`n`n"
+ $blockXml += "`n`n"
+ } elseif ("Combobox" -eq $appInfo.Type) {
+ $blockXml += "`n"
+ # If it is a digit, type is button and button length is digits
+ } elseif ($appInfo.Type -match "^[\d\.]+$") {
+ $blockXml += "`n"
+ # else it is a checkbox
+ } else {
+ $checkedStatus = If ($null -eq $appInfo.Checked) {""} Else {"IsChecked=`"$($appInfo.Checked)`" "}
+ if ($null -eq $appInfo.Link)
+ {
+ $blockXml += "`n"
+ }
+ else
+ {
+ $blockXml += "`n`n`n"
+ }
+ }
+ }
+ }
+ $blockXml +="`n`n`n"
+ }
+ return ($blockXml)
+}
Function Get-WinUtilCheckBoxes {
<#
@@ -2414,7 +2539,7 @@ function Invoke-WPFButton {
"WPFFixesNetwork" {Invoke-WPFFixesNetwork}
"WPFUpdatesdisable" {Invoke-WPFUpdatesdisable}
"WPFUpdatessecurity" {Invoke-WPFUpdatessecurity}
- "WPFWinUtilShortcut" {Invoke-WPFShortcut -ShortcutToAdd "WinUtil"}
+ "WPFWinUtilShortcut" {Invoke-WPFShortcut -ShortcutToAdd "WinUtil" -RunAsAdmin $true}
"WPFGetInstalled" {Invoke-WPFGetInstalled -CheckBox "winget"}
"WPFGetInstalledTweaks" {Invoke-WPFGetInstalled -CheckBox "tweaks"}
"WPFGetIso" {Invoke-WPFGetIso}
@@ -3839,8 +3964,14 @@ function Invoke-WPFShortcut {
.PARAMETER ShortcutToAdd
The name of the shortcut to add
+ .PARAMETER RunAsAdmin
+ A boolean value to make 'Run as administrator' property on (true) or off (false), defaults to off
+
#>
- param($ShortcutToAdd)
+ param(
+ $ShortcutToAdd,
+ [bool]$RunAsAdmin = $false
+ )
$iconPath = $null
Switch ($ShortcutToAdd) {
@@ -3873,7 +4004,14 @@ function Invoke-WPFShortcut {
}
$Shortcut.Save()
- Write-Host "Shortcut for $ShortcutToAdd has been saved to $($FileBrowser.FileName)"
+ if ($RunAsAdmin -eq $true) {
+ $bytes = [System.IO.File]::ReadAllBytes($FileBrowser.FileName)
+ # Set byte value at position 0x15 in hex, or 21 in decimal, from the value 0x00 to 0x20 in hex
+ $bytes[0x15] = $bytes[0x15] -bor 0x20
+ [System.IO.File]::WriteAllBytes($FileBrowser.FileName, $bytes)
+ }
+
+ Write-Host "Shortcut for $ShortcutToAdd has been saved to $($FileBrowser.FileName) with 'Run as administrator' set to $RunAsAdmin"
}
function Invoke-WPFTab {
@@ -4453,7 +4591,7 @@ function Invoke-WPFUpdatessecurity {
Write-Host "-- Updates Set to Recommended ---"
Write-Host "================================="
}
-$inputXML = '`n"+("`n"*($paneltotal))+"`n"
- # Iterate through organizedData by panel, category, and application
- $count = 0
- foreach ($panel in ($organizedData.Keys | Sort-Object)) {
- $blockXml += "`n`n"
- $panelcount++
- foreach ($category in ($organizedData[$panel].Keys | Sort-Object)) {
- $count++
- if ($columncount -gt 0) {
- $panelcount2 = [Int](($count)/$maxcount-0.5)
- if ($panelcount -eq $panelcount2 ) {
- $blockXml +="`n`n`n"
- $blockXml += "`n`n"
- $panelcount++
- }
- }
- $blockXml += "`n"
- $sortedApps = $organizedData[$panel][$category].Keys | Sort-Object
- foreach ($appName in $sortedApps) {
- $count++
- if ($columncount -gt 0) {
- $panelcount2 = [Int](($count)/$maxcount-0.5)
- if ($panelcount -eq $panelcount2 ) {
- $blockXml +="`n`n`n"
- $blockXml += "`n`n"
- $panelcount++
- }
- }
- $appInfo = $organizedData[$panel][$category][$appName]
- if ("Toggle" -eq $appInfo.Type) {
- $blockXml += "`n`n"
- $blockXml += "`n`n"
- } elseif ("Combobox" -eq $appInfo.Type) {
- $blockXml += "`n"
- # If it is a digit, type is button and button length is digits
- } elseif ($appInfo.Type -match "^[\d\.]+$") {
- $blockXml += "`n"
- # else it is a checkbox
- } else {
- $checkedStatus = If ($null -eq $appInfo.Checked) {""} Else {"IsChecked=`"$($appInfo.Checked)`" "}
- if ($null -eq $appInfo.Link)
- {
- $blockXml += "`n"
- }
- else
- {
- $blockXml += "`n`n`n"
- }
- }
- }
- }
- $blockXml +="`n`n`n"
- }
- return ($blockXml)
-}
-
-$tabcolums=Get-TabXaml "applications" 5
-$inputXML = $inputXML -replace "{{InstallPanel_applications}}", ($tabcolums)
-$tabcolums=Get-TabXaml "tweaks"
-$inputXML = $inputXML -replace "{{InstallPanel_tweaks}}", ($tabcolums)
-$tabcolums=Get-TabXaml "feature"
-$inputXML = $inputXML -replace "{{InstallPanel_features}}", ($tabcolums)
if ((Get-WinUtilToggleStatus WPFToggleDarkMode) -eq $True) {
$ctttheme = 'Matrix'
diff --git a/xaml/inputApp.xaml b/xaml/inputApp.xaml
new file mode 100644
index 00000000..fc9c5f1e
--- /dev/null
+++ b/xaml/inputApp.xaml
@@ -0,0 +1,894 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/xaml/inputFeatures.xaml b/xaml/inputFeatures.xaml
new file mode 100644
index 00000000..c57704c6
--- /dev/null
+++ b/xaml/inputFeatures.xaml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/xaml/inputTweaks.xaml b/xaml/inputTweaks.xaml
new file mode 100644
index 00000000..5b8bbe0a
--- /dev/null
+++ b/xaml/inputTweaks.xaml
@@ -0,0 +1,94 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+