diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..a5da09a
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,27 @@
+{
+ "version": "0.2.0",
+ "configurations": [
+ {
+ // Use IntelliSense to find out which attributes exist for C# debugging
+ // Use hover for the description of the existing attributes
+ // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
+ "name": ".NET Core Launch (console)",
+ "type": "coreclr",
+ "request": "launch",
+ "preLaunchTask": "build",
+ // If you have changed target frameworks, make sure to update the program path.
+ "program": "${workspaceFolder}/LanguageGenerator/bin/Debug/net5.0/LanguageGenerator.dll",
+ "args": [],
+ "cwd": "${workspaceFolder}/LanguageGenerator",
+ // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
+ "console": "internalConsole",
+ "stopAtEntry": false
+ },
+ {
+ "name": ".NET Core Attach",
+ "type": "coreclr",
+ "request": "attach",
+ "processId": "${command:pickProcess}"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644
index 0000000..f8a6c20
--- /dev/null
+++ b/.vscode/tasks.json
@@ -0,0 +1,42 @@
+{
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "build",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "build",
+ "${workspaceFolder}/LanguageGenerator/LanguageGenerator.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "publish",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "publish",
+ "${workspaceFolder}/LanguageGenerator/LanguageGenerator.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "watch",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "watch",
+ "run",
+ "${workspaceFolder}/LanguageGenerator/LanguageGenerator.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/LanguageGenerator/LanguageGenerator.csproj b/LanguageGenerator/LanguageGenerator.csproj
new file mode 100644
index 0000000..2082704
--- /dev/null
+++ b/LanguageGenerator/LanguageGenerator.csproj
@@ -0,0 +1,8 @@
+
+
+
+ Exe
+ net5.0
+
+
+
diff --git a/LanguageGenerator/Program.cs b/LanguageGenerator/Program.cs
new file mode 100644
index 0000000..5d2f360
--- /dev/null
+++ b/LanguageGenerator/Program.cs
@@ -0,0 +1,276 @@
+using System.IO;
+using System.Text;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace LanguageGenerator
+{
+ public enum CIRCLESECTION
+ {
+ Right = 0,
+ Bottom = 1,
+ Left = 2,
+ Top = 3
+ }
+ public static class Program
+ {
+ private static readonly char[,] smallCharacters = new char[4, 8]
+ {
+ {'k', 's', 'i', 'n', 'e', 'l', 'a', 't'},
+ {'g', 'b', 'm', 'o', 'z', 'r', 'y', 'v'},
+ {'x', 'p', 'f', 'd', 'j', 'c', 'u', 'h'},
+ {'q', '?', '!', 'w', '@', ',', '.', '\''}
+ };
+ private static readonly char[,] capitalCharacters = new char[4, 8]
+ {
+ {'K', 'S', 'I', 'N', 'E', 'L', 'A', 'T'},
+ {'G', 'B', 'M', 'O', 'Z', 'R', 'Y', 'V'},
+ {'X', 'P', 'F', 'D', 'J', 'C', 'U', 'H'},
+ {'Q', '-', '_', 'W', '*', '/', ':', '\"'}
+ };
+
+ private static readonly string[] upperCaseFlags = new string[] { "1" };
+
+ private const string fileName = "hu_eight_pen_original.xml";
+
+ private static readonly Dictionary diacritics = new()
+ {
+ { 'a', new char[] { 'á' } },
+ { 'e', new char[] { 'é' } },
+ { 'i', new char[] { 'í' } },
+ { 'o', new char[] { 'ó', 'ö', 'ő' } },
+ { 'u', new char[] { 'ú', 'ü', 'ű' } },
+ { 'A', new char[] { 'Á' } },
+ { 'E', new char[] { 'É' } },
+ { 'I', new char[] { 'Í' } },
+ { 'O', new char[] { 'Ó', 'Ö', 'Ő' } },
+ { 'U', new char[] { 'Ú', 'Ü', 'Ű' } },
+ };
+
+ public static void Main()
+ {
+ var keyboardActions = new List();
+ foreach (var (characters, extraLine) in new[] { (smallCharacters, 0), (capitalCharacters, 4) })
+ {
+ for (var x = 0; x < characters.GetLength(0); x++)
+ {
+ for (var y = 0; y < characters.GetLength(1); y++)
+ {
+ keyboardActions.Add(CharToKeyboardAction(characters[x, y], x + extraLine, y));
+ }
+ }
+ }
+
+ foreach (var keyboardAction in new List(keyboardActions))
+ {
+ if (keyboardAction.Content is KeyCodeContent keyCodeContent && diacritics.ContainsKey(keyCodeContent.KeyCode))
+ {
+ var keyCode = keyCodeContent.KeyCode;
+ var diacriticsForChar = diacritics[keyCode];
+ for (var i = 0; i < diacriticsForChar.Length; i++)
+ {
+ var diacritic = diacriticsForChar[i];
+ var (baseMovementSequence, startToLeft) = PositionToMovementSequence(keyCodeContent.Circle, keyCodeContent.Line);
+
+ startToLeft = !startToLeft;
+
+ var movements = new List(baseMovementSequence);
+
+ var currentSection = movements.Last();
+ for (var i2 = 0; i2 < i + 1; i2++)
+ {
+ var nextSection = GetNextSection(currentSection, startToLeft);
+
+ movements.Add(nextSection);
+
+ currentSection = nextSection;
+ }
+
+ keyboardActions.Add(
+ new KeyboardAction(
+ new StringContent(diacritic.ToString()),
+ PositionToMovementSequenceEdges(movements.Select(m => CircleSectionToString(m)))
+ )
+ );
+ }
+ }
+ }
+
+ var generatedOutput = new StringBuilder();
+ foreach (var keyboardAction in keyboardActions)
+ {
+ var keyboardActionsString = $@"
+
+ {keyboardAction.Content.GetActionType()}
+ {string.Join(";", keyboardAction.MovementActions) + ";"}
+ {keyboardAction.Content.GetContent()}{(keyboardAction.Flags.Count > 0 ? $"\n \n {string.Join("\n ", keyboardAction.Flags)}\n " : "")}
+
+";
+
+ generatedOutput.Append(keyboardActionsString);
+ }
+
+ using var writer = File.CreateText(fileName);
+ writer.Write("" + Environment.NewLine);
+ writer.Write(generatedOutput);
+ writer.Write(File.ReadAllText("append.xml"));
+ writer.Write(Environment.NewLine + "");
+ }
+
+ private static KeyboardAction CharToKeyboardAction(char chr, int circle, int line)
+ {
+ var movementActions = PositionToMovementSequenceEdges(circle, line);
+
+ return chr switch
+ {
+ var c when c >= 'a' && c <= 'z' => new KeyboardAction(new KeyCodeContent(c, circle, line), movementActions),
+ var c when c >= 'A' && c <= 'Z' => new KeyboardAction(new KeyCodeContent(c, circle, line), movementActions, upperCaseFlags),
+ /* var c when c == '?' => new KeyboardAction(new StringContent("?"), movementActions),
+ var c when c == '!' => new KeyboardAction(new StringContent("!"), movementActions),
+ var c when c == '@' => new KeyboardAction(new StringContent("@"), movementActions),
+ var c when c == ',' => new KeyboardAction(new StringContent(","), movementActions),
+ var c when c == '.' => new KeyboardAction(new StringContent("."), movementActions),
+ var c when c == '\'' => new KeyboardAction(new StringContent("\'"), movementActions),
+ var c when c == '-' => new KeyboardAction(new StringContent("?"), movementActions),
+ var c when c == '_' => new KeyboardAction(new StringContent("!"), movementActions),
+ var c when c == '*' => new KeyboardAction(new StringContent("@"), movementActions),
+ var c when c == '/' => new KeyboardAction(new StringContent(","), movementActions),
+ var c when c == ':' => new KeyboardAction(new StringContent("."), movementActions),
+ var c when c == '\"' => new KeyboardAction(new StringContent("\'"), movementActions), */
+ var c => new KeyboardAction(new StringContent(c.ToString()), movementActions)
+ //_ => throw new ArgumentException($"Unknown character: '{chr}' ({(int)chr})")
+ };
+ }
+
+ private static List PositionToMovementSequenceEdges(int fakeCircle, int line)
+ {
+ return PositionToMovementSequenceEdges(
+ PositionToMovementSequence(fakeCircle, line)
+ .movements
+ .Select(m => CircleSectionToString(m))
+ );
+ }
+
+ private static List PositionToMovementSequenceEdges(IEnumerable movements)
+ {
+ var allMovements = new List()
+ {
+ "INSIDE_CIRCLE"
+ };
+
+ allMovements.AddRange(movements);
+
+ allMovements.Add("INSIDE_CIRCLE");
+
+ return allMovements;
+ }
+
+ private static (List movements, bool startToLeft) PositionToMovementSequence(int fakeCircle, int line)
+ {
+ var movements = new List();
+
+ var (startPos, startToLeft) = line switch
+ {
+ var l when l == 0 => (CIRCLESECTION.Top, false),
+ var l when l == 1 => (CIRCLESECTION.Right, true),
+ var l when l == 2 => (CIRCLESECTION.Right, false),
+ var l when l == 3 => (CIRCLESECTION.Bottom, true),
+ var l when l == 4 => (CIRCLESECTION.Bottom, false),
+ var l when l == 5 => (CIRCLESECTION.Left, true),
+ var l when l == 6 => (CIRCLESECTION.Left, false),
+ var l when l == 7 => (CIRCLESECTION.Top, true),
+ _ => throw new Exception()
+ };
+
+ movements.Add(startPos);
+
+ var currentSection = startPos;
+ for (var i = 0; i < fakeCircle + 1; i++)
+ {
+ var nextSection = GetNextSection(currentSection, startToLeft);
+
+ movements.Add(nextSection);
+
+ currentSection = nextSection;
+ }
+
+ return (movements, startToLeft);
+ }
+
+ private static CIRCLESECTION GetNextSection(CIRCLESECTION currentSection, bool toLeft) =>
+ currentSection switch
+ {
+ CIRCLESECTION.Top => toLeft ? CIRCLESECTION.Left : CIRCLESECTION.Right,
+ CIRCLESECTION.Right => toLeft ? CIRCLESECTION.Top : CIRCLESECTION.Bottom,
+ CIRCLESECTION.Bottom => toLeft ? CIRCLESECTION.Right : CIRCLESECTION.Left,
+ CIRCLESECTION.Left => toLeft ? CIRCLESECTION.Bottom : CIRCLESECTION.Top,
+ _ => throw new ArgumentException($"Unkown value of {nameof(CIRCLESECTION)}", nameof(currentSection))
+ };
+
+ private static string CircleSectionToString(CIRCLESECTION section) =>
+ section switch
+ {
+ CIRCLESECTION.Top => "TOP",
+ CIRCLESECTION.Right => "RIGHT",
+ CIRCLESECTION.Bottom => "BOTTOM",
+ CIRCLESECTION.Left => "LEFT",
+ _ => throw new ArgumentException($"Unkown value of {nameof(CIRCLESECTION)}", nameof(section))
+ };
+ }
+
+ public class KeyboardAction
+ {
+ public KeyboardAction(IKeyboardContent content, IEnumerable movementActions, IEnumerable flags = null)
+ {
+ if (movementActions is null) throw new ArgumentNullException(nameof(movementActions));
+
+ Content = content;
+ MovementActions.AddRange(movementActions);
+
+ if (flags != null) Flags.AddRange(flags);
+ }
+
+ public IKeyboardContent Content { get; }
+ public List Flags { get; } = new List();
+ public List MovementActions { get; } = new List();
+ }
+
+ public interface IKeyboardContent
+ {
+ string GetContent();
+ string GetActionType();
+ }
+
+ public class KeyCodeContent : IKeyboardContent
+ {
+ public KeyCodeContent(char keyCode, int circle, int line)
+ {
+ KeyCode = keyCode;
+ KeyCodeText = "KEYCODE_" + keyCode.ToString().ToUpper();
+ Circle = circle;
+ Line = line;
+ }
+
+ public string KeyCodeText { get; }
+ public char KeyCode { get; }
+ public int Circle { get; }
+ public int Line { get; }
+
+ public string GetContent() => $"{KeyCodeText}";
+ public string GetActionType() =>"INPUT_KEY";
+ }
+
+ public class StringContent : IKeyboardContent
+ {
+ public StringContent(string content)
+ {
+ Content = content;
+ }
+
+ public string Content { get; }
+
+ public string GetContent() => $"{Content}";
+ public string GetActionType() => "INPUT_TEXT";
+ }
+}
diff --git a/LanguageGenerator/append.xml b/LanguageGenerator/append.xml
new file mode 100644
index 0000000..900828d
--- /dev/null
+++ b/LanguageGenerator/append.xml
@@ -0,0 +1,6 @@
+
+
+ INPUT_TEXT
+ INSIDE_CIRCLE;BOTTOM;LEFT;TOP;RIGHT;BOTTOM;LEFT;TOP;RIGHT;BOTTOM;INSIDE_CIRCLE;
+ kovacsadam07@outlook.hu
+
\ No newline at end of file