using System; using System.Drawing; using System.Globalization; using CC_Functions.Commandline; using CC_Functions.Commandline.TUI; using CC_Functions.Core; using D = CC_Functions.Commandline.DiffDraw; namespace OnScreenKeyboard { class Program { private const string Keyboard = "qwertyuiop\nasdfghjkl_\nzxcvbnm,.-"; private const int Width = 10 * 3; private const int Height = 4; private static Point _ball = new Point(0, Height - 1); private static Point _ballSpeed = new Point(1, -1); private static int _peddle = 0; private static string _input = ""; static void Main(string[] a) { ArgsParse args = new ArgsParse(a); //args if (args.GetBool("help") || args.GetBool("?") || args.GetBool("h")) { Console.WriteLine(@"JF OSK v1 Shows an interactive keyboard (stdout and stdin) and logs the output to stderr Usage: OSK [arguments] Arguments: delay The time to wait between ball movements. no-color Do not output color. Use only if color doesn't work. peddle-length The length of the peddle. Examples: OSK --delay:0.3 --peddle-length:3 OSK --no-color OSK 2> output.txt"); return; } TimeSpan ballSpeed = args.Get("delay", s => s == null ? new TimeSpan(0, 0, 1) : TimeSpan.Parse($"0:0:0:{s}", CultureInfo.InvariantCulture)); bool color = !args.GetBool("no-color"); int peddleLength = args.Get("peddle-length", s => s == null ? 4 : int.Parse(s, CultureInfo.InvariantCulture)); if (peddleLength > Width) peddleLength = Width; //init Console.BackgroundColor = ConsoleColor.Black; Console.ForegroundColor = ConsoleColor.White; Console.Clear(); bool playing = true; DateTime lastGameTick = DateTime.Now; while (playing) { //Process input bool left = false; bool right = false; bool select = false; while (Console.KeyAvailable) { switch (Console.ReadKey().Key) { case ConsoleKey.LeftArrow: case ConsoleKey.A: left = true; break; case ConsoleKey.RightArrow: case ConsoleKey.D: right = true; break; case ConsoleKey.W: case ConsoleKey.S: case ConsoleKey.UpArrow: case ConsoleKey.DownArrow: case ConsoleKey.Spacebar: case ConsoleKey.Enter: select = true; break; case ConsoleKey.Escape: playing = false; break; } } //Move peddle if (left) _peddle--; if (right) _peddle++; if (_peddle < 0) _peddle = 0; if (_peddle > Width - peddleLength) _peddle = Width - peddleLength; //Scheduled game tick if (lastGameTick + ballSpeed - DateTime.Now <= TimeSpan.Zero) { lastGameTick = DateTime.Now; //Move ball ball: _ball = new Point(_ball.X + _ballSpeed.X, _ball.Y + _ballSpeed.Y); if (_ball.X == 0 || _ball.X == Width - 1) _ballSpeed = new Point(-_ballSpeed.X, _ballSpeed.Y); if (_ball.Y == 0) _ballSpeed = new Point(_ballSpeed.X, -_ballSpeed.Y); if (_ball.Y == Height - 1 && _ball.X >= _peddle && _ball.X < _peddle + peddleLength) { if (_ball.X > 0 && _ball.X < Width - 1) _ball.X -= _ballSpeed.X; _ball.Y -= 1; _ballSpeed = new Point(_ballSpeed.X, -_ballSpeed.Y); goto ball; } if (_ball.Y == Height) playing = false; } //Post-input pre-draw stuff if (!playing) continue; Pixel[,] empty = new Pixel[Height, Width]; empty.Populate(new Pixel(' ')); D.Clear(empty); //Draw keyboard and add to output. Combined one to avoid major code duplication int y = 0; int sub = 0; for (int i = 0; i < Keyboard.Length; i++) { char t = Keyboard[i]; if (t == '\n') { y++; sub = i + 1; } else { Point start = new Point((i - sub) * 3, y); bool selected = _ball.Y == start.Y && _ball.X >= start.X && _ball.X < start.X + 3; if (selected && select) _input += t; DrawString(start, $" {t} ", selected ? Console.BackgroundColor : Console.ForegroundColor, selected ? Console.ForegroundColor : Console.BackgroundColor); } } //Draw ball D.Set(_ball, new Pixel(Console.ForegroundColor, Console.BackgroundColor, 'X')); //Draw paddle DrawString(new Point(_peddle, Height - 1), new string('█', peddleLength), Console.ForegroundColor, Console.BackgroundColor); //Finish frame D.Draw(color); Console.CursorLeft = 0; Console.CursorTop = Height; Console.Write(_input); } Console.ResetColor(); Console.Clear(); Console.Error.WriteLine(_input); } private static void DrawString(Point start, string chars, ConsoleColor foreColor, ConsoleColor backColor) { foreach (string s in chars.Split('\n')) for (int i = 0; i < s.Length; i++) { char t = s[i]; D.Set(start.X + i, start.Y, new Pixel(backColor, foreColor, t)); } } } }