From 4605d2dab72d034dff372421f49001a9086dda68 Mon Sep 17 00:00:00 2001
From: Allen Wolf <63997543+aaw3@users.noreply.github.com>
Date: Wed, 10 Jan 2024 23:06:50 -0600
Subject: [PATCH] Add project

---
 src/App.config                       |    6 +
 src/Form1.Designer.cs                |   89 ++
 src/Form1.cs                         |  952 ++++++++++++++
 src/Form1.resx                       |  120 ++
 src/Form2.Designer.cs                |   51 +
 src/Form2.cs                         |   25 +
 src/Form2.resx                       |  120 ++
 src/FormNowControlCenter.Designer.cs |  281 +++++
 src/FormNowControlCenter.cs          |  321 +++++
 src/FormNowControlCenter.resx        |  120 ++
 src/KeyboardLock.cs                  | 1733 ++++++++++++++++++++++++++
 src/Program.cs                       |   22 +
 src/Properties/AssemblyInfo.cs       |   38 +
 src/Properties/Resources.Designer.cs |   63 +
 src/Properties/Resources.resx        |  117 ++
 src/Properties/Settings.Designer.cs  |   26 +
 src/Properties/Settings.settings     |    7 +
 src/TeamViewerController.csproj      |  125 ++
 src/TeamViewerController.sln         |   25 +
 src/packages.config                  |    4 +
 20 files changed, 4245 insertions(+)
 create mode 100755 src/App.config
 create mode 100755 src/Form1.Designer.cs
 create mode 100755 src/Form1.cs
 create mode 100755 src/Form1.resx
 create mode 100755 src/Form2.Designer.cs
 create mode 100755 src/Form2.cs
 create mode 100755 src/Form2.resx
 create mode 100755 src/FormNowControlCenter.Designer.cs
 create mode 100755 src/FormNowControlCenter.cs
 create mode 100755 src/FormNowControlCenter.resx
 create mode 100755 src/KeyboardLock.cs
 create mode 100755 src/Program.cs
 create mode 100755 src/Properties/AssemblyInfo.cs
 create mode 100755 src/Properties/Resources.Designer.cs
 create mode 100755 src/Properties/Resources.resx
 create mode 100755 src/Properties/Settings.Designer.cs
 create mode 100755 src/Properties/Settings.settings
 create mode 100755 src/TeamViewerController.csproj
 create mode 100755 src/TeamViewerController.sln
 create mode 100755 src/packages.config

diff --git a/src/App.config b/src/App.config
new file mode 100755
index 0000000..5754728
--- /dev/null
+++ b/src/App.config
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+    <startup> 
+        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
+    </startup>
+</configuration>
\ No newline at end of file
diff --git a/src/Form1.Designer.cs b/src/Form1.Designer.cs
new file mode 100755
index 0000000..342bb23
--- /dev/null
+++ b/src/Form1.Designer.cs
@@ -0,0 +1,89 @@
+namespace TeamViewerController
+{
+    partial class Form1
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            this.label1 = new System.Windows.Forms.Label();
+            this.button1 = new System.Windows.Forms.Button();
+            this.textBox1 = new System.Windows.Forms.TextBox();
+            this.SuspendLayout();
+            // 
+            // label1
+            // 
+            this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 20.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.label1.Location = new System.Drawing.Point(261, 9);
+            this.label1.Name = "label1";
+            this.label1.Size = new System.Drawing.Size(232, 51);
+            this.label1.TabIndex = 0;
+            this.label1.Text = "Access Type";
+            this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+            // 
+            // button1
+            // 
+            this.button1.Location = new System.Drawing.Point(450, 63);
+            this.button1.Name = "button1";
+            this.button1.Size = new System.Drawing.Size(83, 39);
+            this.button1.TabIndex = 1;
+            this.button1.Text = "Submit";
+            this.button1.UseVisualStyleBackColor = true;
+            this.button1.Click += new System.EventHandler(this.button1_Click);
+            // 
+            // textBox1
+            // 
+            this.textBox1.Font = new System.Drawing.Font("Microsoft Sans Serif", 20.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.textBox1.Location = new System.Drawing.Point(313, 63);
+            this.textBox1.Name = "textBox1";
+            this.textBox1.Text = "Install 1.0";
+            this.textBox1.Size = new System.Drawing.Size(131, 38);
+            this.textBox1.TabIndex = 2;
+            this.textBox1.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
+            // 
+            // Form1
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.ClientSize = new System.Drawing.Size(800, 450);
+            this.Controls.Add(this.textBox1);
+            this.Controls.Add(this.button1);
+            this.Controls.Add(this.label1);
+            this.Name = "Form1";
+            this.Text = "Install Remote Access";
+            this.Load += new System.EventHandler(this.Form1_Load);
+            this.ResumeLayout(false);
+            this.PerformLayout();
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.Label label1;
+        private System.Windows.Forms.Button button1;
+        private System.Windows.Forms.TextBox textBox1;
+    }
+}
+
diff --git a/src/Form1.cs b/src/Form1.cs
new file mode 100755
index 0000000..954716f
--- /dev/null
+++ b/src/Form1.cs
@@ -0,0 +1,952 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Net;
+using System.Net.Sockets;
+using System.Diagnostics;
+using System.Net.NetworkInformation;
+using Open.Nat;
+using System.Threading;
+using System.Windows.Forms;
+using System.IO;
+using System.ComponentModel;
+using System.Drawing.Imaging;
+using System.Drawing;
+using Microsoft.Win32;
+using System.Runtime.InteropServices;
+using KeyboardHookMain;
+
+namespace TeamViewerController
+{
+    public partial class Form1 : Form
+    {
+
+
+
+        public static TcpClient client;
+        public static TcpListener listener;
+        public static string IPstring;
+        public static IPEndPoint ipEP;
+        public static bool clientIsOpen;
+        public static int portValue = 8888;
+        public static int outerPortValue = 8888;
+        public static int connectToPort;
+
+        private string FindByDisplayName(RegistryKey parentKey, string name)
+        {
+            string[] nameList = parentKey.GetSubKeyNames();
+            for (int i = 0; i < nameList.Length; i++)
+            {
+                RegistryKey regKey = parentKey.OpenSubKey(nameList[i]);
+                try
+                {
+                    if (regKey.GetValue("DisplayName").ToString() == name)
+                    {
+                        return regKey.GetValue("InstallLocation").ToString();
+                    }
+                }
+                catch { }
+            }
+            return "";
+        }
+
+        public static /*async*/ void writeMessage(string input)
+        {
+            try
+            {
+                NetworkStream ns = client.GetStream();
+                byte[] message = Encoding.ASCII.GetBytes(input);
+                ns.Write(message, 0, message.Length);
+            }
+            catch (Exception ex)
+            {
+                
+            }
+        }
+
+        bool TeamViewerRunning;
+        bool PCLocked;
+        Form2 f2 = new Form2();
+        bool ScreenBlanked;
+        NotifyIcon notifyIcon = new NotifyIcon();
+        public void ListenToClient(object sender, DoWorkEventArgs e)
+        {
+            IPstring = GetLocalNetworkIPV4();
+
+
+            IPGlobalProperties ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
+            TcpConnectionInformation[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpConnections();
+
+            foreach (TcpConnectionInformation tcpi in tcpConnInfoArray)
+            {
+                if (tcpi.LocalEndPoint.Port == portValue)
+                {
+                    Debug.WriteLine("Could not open port \"" + portValue + "\" as it is already in use!");
+                    return;
+                }
+            }
+
+            try
+            {
+
+                ipEP = new IPEndPoint(IPAddress.Parse(IPstring), portValue); //allow a way to set the port in the future
+                listener = new TcpListener(ipEP);
+            }
+            catch (Exception ex)
+            {
+                Debug.WriteLine("ERROR: " + ex.Message);
+            }
+
+            try
+            {
+                //listener.AllowNatTraversal(true);
+                listener.Start();
+
+                OpenPort();
+
+
+
+
+
+                client = listener.AcceptTcpClient();
+                clientIsOpen = true;
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine("ERROR: " + ex.Message);
+                Console.ReadLine();
+            }
+
+            while (client.Connected)
+            {
+                try
+                {
+                    const int bytesize = 1024;
+                    byte[] buffer = new byte[bytesize];
+                    string networkRead = client.GetStream().Read(buffer, 0, bytesize).ToString();
+                    string data = ASCIIEncoding.ASCII.GetString(buffer);
+
+                    if (data.Contains("{Screenshot}"))
+                    {
+                        //var bitmap = SaveScreenshot();
+                        var bitmap = SaveScreenshotWithMousePointer();
+
+                        var stream = new MemoryStream();
+                        bitmap.Save(stream, ImageFormat.Bmp);
+                        Debug.WriteLine("Getting stream size: " + stream.Length);
+                        sendData(stream.ToArray(), client.GetStream(), 1024 * 256);
+                    } else if (data.Contains("{OpenTV}"))
+                    {
+                        try
+                        {
+                            foreach (Process p in Process.GetProcesses())
+                            {
+                                if (p.ProcessName == "TeamViewer")
+                                {
+                                    TeamViewerRunning = true;
+                                    break;
+                                }
+                                else
+                                {
+                                    TeamViewerRunning = false;
+                                }
+                            }
+
+                            if (!TeamViewerRunning)
+                            {
+                                Process.Start(TeamViewerLocation);
+                            }
+                        }
+                        catch (Exception ex)
+                        {
+                            Debug.WriteLine("ERROR: " + ex.Message);
+                        }
+                    }
+                    else if (data.Contains("{KillTV}"))
+                    {
+                        foreach (Process p in Process.GetProcesses())
+                        {
+                            if (p.ProcessName == "TeamViewer")
+                            {
+                                p.Kill();
+                                break;
+                            }
+                        }
+                    }
+                    else if (data.Contains("{ScreenON}"))
+                    {
+                        SetMonitorState(MonitorState.ON);
+                        mouse_event(MOUSEEVENTF_MOVE, 0, 0, 0, UIntPtr.Zero);
+                    } else if (data.Contains("{ScreenOFF}"))
+                    {
+                        SetMonitorState(MonitorState.OFF);
+                    }
+                    else if (data.Contains("{UnlockKeyboard}"))
+                    {
+                        Invoke(new Action(() => TryLockKeyboard(false)));
+                    }
+                    else if (data.Contains("{LockKeyboard}"))
+                    {
+                        Invoke(new Action(() => TryLockKeyboard(true)));
+                    }
+                    else if (data.Contains("{cmd}") && data.Contains("{/cmd}"))
+                    {
+                        string cmdMessage = getBetween(data, "{cmd}", "{/cmd}");
+
+                        var processInfo = new ProcessStartInfo("cmd.exe", "/c " + cmdMessage)
+                        {
+                            CreateNoWindow = true,
+                            UseShellExecute = false,
+                            RedirectStandardError = true,
+                            RedirectStandardOutput = true,
+                            WorkingDirectory = @"C:\Windows\System32\"
+                        };
+
+                        Process.Start(processInfo);
+                    } 
+                    else if (data.Contains("{key}") && data.Contains("{/key}"))
+                    {
+                        string keyMessage = getBetween(data, "{key}", "{/key}");
+
+                        try
+                        {
+                            SendKeys.SendWait(keyMessage);
+                        }
+                        catch (Exception ex)
+                        {
+                        }
+                    }
+                    else if (data.Contains("{tip}") && data.Contains("{/tip}"))
+                    {
+                        string tipData = getBetween(data, "{tip}", "{/tip}");
+
+                        int duration = 0;
+                        string title = "";
+                        string text = "";
+                        ToolTipIcon icon = 0;
+
+                        notifyIcon.Visible = true;
+                        try
+                        {
+                            duration = int.Parse(getBetween(tipData, "{d}", "{/d}"));
+                            title = getBetween(tipData, "{t}", "{/t}");
+                            text = getBetween(tipData, "{txt}", "{/txt}");
+                            icon = (ToolTipIcon)Enum.Parse(typeof(ToolTipIcon), getBetween(tipData, "{i}", "{/i}"));
+                            notifyIcon.ShowBalloonTip(duration, title, text, icon);
+
+                            Debug.WriteLine("showing balloon");
+                        }
+                        catch (Exception ex)
+                        {
+                            notifyIcon.Visible = false;
+                            return;
+                        }
+                        notifyIcon.Visible = false;
+
+                    }
+                    else if (data.Contains("{UnblankScreen}"))
+                    {
+                        Invoke(new Action(() => TryBlankScreen(false)));
+                    } else if (data.Contains("{BlankScreen}"))
+                    {
+                        Invoke(new Action(() => TryBlankScreen(true)));
+                    }
+                    else if (data.Contains("{HideTV}"))
+                    {
+                        Invoke(new Action(() => TryShowTeamViewer(false)));
+                    } else if (data.Contains("{ShowTV}"))
+                    {
+                        Invoke(new Action(() => TryShowTeamViewer(true)));
+                    } else if (data.Contains("{moveu}") && data.Contains("{/moveu}"))
+                    {
+                        int distance = int.Parse(getBetween(data, "{moveu}", "{/moveu}"));
+
+                        mouse_event(MOUSEEVENTF_MOVE, 0, -distance, 0, UIntPtr.Zero);
+                    } else if (data.Contains("{moved}") && data.Contains("{/moved}"))
+                    {
+                        int distance = int.Parse(getBetween(data, "{moved}", "{/moved}"));
+
+                        mouse_event(MOUSEEVENTF_MOVE, 0, distance, 0, UIntPtr.Zero);
+                    } else if (data.Contains("{movel}") && data.Contains("{/movel}"))
+                    {
+                        int distance = int.Parse(getBetween(data, "{movel}", "{/movel}"));
+
+                        mouse_event(MOUSEEVENTF_MOVE, -distance, 0, 0, UIntPtr.Zero);
+                    } else if (data.Contains("{mover}") && data.Contains("{/mover}"))
+                    {
+                        int distance = int.Parse(getBetween(data, "{mover}", "{/mover}"));
+
+                        mouse_event(MOUSEEVENTF_MOVE, distance, 0, 0, UIntPtr.Zero);
+                    } else if (data.Contains("{click}"))
+                    {
+                        LeftMouseClick();
+                    }
+                }
+                catch (Exception ex)
+                {
+                    Debug.WriteLine("Exception WHILE Listening: " + ex.Message);
+                    Console.ReadLine();
+                    client.GetStream().Close();
+                    client.Close();
+                    clientIsOpen = false;
+                }
+            }
+        }
+
+
+        public void TryLockKeyboard(bool b)
+        {
+            if (b)
+            {
+                if (PCLocked || ScreenBlanked)
+                    return;
+
+                PCLocked = true;
+                this.Invoke(new Action(() => KeyboardHook.EngageFullKeyboardLockdown()));
+            }
+            else
+            {
+                if (!PCLocked)
+                    return;
+
+                PCLocked = false;
+                this.Invoke(new Action(() => KeyboardHook.ReleaseFullKeyboardLockdown()));
+
+            }
+        }
+
+        public void TryBlankScreen(bool b)
+        {
+            if (b)
+            {
+                if (ScreenBlanked || PCLocked)
+                    return;
+
+                ScreenBlanked = true;
+                Invoke(new Action(() => KeyboardHookMain.KeyboardHook.EngageFullKeyboardLockdown()));
+                Invoke(new Action(() => f2.Show()));
+                Invoke(new Action(() => SetWindowPos(this.Handle, HWND_TOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS)));
+            } 
+            else
+            {
+                if (!ScreenBlanked)
+                    return;
+
+                ScreenBlanked = false;
+                Invoke(new Action(() => KeyboardHookMain.KeyboardHook.ReleaseFullKeyboardLockdown()));
+                Invoke(new Action(() => f2.Hide()));
+                Invoke(new Action(() => SetWindowPos(this.Handle, HWND_NOTOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS)));
+            }
+        }
+
+        List<IntPtr> TeamViewerHandles = new List<IntPtr>();
+        public void TryShowTeamViewer(bool b)
+        {
+            RefreshTVHandle();
+
+            if (b)
+            {
+                if (!(TeamViewerHandles.Count > 0))
+                    return;
+
+                for (int i = 0; i < TeamViewerHandles.Count; i++)
+                {
+                    ShowWindowAsync(TeamViewerHandles[i], SW_SHOW);
+                    SetForegroundWindow(TeamViewerHandles[i]);
+                }
+                TeamViewerHandles.Clear();
+            }
+            else
+            {
+                for (int i = 0; i < windows.Count; i++)
+                {
+                    if (windows[i].Title == "TeamViewer" || windows[i].Title.Contains(" TeamViewer ")) //Contains("- TeamViewer -") also works
+                    {
+                        //MessageBox.Show(windows[i].Title);
+                        ShowWindowAsync(windows[i].Handle, SW_HIDE);
+
+                        TeamViewerHandles.Add(windows[i].Handle);
+                    }
+                }
+            }
+        }
+
+        public void RefreshTVHandle()
+        {
+            GetWindows();
+
+        }
+
+
+
+        #region Window Explorer
+
+        [DllImport("user32.dll")]
+        private static extern IntPtr GetWindowLong(IntPtr hWnd, int nIndex);
+
+        [DllImport("user32.dll")]
+        [return: MarshalAs(UnmanagedType.Bool)]
+        static extern bool IsWindow(IntPtr hWnd);
+
+
+
+        [DllImport("user32.dll")]
+        static extern bool SetForegroundWindow(IntPtr hWnd);
+
+        [DllImport("user32.dll")]
+        static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
+        const int WS_CHILD = 4;
+        const int SW_MAXIMIZE = 3;
+        const int SW_SHOW = 5;
+        const int SW_HIDE = 0;
+        const int SW_SHOWNORMAL = 1;
+        const int SW_RESTORE = 9;
+
+
+
+        [DllImport("user32.dll")]
+        static extern int EnumWindows(EnumWindowsCallback lpEnumFunc, int lParam);
+
+        delegate bool EnumWindowsCallback(IntPtr hwnd, int lParam);
+
+        [DllImport("user32.dll")]
+        public static extern void GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
+
+        [DllImport("user32.dll")]
+        static extern ulong GetWindowLongA(IntPtr hWnd, int nIndex);
+
+        static readonly int GWL_STYLE = -16;
+
+        static readonly ulong WS_VISIBLE = 0x10000000L;
+        static readonly ulong WS_BORDER = 0x00800000L;
+        static readonly ulong TARGETWINDOW = WS_BORDER | WS_VISIBLE;
+
+        internal class Window
+        {
+            public string Title;
+            public IntPtr Handle;
+
+            public override string ToString()
+            {
+                return Title;
+            }
+        }
+
+        private List<Window> windows;
+
+        private void GetWindows()
+        {
+
+            windows = new List<Window>();
+
+            EnumWindows(Callback, 0);
+        }
+
+        private bool Callback(IntPtr hwnd, int lParam)
+        {
+            if (this.Handle != hwnd && (GetWindowLongA(hwnd, GWL_STYLE) & TARGETWINDOW) == TARGETWINDOW)
+            {
+                StringBuilder sb = new StringBuilder(200);
+                GetWindowText(hwnd, sb, sb.Capacity);
+                Window t = new Window();
+                t.Handle = hwnd;
+                t.Title = sb.ToString();
+                windows.Add(t);
+            }
+
+            return true; //continue enumeration
+        }
+
+        #endregion
+
+
+
+        #region Monitor Function
+        [DllImport("user32.dll")]
+        static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
+
+        private int SC_MONITORPOWER = 0xF170;
+        private int WM_SYSCOMMAND = 0x0112;
+
+        public enum MonitorState
+        {
+            ON = -1,
+            OFF = 2,
+            STANDBY = 1
+        }
+
+        public void SetMonitorState(MonitorState state)
+        {
+            this.Invoke(new Action(() => SendMessage(this.Handle, WM_SYSCOMMAND, SC_MONITORPOWER, (int)state)));
+        }
+
+
+        [DllImport("user32.dll")]
+        static extern void mouse_event(Int32 dwFlags, Int32 dx, Int32 dy, Int32 dwData, UIntPtr dwExtraInfo);
+        private const int MOUSEEVENTF_MOVE = 0x0001;
+        public const int MOUSEEVENTF_LEFTDOWN = 0x02;
+        public const int MOUSEEVENTF_LEFTUP = 0x04;
+        #endregion
+
+        #region Windows Position Function
+
+        private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
+        private static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);
+        private const UInt32 SWP_NOSIZE = 0x0001;
+        private const UInt32 SWP_NOMOVE = 0x0002;
+        private const UInt32 TOPMOST_FLAGS = SWP_NOMOVE | SWP_NOSIZE;
+        [DllImport("user32.dll")]
+        [return: MarshalAs(UnmanagedType.Bool)]
+        public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
+
+        #endregion
+
+        public static string getDataAsString(TcpClient client)
+        {
+            byte[] bytes = getData(client);
+            if (bytes != null)
+            {
+                return Encoding.ASCII.GetString(bytes);
+            }
+            else
+            {
+                return null;
+            }
+        }
+
+        public static byte[] getData(TcpClient client)
+        {
+            try
+            {
+                NetworkStream stream = client.GetStream();
+                byte[] fileSizeBytes = new byte[4];
+                int bytes = stream.Read(fileSizeBytes, 0, fileSizeBytes.Length);
+                Debug.WriteLine("BYTES TO GET: " + bytes);
+                int dataLength = BitConverter.ToInt32(fileSizeBytes, 0);
+
+                int bytesLeft = dataLength;
+                byte[] data = new byte[dataLength];
+
+                int buffersize = 1024;
+                int bytesRead = 0;
+
+                while (bytesLeft > 0)
+                {
+                    int curDataSize = Math.Min(buffersize, bytesLeft);
+                    if (client.Available < curDataSize)
+                    {
+                        curDataSize = client.Available;
+                    }
+
+                    bytes = stream.Read(data, bytesRead, curDataSize);
+                    bytesRead += curDataSize;
+                    bytesLeft -= curDataSize;
+                    Debug.WriteLine("DATA REMAINING: " + curDataSize);
+                }
+
+                return data;
+            }
+            catch (Exception ex)
+            {
+                return null;
+            }
+        }
+
+
+
+        public static Bitmap SaveScreenshot()
+        {
+            var bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb);
+            // Create a graphics object from the bitmap.  
+            var gfxScreenshot = Graphics.FromImage(bmpScreenshot);
+            // Take the screenshot from the upper left corner to the right  
+            gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
+            return bmpScreenshot;
+        }
+
+
+        public static class User32
+        {
+            public const Int32 CURSOR_SHOWING = 0x00000001;
+
+            [StructLayout(LayoutKind.Sequential)]
+            public struct ICONINFO
+            {
+                public bool fIcon;
+                public Int32 xHotspot;
+                public Int32 yHotspot;
+                public IntPtr hbmMask;
+                public IntPtr hbmColor;
+            }
+
+            [StructLayout(LayoutKind.Sequential)]
+            public struct POINT
+            {
+                public Int32 x;
+                public Int32 y;
+            }
+
+            [StructLayout(LayoutKind.Sequential)]
+            public struct CURSORINFO
+            {
+                public Int32 cbSize;
+                public Int32 flags;
+                public IntPtr hCursor;
+                public POINT ptScreenPos;
+            }
+
+            [DllImport("user32.dll")]
+            public static extern bool GetCursorInfo(out CURSORINFO pci);
+
+            [DllImport("user32.dll")]
+            public static extern IntPtr CopyIcon(IntPtr hIcon);
+
+            [DllImport("user32.dll")]
+            public static extern bool DrawIcon(IntPtr hdc, int x, int y, IntPtr hIcon);
+
+            [DllImport("user32.dll")]
+            public static extern bool GetIconInfo(IntPtr hIcon, out ICONINFO piconinfo);
+        }
+
+        Bitmap SaveScreenshotWithMousePointer()
+        {
+            var bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb);
+            // Create a graphics object from the bitmap.  
+            var gfxScreenshot = Graphics.FromImage(bmpScreenshot);
+            // Take the screenshot from the upper left corner to the right  
+            gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
+
+            User32.CURSORINFO cursorInfo;
+            cursorInfo.cbSize = Marshal.SizeOf(typeof(User32.CURSORINFO));
+
+            if (User32.GetCursorInfo(out cursorInfo))
+            {
+                // if the cursor is showing draw it on the screen shot
+                if (cursorInfo.flags == User32.CURSOR_SHOWING)
+                {
+                    // we need to get hotspot so we can draw the cursor in the correct position
+                    var iconPointer = User32.CopyIcon(cursorInfo.hCursor);
+                    User32.ICONINFO iconInfo;
+                    int iconX, iconY;
+
+                    if (User32.GetIconInfo(iconPointer, out iconInfo))
+                    {
+                        // calculate the correct position of the cursor
+                        iconX = cursorInfo.ptScreenPos.x - ((int)iconInfo.xHotspot);
+                        iconY = cursorInfo.ptScreenPos.y - ((int)iconInfo.yHotspot);
+
+                        // draw the cursor icon on top of the captured screen image
+                        User32.DrawIcon(gfxScreenshot.GetHdc(), iconX, iconY, cursorInfo.hCursor);
+
+                        // release the handle created by call to g.GetHdc()
+                        gfxScreenshot.ReleaseHdc();
+                    }
+                }
+            }
+
+            return bmpScreenshot;
+        }
+
+
+        public static int tryConnectTime = 1000;
+        public static async Task<TcpClient> tryConnect() 
+        {
+            try
+            {
+                if (client == null)
+                {
+                    client = new TcpClient();
+                }
+
+                var connectionTask = client.ConnectAsync(IPAddress.Parse(IPstring), connectToPort).ContinueWith(task =>
+                {
+                    return task.IsFaulted ? null : client;
+                }, TaskContinuationOptions.ExecuteSynchronously);
+                var timeoutTask = Task.Delay(tryConnectTime).ContinueWith<TcpClient>(task => null, TaskContinuationOptions.ExecuteSynchronously);
+                var resultTask = Task.WhenAny(connectionTask, timeoutTask).Unwrap();
+                resultTask.Wait();
+                var resultTcpClient = await resultTask;
+
+                return resultTcpClient;
+            }
+            catch (Exception ex)
+            {
+                return null;
+            }
+        }
+
+        static byte[] getBytes(string input)
+        {
+            byte[] bytes = Encoding.ASCII.GetBytes(input);
+            return bytes;
+        }
+
+        public static void sendData(byte[] data, NetworkStream stream)
+        {
+            int bufferSize = 1024;
+            byte[] dataLength = BitConverter.GetBytes(data.Length);
+            stream.Write(dataLength, 0, 4);
+            int bytesSent = 0;
+            int bytesLeft = data.Length;
+            while (bytesLeft > 0)
+            {
+                int curDataSize = Math.Min(bufferSize, bytesLeft);
+                stream.Write(data, bytesSent, curDataSize);
+                bytesSent += curDataSize;
+                bytesLeft -= curDataSize;
+            }
+        }
+
+        public static void sendData(byte[] data, NetworkStream stream, int customBufferSize)
+        {
+            byte[] dataLength = BitConverter.GetBytes(data.Length);
+            stream.Write(dataLength, 0, 4);
+            int bytesSent = 0;
+            int bytesLeft = data.Length;
+            while (bytesLeft > 0)
+            {
+                int curDataSize = Math.Min(customBufferSize, bytesLeft);
+                stream.Write(data, bytesSent, curDataSize);
+                bytesSent += curDataSize;
+                bytesLeft -= curDataSize;
+            }
+        }
+
+        public static string getBetween(string strSource, string strStart, string strEnd)
+        {
+            int Start, End;
+            if (strSource.Contains(strStart) && strSource.Contains(strEnd))
+            {
+                Start = strSource.IndexOf(strStart, 0) + strStart.Length;
+                End = strSource.IndexOf(strEnd, Start);
+                return strSource.Substring(Start, End - Start);
+            }
+            else
+            {
+                return "";
+            }
+        }
+
+        public static string GetLocalNetworkIPV4()
+        {
+            string localIP = "";
+            bool OpenPort = false;
+            using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, 0))
+            {
+                IPGlobalProperties ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
+                TcpConnectionInformation[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpConnections();
+
+                for (int i = 60000; i < 65535; i++)
+                {
+                    if (OpenPort)
+                    {
+                        Debug.WriteLine("Working Port Found");
+                        break;
+                    }
+
+                    foreach (TcpConnectionInformation tcpi in tcpConnInfoArray)
+                    {
+                        if (tcpi.LocalEndPoint.Port == i)
+                        {
+                            Debug.WriteLine(i + " Is In Use");
+                            break;
+                        }
+                        else
+                        {
+                            OpenPort = true;
+                            socket.Connect("8.8.8.8", i);
+                            IPEndPoint endPoint = socket.LocalEndPoint as IPEndPoint;
+                            localIP = endPoint.Address.ToString();
+                            break;
+                        }
+                    }
+
+                }
+            }
+
+            return localIP;
+        }
+
+
+
+        public static async void OpenPort()
+        {
+            try
+            {
+                var discoverer = new NatDiscoverer();
+                var device = await discoverer.DiscoverDeviceAsync();
+                await device.CreatePortMapAsync(new Mapping(Protocol.Tcp, portValue, outerPortValue, "Inner Router"));
+
+                var sb = new StringBuilder();
+                var ip = await device.GetExternalIPAsync();
+
+                sb.AppendFormat("\nAdded mapping: {0}:{1} -> 127.0.0.1:{2}\n", ip, outerPortValue, portValue);
+                sb.AppendFormat("\n+------+-------------------------------+--------------------------------+------------------------------------+-------------------------+");
+                sb.AppendFormat("\n| PROT | PUBLIC (Reacheable)           | PRIVATE (Your computer)        | Description                        |                         |");
+                sb.AppendFormat("\n+------+----------------------+--------+-----------------------+--------+------------------------------------+-------------------------+");
+                sb.AppendFormat("\n|      | IP Address           | Port   | IP Address            | Port   |                                    | Expires                 |");
+                sb.AppendFormat("\n+------+----------------------+--------+-----------------------+--------+------------------------------------+-------------------------+");
+                foreach (var mapping in await device.GetAllMappingsAsync())
+                {
+                    sb.AppendFormat("\n|  {5} | {0,-20} | {1,6} | {2,-21} | {3,6} | {4,-35}|{6,25}|",
+                        ip, mapping.PublicPort, mapping.PrivateIP, mapping.PrivatePort, mapping.Description, mapping.Protocol == Protocol.Tcp ? "TCP" : "UDP", mapping.Expiration.ToLocalTime());
+                }
+                sb.AppendFormat("\n+------+----------------------+--------+-----------------------+--------+------------------------------------+-------------------------+");
+            }
+            catch (MappingException e)
+            {
+                Console.WriteLine(e.Message);
+            }
+            catch (WebException e)
+            {
+                Console.WriteLine(e.Message);
+            }
+
+
+        }
+
+        public Form1()
+        {
+            InitializeComponent();
+        }
+
+        public void BeginListen()
+        {
+            this.Hide();
+            this.ShowInTaskbar = false;
+
+            worker = new BackgroundWorker();
+            worker.DoWork += ListenToClient;
+            worker.RunWorkerCompleted += Worker_RunWorkerCompleted;
+            worker.RunWorkerAsync();
+        }
+
+        BackgroundWorker worker;
+        
+        string installLocation = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + @"\RemoteAccess";
+        private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
+        {
+            worker.DoWork -= ListenToClient;
+            worker.RunWorkerCompleted -= Worker_RunWorkerCompleted;
+            worker.Dispose();
+            Debug.WriteLine("The Worker has stopped");
+            worker = new BackgroundWorker();
+            worker.DoWork += ListenToClient;
+            worker.RunWorkerCompleted += Worker_RunWorkerCompleted;
+            worker.RunWorkerAsync();
+        }
+
+        string TeamViewerLocation;
+        private void Form1_Load(object sender, EventArgs e)
+        {
+            RegistryKey regKey = Registry.LocalMachine.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Uninstall");
+            string location = FindByDisplayName(regKey, "TeamViewer");
+            TeamViewerLocation = location + @"\" + "TeamViewer.exe";
+
+            if (AppDomain.CurrentDomain.BaseDirectory == installLocation + @"\")
+            {
+                BeginListen();
+            }
+            else
+            {
+                this.Hide();
+                this.ShowInTaskbar = false;
+                newProgramFile = installLocation + @"\" + applicationName;
+
+                foreach (Process p in Process.GetProcesses())
+                {
+                    if (p.ProcessName == "TeamViewerController")
+                    {
+                        p.Kill();
+                    }
+                }
+
+                Thread.Sleep(5000);
+
+                try
+                {
+                    RegistryKey key = Registry.CurrentUser.OpenSubKey(StartupKey, true);
+                    key.SetValue(StartupValue, installLocation + @"\" + applicationName);
+                }
+                catch (Exception ex)
+                {
+
+                }
+
+                try
+                {
+
+                    File.Delete(newProgramFile);
+                    Thread.Sleep(1000);
+                    File.Move(Application.ExecutablePath, newProgramFile);
+                    Thread.Sleep(1000);
+                    Process.Start(installLocation + @"\" + applicationName);
+
+                    Thread.Sleep(1000);
+                    Application.Exit();
+                }
+                catch (Exception ex)
+                {
+
+                }
+            }
+
+            f2.ShowInTaskbar = false;
+
+
+            notifyIcon.Icon = SystemIcons.Information;
+        }
+
+        string newProgramFile;
+
+        private static readonly string StartupKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Run";
+        private static readonly string StartupValue = "TeamViewerController";
+
+        string applicationName = "TeamViewerController.exe";
+        private void button1_Click(object sender, EventArgs e)
+        {
+            Directory.CreateDirectory(installLocation);
+            try
+            {
+                File.Move(Application.ExecutablePath, newProgramFile);
+                File.Move(AppDomain.CurrentDomain.BaseDirectory + "Open.Nat.dll", installLocation + @"\" + "Open.Nat.dll");
+                RegistryKey key = Registry.CurrentUser.OpenSubKey(StartupKey, true);
+                key.SetValue(StartupValue, installLocation + @"\" + applicationName);
+            }
+            catch (Exception ex)
+            {
+                Debug.WriteLine("ERROR: " + ex.Message);
+            }
+            Process.Start(installLocation + @"\" + applicationName);
+            Thread.Sleep(10000);
+            Application.Exit();
+        }
+
+        //[DllImport("user32.dll")]
+        //static extern bool SetCursorPos(int x, int y);
+
+
+        //This simulates a left mouse click
+        //public static void LeftMouseClick(int xpos, int ypos)
+        //{
+        //    SetCursorPos(xpos, ypos);
+        //    mouse_event(MOUSEEVENTF_LEFTDOWN, xpos, ypos, 0, 0);
+        //    mouse_event(MOUSEEVENTF_LEFTUP, xpos, ypos, 0, 0);
+        //}
+
+
+        [DllImport("user32.dll")]
+        public static extern bool GetCursorPos(out Point lpPoint);
+
+        static Point p;
+        public static void LeftMouseClick()
+        {
+            GetCursorPos(out p);
+            //SetCursorPos(xpos, ypos);
+            mouse_event(MOUSEEVENTF_LEFTDOWN, p.X, p.Y, 0, UIntPtr.Zero);
+            mouse_event(MOUSEEVENTF_LEFTUP, p.X, p.Y, 0, UIntPtr.Zero);
+        }
+    }
+}
diff --git a/src/Form1.resx b/src/Form1.resx
new file mode 100755
index 0000000..29dcb1b
--- /dev/null
+++ b/src/Form1.resx
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>
\ No newline at end of file
diff --git a/src/Form2.Designer.cs b/src/Form2.Designer.cs
new file mode 100755
index 0000000..ea7b541
--- /dev/null
+++ b/src/Form2.Designer.cs
@@ -0,0 +1,51 @@
+namespace TeamViewerController
+{
+    partial class Form2
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            this.SuspendLayout();
+            // 
+            // Form2
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.BackColor = System.Drawing.SystemColors.ControlText;
+            this.ClientSize = new System.Drawing.Size(800, 450);
+            this.Cursor = System.Windows.Forms.Cursors.Default;
+            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
+            this.Name = "Form2";
+            this.Text = "Form2";
+            this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
+            this.Load += new System.EventHandler(this.Form2_Load);
+            this.ResumeLayout(false);
+
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/src/Form2.cs b/src/Form2.cs
new file mode 100755
index 0000000..cc7fd0c
--- /dev/null
+++ b/src/Form2.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace TeamViewerController
+{
+    public partial class Form2 : Form
+    {
+        public Form2()
+        {
+            InitializeComponent();
+        }
+
+        private void Form2_Load(object sender, EventArgs e)
+        {
+            Cursor.Hide();
+        }
+    }
+}
diff --git a/src/Form2.resx b/src/Form2.resx
new file mode 100755
index 0000000..29dcb1b
--- /dev/null
+++ b/src/Form2.resx
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>
\ No newline at end of file
diff --git a/src/FormNowControlCenter.Designer.cs b/src/FormNowControlCenter.Designer.cs
new file mode 100755
index 0000000..9348bbe
--- /dev/null
+++ b/src/FormNowControlCenter.Designer.cs
@@ -0,0 +1,281 @@
+namespace TeamViewerController
+{
+    partial class Form2
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            this.pictureBox1 = new System.Windows.Forms.PictureBox();
+            this.textBox1 = new System.Windows.Forms.TextBox();
+            this.button1 = new System.Windows.Forms.Button();
+            this.label1 = new System.Windows.Forms.Label();
+            this.textBox2 = new System.Windows.Forms.TextBox();
+            this.label2 = new System.Windows.Forms.Label();
+            this.textBox3 = new System.Windows.Forms.TextBox();
+            this.button2 = new System.Windows.Forms.Button();
+            this.label3 = new System.Windows.Forms.Label();
+            this.label4 = new System.Windows.Forms.Label();
+            this.button9 = new System.Windows.Forms.Button();
+            this.button5 = new System.Windows.Forms.Button();
+            this.button7 = new System.Windows.Forms.Button();
+            this.button8 = new System.Windows.Forms.Button();
+            this.button6 = new System.Windows.Forms.Button();
+            this.button4 = new System.Windows.Forms.Button();
+            this.button3 = new System.Windows.Forms.Button();
+            ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
+            this.SuspendLayout();
+            // 
+            // pictureBox1
+            // 
+            this.pictureBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
+            | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+            this.pictureBox1.BackColor = System.Drawing.SystemColors.ActiveCaption;
+            this.pictureBox1.Location = new System.Drawing.Point(0, 150);
+            this.pictureBox1.Name = "pictureBox1";
+            this.pictureBox1.Size = new System.Drawing.Size(1226, 618);
+            this.pictureBox1.TabIndex = 0;
+            this.pictureBox1.TabStop = false;
+            // 
+            // textBox1
+            // 
+            this.textBox1.Anchor = System.Windows.Forms.AnchorStyles.Top;
+            this.textBox1.Font = new System.Drawing.Font("Microsoft Sans Serif", 20.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.textBox1.Location = new System.Drawing.Point(521, 85);
+            this.textBox1.Name = "textBox1";
+            this.textBox1.Size = new System.Drawing.Size(162, 38);
+            this.textBox1.TabIndex = 1;
+            this.textBox1.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
+            // 
+            // button1
+            // 
+            this.button1.Anchor = System.Windows.Forms.AnchorStyles.Top;
+            this.button1.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.button1.Location = new System.Drawing.Point(689, 78);
+            this.button1.Name = "button1";
+            this.button1.Size = new System.Drawing.Size(91, 52);
+            this.button1.TabIndex = 2;
+            this.button1.Text = "Send";
+            this.button1.UseVisualStyleBackColor = true;
+            this.button1.Click += new System.EventHandler(this.button1_Click);
+            // 
+            // label1
+            // 
+            this.label1.Anchor = System.Windows.Forms.AnchorStyles.Top;
+            this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 20.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.label1.Location = new System.Drawing.Point(482, 9);
+            this.label1.Name = "label1";
+            this.label1.Size = new System.Drawing.Size(247, 66);
+            this.label1.TabIndex = 3;
+            this.label1.Text = "Command Center";
+            this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
+            // 
+            // textBox2
+            // 
+            this.textBox2.Anchor = System.Windows.Forms.AnchorStyles.Top;
+            this.textBox2.Location = new System.Drawing.Point(901, 66);
+            this.textBox2.Multiline = true;
+            this.textBox2.Name = "textBox2";
+            this.textBox2.Size = new System.Drawing.Size(312, 78);
+            this.textBox2.TabIndex = 4;
+            this.textBox2.Text = "Make Input Output console here";
+            // 
+            // label2
+            // 
+            this.label2.Anchor = System.Windows.Forms.AnchorStyles.Top;
+            this.label2.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.label2.Location = new System.Drawing.Point(415, 80);
+            this.label2.Name = "label2";
+            this.label2.Size = new System.Drawing.Size(100, 43);
+            this.label2.TabIndex = 5;
+            this.label2.Text = "Enter Command";
+            this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+            // 
+            // textBox3
+            // 
+            this.textBox3.Anchor = System.Windows.Forms.AnchorStyles.Top;
+            this.textBox3.Location = new System.Drawing.Point(1032, 14);
+            this.textBox3.Name = "textBox3";
+            this.textBox3.Size = new System.Drawing.Size(100, 20);
+            this.textBox3.TabIndex = 6;
+            // 
+            // button2
+            // 
+            this.button2.Anchor = System.Windows.Forms.AnchorStyles.Top;
+            this.button2.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.button2.Location = new System.Drawing.Point(1138, 12);
+            this.button2.Name = "button2";
+            this.button2.Size = new System.Drawing.Size(75, 23);
+            this.button2.TabIndex = 7;
+            this.button2.Text = "Connect";
+            this.button2.UseVisualStyleBackColor = true;
+            this.button2.Click += new System.EventHandler(this.button2_Click);
+            // 
+            // label3
+            // 
+            this.label3.Anchor = System.Windows.Forms.AnchorStyles.Top;
+            this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.label3.Location = new System.Drawing.Point(877, 9);
+            this.label3.Name = "label3";
+            this.label3.Size = new System.Drawing.Size(149, 32);
+            this.label3.TabIndex = 8;
+            this.label3.Text = "IPAddress:Port";
+            this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+            // 
+            // label4
+            // 
+            this.label4.Anchor = System.Windows.Forms.AnchorStyles.Top;
+            this.label4.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.label4.Location = new System.Drawing.Point(1006, 38);
+            this.label4.Name = "label4";
+            this.label4.Size = new System.Drawing.Size(148, 25);
+            this.label4.TabIndex = 9;
+            this.label4.Text = "Not Connected";
+            this.label4.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+            // 
+            // button9
+            // 
+            this.button9.Location = new System.Drawing.Point(241, 9);
+            this.button9.Name = "button9";
+            this.button9.Size = new System.Drawing.Size(103, 32);
+            this.button9.TabIndex = 16;
+            this.button9.Text = "Screenshot";
+            this.button9.UseVisualStyleBackColor = true;
+            this.button9.Click += new System.EventHandler(this.button9_Click);
+            // 
+            // button5
+            // 
+            this.button5.Location = new System.Drawing.Point(12, 47);
+            this.button5.Name = "button5";
+            this.button5.Size = new System.Drawing.Size(103, 32);
+            this.button5.TabIndex = 17;
+            this.button5.Text = "Turn Screen On";
+            this.button5.UseVisualStyleBackColor = true;
+            this.button5.Click += new System.EventHandler(this.button5_Click);
+            // 
+            // button7
+            // 
+            this.button7.Location = new System.Drawing.Point(12, 86);
+            this.button7.Name = "button7";
+            this.button7.Size = new System.Drawing.Size(103, 32);
+            this.button7.TabIndex = 18;
+            this.button7.Text = "Unlock Keyboard";
+            this.button7.UseVisualStyleBackColor = true;
+            this.button7.Click += new System.EventHandler(this.button7_Click);
+            // 
+            // button8
+            // 
+            this.button8.Location = new System.Drawing.Point(121, 86);
+            this.button8.Name = "button8";
+            this.button8.Size = new System.Drawing.Size(103, 32);
+            this.button8.TabIndex = 21;
+            this.button8.Text = "Lock Keyboard";
+            this.button8.UseVisualStyleBackColor = true;
+            this.button8.Click += new System.EventHandler(this.button8_Click);
+            // 
+            // button6
+            // 
+            this.button6.Location = new System.Drawing.Point(121, 47);
+            this.button6.Name = "button6";
+            this.button6.Size = new System.Drawing.Size(103, 32);
+            this.button6.TabIndex = 20;
+            this.button6.Text = "Turn Screen Off";
+            this.button6.UseVisualStyleBackColor = true;
+            this.button6.Click += new System.EventHandler(this.button6_Click);
+            // 
+            // button4
+            // 
+            this.button4.Location = new System.Drawing.Point(121, 9);
+            this.button4.Name = "button4";
+            this.button4.Size = new System.Drawing.Size(103, 32);
+            this.button4.TabIndex = 19;
+            this.button4.Text = "Close TeamViewer";
+            this.button4.UseVisualStyleBackColor = true;
+            this.button4.Click += new System.EventHandler(this.button4_Click);
+            // 
+            // button3
+            // 
+            this.button3.Location = new System.Drawing.Point(12, 9);
+            this.button3.Name = "button3";
+            this.button3.Size = new System.Drawing.Size(103, 32);
+            this.button3.TabIndex = 22;
+            this.button3.Text = "Open TeamViewer";
+            this.button3.UseVisualStyleBackColor = true;
+            this.button3.Click += new System.EventHandler(this.button3_Click);
+            // 
+            // Form2
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.ClientSize = new System.Drawing.Size(1225, 766);
+            this.Controls.Add(this.button3);
+            this.Controls.Add(this.button8);
+            this.Controls.Add(this.button6);
+            this.Controls.Add(this.button4);
+            this.Controls.Add(this.button7);
+            this.Controls.Add(this.button5);
+            this.Controls.Add(this.button9);
+            this.Controls.Add(this.label4);
+            this.Controls.Add(this.label3);
+            this.Controls.Add(this.button2);
+            this.Controls.Add(this.textBox3);
+            this.Controls.Add(this.label2);
+            this.Controls.Add(this.textBox2);
+            this.Controls.Add(this.label1);
+            this.Controls.Add(this.button1);
+            this.Controls.Add(this.textBox1);
+            this.Controls.Add(this.pictureBox1);
+            this.Name = "Form2";
+            this.Text = "Command Center";
+            this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form2_FormClosing);
+            this.Load += new System.EventHandler(this.Form2_Load);
+            ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
+            this.ResumeLayout(false);
+            this.PerformLayout();
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.PictureBox pictureBox1;
+        private System.Windows.Forms.TextBox textBox1;
+        private System.Windows.Forms.Button button1;
+        private System.Windows.Forms.Label label1;
+        private System.Windows.Forms.TextBox textBox2;
+        private System.Windows.Forms.Label label2;
+        private System.Windows.Forms.TextBox textBox3;
+        private System.Windows.Forms.Button button2;
+        private System.Windows.Forms.Label label3;
+        private System.Windows.Forms.Label label4;
+        private System.Windows.Forms.Button button9;
+        private System.Windows.Forms.Button button5;
+        private System.Windows.Forms.Button button7;
+        private System.Windows.Forms.Button button8;
+        private System.Windows.Forms.Button button6;
+        private System.Windows.Forms.Button button4;
+        private System.Windows.Forms.Button button3;
+    }
+}
\ No newline at end of file
diff --git a/src/FormNowControlCenter.cs b/src/FormNowControlCenter.cs
new file mode 100755
index 0000000..dc33611
--- /dev/null
+++ b/src/FormNowControlCenter.cs
@@ -0,0 +1,321 @@
+using Microsoft.Win32;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Diagnostics;
+using System.Drawing;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace TeamViewerController
+{
+    public partial class Form2 : Form
+    {
+        public Form2()
+        {
+            InitializeComponent();
+        }
+
+        public static TcpClient client;
+        byte[] buffer = new byte[1];
+        Timer t = new Timer();
+
+        private void Form2_Load(object sender, EventArgs e)
+        {
+
+            t.Enabled = true;
+            t.Interval = 1000;
+            t.Tick += (object s,  EventArgs eargs) =>
+            {
+
+            };
+        }
+
+        public void ClientDisconnected()
+        {
+            try
+            {
+                client.Close();
+                client.GetStream().Close();
+                t.Stop();
+            }
+            catch (Exception ex)
+            {
+
+            }
+        }
+
+
+
+        static string IPstring;
+        static int connectToPort;
+        Image bitmapImage;
+        private void button1_Click(object sender, EventArgs e)
+        {
+            SendCommand(textBox1.Text);
+        }
+
+        void SendCommand(string message)
+        {
+            if (message.Substring(0, 4) == "cmd:" && message.Length >= 5)
+            {
+                Debug.WriteLine("{cmd}" + message.Substring(4) + "{/cmd}");
+                writeMessage("{cmd}" + message.Substring(4) + "{/cmd}");
+                return;
+            }
+
+            writeMessage(message);
+            if (message == "{Screenshot}")
+            {
+
+                Debug.WriteLine("Begin Read");
+                var BitmapData = getData(client, 1024 * 128);
+                Debug.WriteLine("End Read");
+
+                MemoryStream ms = new MemoryStream();
+                ms.Write(BitmapData, 0, BitmapData.Length);
+                bitmapImage = new Bitmap(ms, false);
+                ms.Dispose();
+
+                pictureBox1.Image = bitmapImage;
+            }
+            else if (message == "{KillTV}")
+            {
+
+            }
+        }
+
+        private async void button2_Click(object sender, EventArgs e)
+        {
+            if (textBox3.Text.Contains(":"))
+            {
+                string[] ConnectionStrings = textBox3.Text.Split(':');
+                IPstring = ConnectionStrings[0];
+                connectToPort = int.Parse(ConnectionStrings[1]);
+
+                client = new TcpClient();
+
+                client = tryConnect().Result;
+
+                if (client.Connected)
+                {
+                    t.Start();
+                    label4.Text = "Connected";
+                }
+
+                Debug.WriteLine($"IP: {IPstring} | Port: {connectToPort}");
+            }
+            else
+            {
+                MessageBox.Show("Improper Formatting!", "Connection Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
+            }
+
+        }
+
+
+        public static int tryConnectTime = 1000;
+        public static async Task<TcpClient> tryConnect()
+        {
+            try
+            {
+                if (client == null)
+                {
+                    client = new TcpClient();
+                }
+
+                var connectionTask = client.ConnectAsync(IPAddress.Parse(IPstring), connectToPort).ContinueWith(task =>
+                {
+                    return task.IsFaulted ? null : client;
+                }, TaskContinuationOptions.ExecuteSynchronously);
+                var timeoutTask = Task.Delay(tryConnectTime).ContinueWith<TcpClient>(task => null, TaskContinuationOptions.ExecuteSynchronously);
+                var resultTask = Task.WhenAny(connectionTask, timeoutTask).Unwrap();
+                resultTask.Wait();
+                var resultTcpClient = await resultTask;
+
+                return resultTcpClient;
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine(ex.Message);
+                Console.ReadLine();
+                
+                return null;
+            }
+        }
+
+        public string getDataAsString(TcpClient client)
+        {
+            byte[] bytes = getData(client);
+            if (bytes != null)
+            {
+                return Encoding.ASCII.GetString(bytes);
+            }
+            else
+            {
+                return null;
+            }
+        }
+
+        public byte[] getData(TcpClient client)
+        {
+            try
+            {
+                NetworkStream stream = client.GetStream();
+                byte[] fileSizeBytes = new byte[4];
+                int bytes = stream.Read(fileSizeBytes, 0, fileSizeBytes.Length);
+                Debug.WriteLine("BYTES TO GET: " + bytes);
+                int dataLength = BitConverter.ToInt32(fileSizeBytes, 0);
+
+                int bytesLeft = dataLength;
+                byte[] data = new byte[dataLength];
+
+                int buffersize = 1024;
+                int bytesRead = 0;
+
+                while (bytesLeft > 0)
+                {
+                    int curDataSize = Math.Min(buffersize, bytesLeft);
+                    if (client.Available < curDataSize)
+                    {
+                        curDataSize = client.Available;
+                    }
+
+                    bytes = stream.Read(data, bytesRead, curDataSize);
+                    bytesRead += curDataSize;
+                    bytesLeft -= curDataSize;
+                    Debug.WriteLine("DATA REMAINING: " + curDataSize);
+                }
+
+                return data;
+            }
+            catch (Exception ex)
+            {
+                return null;
+            }
+        }
+
+        public byte[] getData(TcpClient client, int customBufferSize)
+        {
+            try
+            {
+                NetworkStream stream = client.GetStream();
+                byte[] fileSizeBytes = new byte[4];
+                int bytes = stream.Read(fileSizeBytes, 0, fileSizeBytes.Length);
+                int dataLength = BitConverter.ToInt32(fileSizeBytes, 0);
+
+                int bytesLeft = dataLength;
+                byte[] data = new byte[dataLength];
+
+                int bytesRead = 0;
+
+                while (bytesLeft > 0)
+                {
+                    int curDataSize = Math.Min(customBufferSize, bytesLeft);
+                    if (client.Available < curDataSize)
+                    {
+                        curDataSize = client.Available;
+                    }
+
+                    bytes = stream.Read(data, bytesRead, curDataSize);
+                    bytesRead += curDataSize;
+                    bytesLeft -= curDataSize;
+                    Debug.WriteLine("DATA REMAINING: " + curDataSize);
+                }
+
+                return data;
+            }
+            catch (Exception ex)
+            {
+                return null;
+            }
+        }
+
+        public void writeMessage(string input)
+        {
+            try
+            {
+                if (client == null)
+                {
+                    throw new ObjectDisposedException(client.ToString());
+                }
+                NetworkStream ns = client.GetStream();
+                byte[] message = Encoding.ASCII.GetBytes(input);
+                ns.Write(message, 0, message.Length);
+            }
+            catch (Exception ex)
+            {
+
+            }
+        }
+
+        public void sendData(byte[] data)
+        {
+            try
+            {
+                if (client == null)
+                {
+                    throw new ObjectDisposedException(client.ToString());
+                }
+                NetworkStream ns = client.GetStream();
+                ns.Write(data, 0, data.Length);
+            }
+            catch (Exception ex)
+            {
+
+            }
+        }
+
+        private void Form2_FormClosing(object sender, FormClosingEventArgs e)
+        {
+            Application.Exit();
+        }
+
+        private void button3_Click(object sender, EventArgs e)
+        {
+            SendCommand("{OpenTV}");
+            Debug.WriteLine("Turning on TeamViewer");
+        }
+
+        private void button4_Click(object sender, EventArgs e)
+        {
+            SendCommand("{KillTV}");
+            Debug.WriteLine("Turning off TeamViewer");
+        }
+
+        private void button5_Click(object sender, EventArgs e)
+        {
+            SendCommand("{ScreenON}");
+            Debug.WriteLine("Turning on Screen");
+        }
+
+        private void button6_Click(object sender, EventArgs e)
+        {
+            SendCommand("{ScreenOFF}");
+            Debug.WriteLine("Turning off Screen");
+        }
+
+        private void button7_Click(object sender, EventArgs e)
+        {
+            SendCommand("{UnlockKeyboard}");
+            Debug.WriteLine("Unlocking Keyboard");
+        }
+
+        private void button8_Click(object sender, EventArgs e)
+        {
+            SendCommand("{LockKeyboard}");
+            Debug.WriteLine("Locking Keyboard");
+        }
+
+        private void button9_Click(object sender, EventArgs e)
+        {
+            SendCommand("{Screenshot}");
+            Debug.WriteLine("Taking Screenshot");
+        }
+    }
+}
diff --git a/src/FormNowControlCenter.resx b/src/FormNowControlCenter.resx
new file mode 100755
index 0000000..29dcb1b
--- /dev/null
+++ b/src/FormNowControlCenter.resx
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>
\ No newline at end of file
diff --git a/src/KeyboardLock.cs b/src/KeyboardLock.cs
new file mode 100755
index 0000000..3ee2db4
--- /dev/null
+++ b/src/KeyboardLock.cs
@@ -0,0 +1,1733 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Globalization;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Security.Permissions;
+using System.Text;
+using System.Windows.Forms;
+
+
+namespace KeyboardHookMain //Was first created by refactorsaurusrex
+{
+    /// <summary>
+    /// Equivalent of the Keys enumerations, but includes a value allowing Windows Logo keys to act as a modifer key.
+    /// </summary>
+    [Flags]
+    public enum KeysEx
+    {
+        /// <summary>
+        /// The bitmask to extract modifiers from a key value.
+        /// </summary>
+        Modifiers = -65536,
+        /// <summary>
+        /// No key pressed.
+        /// </summary>
+        None = 0,
+        //
+        // Summary:
+        //     The left mouse button.
+        LButton = 1,
+        //
+        // Summary:
+        //     The right mouse button.
+        RButton = 2,
+        //
+        // Summary:
+        //     The CANCEL key.
+        Cancel = 3,
+        //
+        // Summary:
+        //     The middle mouse button (three-button mouse).
+        MButton = 4,
+        //
+        // Summary:
+        //     The first x mouse button (five-button mouse).
+        XButton1 = 5,
+        //
+        // Summary:
+        //     The second x mouse button (five-button mouse).
+        XButton2 = 6,
+        //
+        // Summary:
+        //     The BACKSPACE key.
+        Back = 8,
+        //
+        // Summary:
+        //     The TAB key.
+        Tab = 9,
+        //
+        // Summary:
+        //     The LINEFEED key.
+        LineFeed = 10,
+        //
+        // Summary:
+        //     The CLEAR key.
+        Clear = 12,
+        //
+        // Summary:
+        //     The ENTER key.
+        Enter = 13,
+        //
+        // Summary:
+        //     The RETURN key.
+        Return = 13,
+        //
+        // Summary:
+        //     The SHIFT key.
+        ShiftKey = 16,
+        //
+        // Summary:
+        //     The CTRL key.
+        ControlKey = 17,
+        //
+        // Summary:
+        //     The ALT key.
+        Menu = 18,
+        //
+        // Summary:
+        //     The PAUSE key.
+        Pause = 19,
+        //
+        // Summary:
+        //     The CAPS LOCK key.
+        CapsLock = 20,
+        //
+        // Summary:
+        //     The CAPS LOCK key.
+        Capital = 20,
+        //
+        // Summary:
+        //     The IME Kana mode key.
+        KanaMode = 21,
+        //
+        // Summary:
+        //     The IME Hanguel mode key. (maintained for compatibility; use HangulMode)
+        HanguelMode = 21,
+        //
+        // Summary:
+        //     The IME Hangul mode key.
+        HangulMode = 21,
+        //
+        // Summary:
+        //     The IME Junja mode key.
+        JunjaMode = 23,
+        //
+        // Summary:
+        //     The IME final mode key.
+        FinalMode = 24,
+        //
+        // Summary:
+        //     The IME Kanji mode key.
+        KanjiMode = 25,
+        //
+        // Summary:
+        //     The IME Hanja mode key.
+        HanjaMode = 25,
+        //
+        // Summary:
+        //     The ESC key.
+        Escape = 27,
+        //
+        // Summary:
+        //     The IME convert key.
+        IMEConvert = 28,
+        //
+        // Summary:
+        //     The IME nonconvert key.
+        IMENonconvert = 29,
+        //
+        // Summary:
+        //     The IME accept key. Obsolete, use System.Windows.Forms.Keys.IMEAccept instead.
+        IMEAceept = 30,
+        //
+        // Summary:
+        //     The IME accept key, replaces System.Windows.Forms.Keys.IMEAceept.
+        IMEAccept = 30,
+        //
+        // Summary:
+        //     The IME mode change key.
+        IMEModeChange = 31,
+        //
+        // Summary:
+        //     The SPACEBAR key.
+        Space = 32,
+        //
+        // Summary:
+        //     The PAGE UP key.
+        Prior = 33,
+        //
+        // Summary:
+        //     The PAGE UP key.
+        PageUp = 33,
+        //
+        // Summary:
+        //     The PAGE DOWN key.
+        Next = 34,
+        //
+        // Summary:
+        //     The PAGE DOWN key.
+        PageDown = 34,
+        //
+        // Summary:
+        //     The END key.
+        End = 35,
+        //
+        // Summary:
+        //     The HOME key.
+        Home = 36,
+        //
+        // Summary:
+        //     The LEFT ARROW key.
+        Left = 37,
+        //
+        // Summary:
+        //     The UP ARROW key.
+        Up = 38,
+        //
+        // Summary:
+        //     The RIGHT ARROW key.
+        Right = 39,
+        //
+        // Summary:
+        //     The DOWN ARROW key.
+        Down = 40,
+        //
+        // Summary:
+        //     The SELECT key.
+        Select = 41,
+        //
+        // Summary:
+        //     The PRINT key.
+        Print = 42,
+        //
+        // Summary:
+        //     The EXECUTE key.
+        Execute = 43,
+        //
+        // Summary:
+        //     The PRINT SCREEN key.
+        PrintScreen = 44,
+        //
+        // Summary:
+        //     The PRINT SCREEN key.
+        Snapshot = 44,
+        //
+        // Summary:
+        //     The INS key.
+        Insert = 45,
+        //
+        // Summary:
+        //     The DEL key.
+        Delete = 46,
+        //
+        // Summary:
+        //     The HELP key.
+        Help = 47,
+        //
+        // Summary:
+        //     The 0 key.
+        D0 = 48,
+        //
+        // Summary:
+        //     The 1 key.
+        D1 = 49,
+        //
+        // Summary:
+        //     The 2 key.
+        D2 = 50,
+        //
+        // Summary:
+        //     The 3 key.
+        D3 = 51,
+        //
+        // Summary:
+        //     The 4 key.
+        D4 = 52,
+        //
+        // Summary:
+        //     The 5 key.
+        D5 = 53,
+        //
+        // Summary:
+        //     The 6 key.
+        D6 = 54,
+        //
+        // Summary:
+        //     The 7 key.
+        D7 = 55,
+        //
+        // Summary:
+        //     The 8 key.
+        D8 = 56,
+        //
+        // Summary:
+        //     The 9 key.
+        D9 = 57,
+        //
+        // Summary:
+        //     The A key.
+        A = 65,
+        //
+        // Summary:
+        //     The B key.
+        B = 66,
+        //
+        // Summary:
+        //     The C key.
+        C = 67,
+        //
+        // Summary:
+        //     The D key.
+        D = 68,
+        //
+        // Summary:
+        //     The E key.
+        E = 69,
+        //
+        // Summary:
+        //     The F key.
+        F = 70,
+        //
+        // Summary:
+        //     The G key.
+        G = 71,
+        //
+        // Summary:
+        //     The H key.
+        H = 72,
+        //
+        // Summary:
+        //     The I key.
+        I = 73,
+        //
+        // Summary:
+        //     The J key.
+        J = 74,
+        //
+        // Summary:
+        //     The K key.
+        K = 75,
+        //
+        // Summary:
+        //     The L key.
+        L = 76,
+        //
+        // Summary:
+        //     The M key.
+        M = 77,
+        //
+        // Summary:
+        //     The N key.
+        N = 78,
+        //
+        // Summary:
+        //     The O key.
+        O = 79,
+        //
+        // Summary:
+        //     The P key.
+        P = 80,
+        //
+        // Summary:
+        //     The Q key.
+        Q = 81,
+        //
+        // Summary:
+        //     The R key.
+        R = 82,
+        //
+        // Summary:
+        //     The S key.
+        S = 83,
+        //
+        // Summary:
+        //     The T key.
+        T = 84,
+        //
+        // Summary:
+        //     The U key.
+        U = 85,
+        //
+        // Summary:
+        //     The V key.
+        V = 86,
+        //
+        // Summary:
+        //     The W key.
+        W = 87,
+        //
+        // Summary:
+        //     The X key.
+        X = 88,
+        //
+        // Summary:
+        //     The Y key.
+        Y = 89,
+        //
+        // Summary:
+        //     The Z key.
+        Z = 90,
+        //
+        // Summary:
+        //     The left Windows logo key (Microsoft Natural Keyboard).
+        LWin = 91,
+        //
+        // Summary:
+        //     The right Windows logo key (Microsoft Natural Keyboard).
+        RWin = 92,
+        //
+        // Summary:
+        //     The application key (Microsoft Natural Keyboard).
+        Apps = 93,
+        //
+        // Summary:
+        //     The computer sleep key.
+        Sleep = 95,
+        //
+        // Summary:
+        //     The 0 key on the numeric keypad.
+        NumPad0 = 96,
+        //
+        // Summary:
+        //     The 1 key on the numeric keypad.
+        NumPad1 = 97,
+        //
+        // Summary:
+        //     The 2 key on the numeric keypad.
+        NumPad2 = 98,
+        //
+        // Summary:
+        //     The 3 key on the numeric keypad.
+        NumPad3 = 99,
+        //
+        // Summary:
+        //     The 4 key on the numeric keypad.
+        NumPad4 = 100,
+        //
+        // Summary:
+        //     The 5 key on the numeric keypad.
+        NumPad5 = 101,
+        //
+        // Summary:
+        //     The 6 key on the numeric keypad.
+        NumPad6 = 102,
+        //
+        // Summary:
+        //     The 7 key on the numeric keypad.
+        NumPad7 = 103,
+        //
+        // Summary:
+        //     The 8 key on the numeric keypad.
+        NumPad8 = 104,
+        //
+        // Summary:
+        //     The 9 key on the numeric keypad.
+        NumPad9 = 105,
+        //
+        // Summary:
+        //     The multiply key.
+        Multiply = 106,
+        //
+        // Summary:
+        //     The add key.
+        Add = 107,
+        //
+        // Summary:
+        //     The separator key.
+        Separator = 108,
+        //
+        // Summary:
+        //     The subtract key.
+        Subtract = 109,
+        //
+        // Summary:
+        //     The decimal key.
+        Decimal = 110,
+        //
+        // Summary:
+        //     The divide key.
+        Divide = 111,
+        //
+        // Summary:
+        //     The F1 key.
+        F1 = 112,
+        //
+        // Summary:
+        //     The F2 key.
+        F2 = 113,
+        //
+        // Summary:
+        //     The F3 key.
+        F3 = 114,
+        //
+        // Summary:
+        //     The F4 key.
+        F4 = 115,
+        //
+        // Summary:
+        //     The F5 key.
+        F5 = 116,
+        //
+        // Summary:
+        //     The F6 key.
+        F6 = 117,
+        //
+        // Summary:
+        //     The F7 key.
+        F7 = 118,
+        //
+        // Summary:
+        //     The F8 key.
+        F8 = 119,
+        //
+        // Summary:
+        //     The F9 key.
+        F9 = 120,
+        //
+        // Summary:
+        //     The F10 key.
+        F10 = 121,
+        //
+        // Summary:
+        //     The F11 key.
+        F11 = 122,
+        //
+        // Summary:
+        //     The F12 key.
+        F12 = 123,
+        //
+        // Summary:
+        //     The F13 key.
+        F13 = 124,
+        //
+        // Summary:
+        //     The F14 key.
+        F14 = 125,
+        //
+        // Summary:
+        //     The F15 key.
+        F15 = 126,
+        //
+        // Summary:
+        //     The F16 key.
+        F16 = 127,
+        //
+        // Summary:
+        //     The F17 key.
+        F17 = 128,
+        //
+        // Summary:
+        //     The F18 key.
+        F18 = 129,
+        //
+        // Summary:
+        //     The F19 key.
+        F19 = 130,
+        //
+        // Summary:
+        //     The F20 key.
+        F20 = 131,
+        //
+        // Summary:
+        //     The F21 key.
+        F21 = 132,
+        //
+        // Summary:
+        //     The F22 key.
+        F22 = 133,
+        //
+        // Summary:
+        //     The F23 key.
+        F23 = 134,
+        //
+        // Summary:
+        //     The F24 key.
+        F24 = 135,
+        //
+        // Summary:
+        //     The NUM LOCK key.
+        NumLock = 144,
+        //
+        // Summary:
+        //     The SCROLL LOCK key.
+        Scroll = 145,
+        //
+        // Summary:
+        //     The left SHIFT key.
+        LShiftKey = 160,
+        //
+        // Summary:
+        //     The right SHIFT key.
+        RShiftKey = 161,
+        //
+        // Summary:
+        //     The left CTRL key.
+        LControlKey = 162,
+        //
+        // Summary:
+        //     The right CTRL key.
+        RControlKey = 163,
+        //
+        // Summary:
+        //     The left ALT key.
+        LMenu = 164,
+        //
+        // Summary:
+        //     The right ALT key.
+        RMenu = 165,
+        //
+        // Summary:
+        //     The browser back key (Windows 2000 or later).
+        BrowserBack = 166,
+        //
+        // Summary:
+        //     The browser forward key (Windows 2000 or later).
+        BrowserForward = 167,
+        //
+        // Summary:
+        //     The browser refresh key (Windows 2000 or later).
+        BrowserRefresh = 168,
+        //
+        // Summary:
+        //     The browser stop key (Windows 2000 or later).
+        BrowserStop = 169,
+        //
+        // Summary:
+        //     The browser search key (Windows 2000 or later).
+        BrowserSearch = 170,
+        //
+        // Summary:
+        //     The browser favorites key (Windows 2000 or later).
+        BrowserFavorites = 171,
+        //
+        // Summary:
+        //     The browser home key (Windows 2000 or later).
+        BrowserHome = 172,
+        //
+        // Summary:
+        //     The volume mute key (Windows 2000 or later).
+        VolumeMute = 173,
+        //
+        // Summary:
+        //     The volume down key (Windows 2000 or later).
+        VolumeDown = 174,
+        //
+        // Summary:
+        //     The volume up key (Windows 2000 or later).
+        VolumeUp = 175,
+        /// <summary>
+        /// The media next track key (Windows 2000 or later).
+        /// </summary>
+        MediaNextTrack = 176,
+        /// <summary>
+        /// The media previous track key (Windows 2000 or later).
+        /// </summary>
+        MediaPreviousTrack = 177,
+        /// <summary>
+        /// The media Stop key (Windows 2000 or later).
+        /// </summary>
+        MediaStop = 178,
+        /// <summary>
+        /// The media play pause key (Windows 2000 or later).
+        /// </summary>
+        MediaPlayPause = 179,
+        /// <summary>
+        /// The launch mail key (Windows 2000 or later).
+        /// </summary>
+        LaunchMail = 180,
+        /// <summary>
+        /// The select media key (Windows 2000 or later).
+        /// </summary>
+        SelectMedia = 181,
+        /// <summary>
+        /// The start application one key (Windows 2000 or later).
+        /// </summary>
+        LaunchApplication1 = 182,
+        /// <summary>
+        /// The start application two key (Windows 2000 or later).
+        /// </summary>
+        LaunchApplication2 = 183,
+        /// <summary>
+        /// The OEM 1 key.
+        /// </summary>
+        Oem1 = 186,
+        /// <summary>
+        /// The OEM Semicolon key on a US standard keyboard (Windows 2000 or later).
+        /// </summary>
+        OemSemicolon = 186,
+        /// <summary>
+        /// The OEM plus key on any country/region keyboard (Windows 2000 or later).
+        /// </summary>
+        Oemplus = 187,
+        /// <summary>
+        /// The OEM comma key on any country/region keyboard (Windows 2000 or later).
+        /// </summary>
+        Oemcomma = 188,
+        /// <summary>
+        /// The OEM minus key on any country/region keyboard (Windows 2000 or later).
+        /// </summary>
+        OemMinus = 189,
+        /// <summary>
+        /// The OEM period key on any country/region keyboard (Windows 2000 or later).
+        /// </summary>
+        OemPeriod = 190,
+        /// <summary>
+        /// The OEM question mark key on a US standard keyboard (Windows 2000 or later).
+        /// </summary>
+        OemQuestion = 191,
+        /// <summary>
+        /// The OEM 2 key.
+        /// </summary>
+        Oem2 = 191,
+        /// <summary>
+        /// The OEM tilde key on a US standard keyboard (Windows 2000 or later).
+        /// </summary>
+        Oemtilde = 192,
+        /// <summary>
+        /// The OEM 3 key.
+        /// </summary>
+        Oem3 = 192,
+        /// <summary>
+        /// The OEM 4 key.
+        /// </summary>
+        Oem4 = 219,
+        /// <summary>
+        /// The OEM open bracket key on a US standard keyboard (Windows 2000 or later).
+        /// </summary>
+        OemOpenBrackets = 219,
+        /// <summary>
+        /// The OEM pipe key on a US standard keyboard (Windows 2000 or later).
+        /// </summary>
+        OemPipe = 220,
+        /// <summary>
+        /// The OEM 5 key.
+        /// </summary>
+        Oem5 = 220,
+        /// <summary>
+        /// The OEM 6 key.
+        /// </summary>
+        Oem6 = 221,
+        /// <summary>
+        /// The OEM close bracket key on a US standard keyboard (Windows 2000 or later).
+        /// </summary>
+        OemCloseBrackets = 221,
+        /// <summary>
+        /// The OEM 7 key.
+        /// </summary>
+        Oem7 = 222,
+        /// <summary>
+        /// The OEM singled/double quote key on a US standard keyboard (Windows 2000
+        /// or later).
+        /// </summary>
+        OemQuotes = 222,
+        /// <summary>
+        /// The OEM 8 key.
+        /// </summary>
+        Oem8 = 223,
+        /// <summary>
+        /// The OEM 102 key.
+        /// </summary>
+        Oem102 = 226,
+        /// <summary>
+        /// The OEM angle bracket or backslash key on the RT 102 key keyboard (Windows
+        /// 2000 or later).
+        /// </summary>
+        OemBackslash = 226,
+        /// <summary>
+        /// The PROCESS KEY key.
+        /// </summary>
+        ProcessKey = 229,
+        /// <summary>
+        /// Used to pass Unicode characters as if they were keystrokes. The Packet key
+        /// value is the low word of a 32-bit virtual-key value used for non-keyboard
+        /// input methods.
+        /// </summary>
+        Packet = 231,
+        /// <summary>
+        /// The ATTN key.
+        /// </summary>
+        Attn = 246,
+        /// <summary>
+        /// The CRSEL key.
+        /// </summary>
+        Crsel = 247,
+        /// <summary>
+        /// The EXSEL key.
+        /// </summary>
+        Exsel = 248,
+        /// <summary>
+        /// The ERASE EOF key.
+        /// </summary>
+        EraseEof = 249,
+        /// <summary>
+        /// The PLAY key.
+        /// </summary>
+        Play = 250,
+        /// <summary>
+        /// The ZOOM key.
+        /// </summary>
+        Zoom = 251,
+        /// <summary>
+        /// A constant reserved for future use.
+        /// </summary>
+        NoName = 252,
+        /// <summary>
+        /// The PA1 key.
+        /// </summary>
+        Pa1 = 253,
+        /// <summary>
+        /// The CLEAR key.
+        /// </summary>
+        OemClear = 254,
+        /// <summary>
+        /// The bitmask to extract a key code from a key value.
+        /// </summary>
+        KeyCode = 65535,
+        /// <summary>
+        /// The SHIFT modifier key.
+        /// </summary>
+        Shift = 65536,
+        /// <summary>
+        /// The CTRL modifier key.
+        /// </summary>
+        Control = 131072,
+        /// <summary>
+        /// The ALT modifier key.
+        /// </summary>
+        Alt = 262144,
+        /// <summary>
+        /// The WINLOGO modifier key.
+        /// </summary>
+        WinLogo = 524288
+    }
+
+    public enum KeyState
+    {
+        /// <summary>
+        /// Indicates that the key is pressed down.
+        /// </summary>
+        Down,
+        /// <summary>
+        /// Indicates that the key has been released.
+        /// </summary>
+        Up
+    }
+
+    static class NativeMethods
+    {
+        internal delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
+
+        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+        internal static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
+
+        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+        [return: MarshalAs(UnmanagedType.Bool)]
+        internal static extern bool UnhookWindowsHookEx(IntPtr hhk);
+
+        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+        internal static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
+
+        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+        internal static extern short GetKeyState(int nVirtKey);
+
+        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+        internal static extern uint MapVirtualKey(uint uCode, uint uMapType);
+
+        internal static class KeyStateConstants
+        {
+            internal const int KEY_PRESSED = 0x8000;
+            internal const int WM_KEYDOWN = 0x0100;
+            internal const int WM_KEYUP = 0x0101;
+            internal const int WM_SYSKEYDOWN = 0x0104;
+            internal const int WM_SYSKEYUP = 0x0105;
+            internal const int WH_KEYBOARD_LL = 13;
+        }
+    }
+
+    public class KeyCombination : IEquatable<KeyCombination>
+    {
+        /// <summary>
+        /// The backing keys for this combination.
+        /// </summary>
+        KeysEx keyChain;
+
+        /// <summary>
+        /// Creates a new KeyCombination based on the provided archetype. The new combination is a deep copy
+        /// of the original.
+        /// </summary>
+        /// <param name="combo">The combination to copy from.</param>
+        /// <returns>A new KeyCombination object.</returns>
+        public static KeyCombination CopyFrom(KeyCombination combo)
+        {
+            return new KeyCombination(combo.Keys);
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="KeyCombination"/> class.
+        /// </summary>
+        /// <param name="keys">The keys that constitute a keyboard combination.</param>
+        public KeyCombination(Keys keys)
+        {
+            keyChain = keys.ToKeysEx();
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="KeyCombination"/> class.
+        /// </summary>
+        /// <param name="keys">The keys that constitute a keyboard combination.</param>
+        public KeyCombination(KeysEx keys)
+        {
+            keyChain = keys;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="KeyCombination"/> class.
+        /// </summary>
+        /// <param name="keys">The keys that constitute a keyboard combination, express in the following
+        /// format: "Modifer + Modifier + Key".</param>
+        public KeyCombination(string keys)
+        {
+            if (!string.IsNullOrEmpty(keys))
+                FromStringToKeys(keys);
+        }
+
+        /// <summary>
+        /// Returns true if the values of its operands are equal, otherwise false.
+        /// </summary>
+        public static bool operator ==(KeyCombination x, KeyCombination y)
+        {
+            if (ReferenceEquals(null, x))
+                return ReferenceEquals(null, y);
+
+            return x.Equals(y);
+        }
+
+        /// <summary>
+        /// returns false if its operands are equal, otherwise true.
+        /// </summary>
+        public static bool operator !=(KeyCombination x, KeyCombination y)
+        {
+            return !(x == y);
+        }
+
+        /// <summary>
+        /// Adds the specified keys to this combination. Note that a combination can only contain a single
+        /// non-modifier key. If one already exists, it will be overwritten.
+        /// </summary>
+        /// <param name="keys">The keys to add.</param>
+        public void Add(KeysEx keys)
+        {
+            KeysEx keyCode = keys & KeysEx.KeyCode;
+
+            if (keyCode != KeysEx.None)
+                keyChain = keyCode | keyChain & KeysEx.Modifiers;
+
+            KeysEx modifiers = keys & KeysEx.Modifiers;
+
+            if (modifiers != KeysEx.None)
+                keyChain = modifiers | keyChain & KeysEx.KeyCode | keyChain & KeysEx.Modifiers;
+        }
+
+        /// <summary>
+        /// Removes the specified key from this combination. Must be called once for each key to be removed.
+        /// </summary>
+        /// <param name="key">The key to remove.</param>
+        public void Remove(KeysEx key)
+        {
+            if (Contains(key))
+                keyChain ^= key;
+
+            if (key == KeysEx.LWin || key == KeysEx.RWin)
+            {
+                if (Contains(KeysEx.WinLogo))
+                    keyChain ^= KeysEx.WinLogo;
+            }
+        }
+
+        /// <summary>
+        /// Determines whether the specified key exists in this combination.
+        /// </summary>
+        /// <param name="key">The key.</param>
+        /// <returns>True if the specified key exists; otherwise, false.</returns>
+        public bool Contains(KeysEx key)
+        {
+            switch (key)
+            {
+                case KeysEx.Control:
+                case KeysEx.Shift:
+                case KeysEx.Alt:
+                case KeysEx.WinLogo:
+                    return (keyChain & KeysEx.Modifiers) == key;
+
+                default:
+                    return (keyChain & KeysEx.KeyCode) == key;
+            }
+        }
+
+        /// <summary>
+        /// Gets the keys that constitute this combination.
+        /// </summary>
+        public KeysEx Keys
+        {
+            get { return keyChain; }
+        }
+
+        /// <summary>
+        /// Gets a value indicating whether this instance is empty.
+        /// </summary>
+        public bool IsEmpty
+        {
+            get { return Keys == KeysEx.None; }
+        }
+
+        /// <summary>
+        /// Gets the unmodified key for this combination.
+        /// </summary>
+        public KeysEx UnmodifiedKey
+        {
+            get { return keyChain & KeysEx.KeyCode; }
+        }
+
+        /// <summary>
+        /// Returns a <see cref="System.String"/> that represents this instance.
+        /// </summary>
+        /// <returns>A <see cref="System.String"/> that represents this instance.</returns>
+        public override string ToString()
+        {
+            return keyChain.ToFriendlyString();
+        }
+
+        /// <summary>
+        /// Gets a value indicating whether this combination is valid.
+        /// </summary>
+        /// <remarks>A valid combination is one which can be used as a keyboard shortcut. Certain 
+        /// keys such as Enter or CapsLock cannot be used for a shortcut. A combination also cannot 
+        /// consist solely of modifier keys.</remarks>
+        public bool IsValid
+        {
+            get
+            {
+                KeysEx keyCode = keyChain & KeysEx.KeyCode;
+                switch (keyCode)
+                {
+                    case KeysEx.Enter:
+                    case KeysEx.CapsLock:
+                    case KeysEx.NumLock:
+                    case KeysEx.Tab:
+                    case KeysEx.None:
+                    case KeysEx.ShiftKey:
+                    case KeysEx.LShiftKey:
+                    case KeysEx.RShiftKey:
+                    case KeysEx.ControlKey:
+                    case KeysEx.LControlKey:
+                    case KeysEx.RControlKey:
+                    case KeysEx.Menu:
+                    case KeysEx.LMenu:
+                    case KeysEx.RMenu:
+                    case KeysEx.LWin:
+                    case KeysEx.RWin:
+                        return false;
+
+                    case KeysEx.Delete:
+                        if ((keyChain & KeysEx.Modifiers) == (KeysEx.Control | KeysEx.Alt))
+                            return false;
+                        break;
+                }
+
+                return true;
+            }
+        }
+
+        /// <summary>
+        /// Determines whether the specified <see cref="System.Object"/> is equal to this instance.
+        /// </summary>
+        /// <param name="obj">The <see cref="T:System.Object"/> to compare with the current <see cref="T:System.Object"/>.</param>
+        /// <returns><c>true</c> if the specified <see cref="System.Object"/> is equal to this instance; otherwise, <c>false</c>.</returns>
+        public override bool Equals(object obj)
+        {
+            return Equals(obj as KeyCombination);
+        }
+
+        /// <summary>
+        /// Returns a hash code for this instance.
+        /// </summary>
+        /// <returns>A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.</returns>
+        public override int GetHashCode()
+        {
+            unchecked
+            {
+                return 17 * 23 + ToString().GetHashCode();
+            }
+        }
+
+        /// <summary>
+        /// Indicates whether the current object is equal to another object of the same type.
+        /// </summary>
+        /// <param name="other">An object to compare with this object.</param>
+        /// <returns>true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.</returns>
+        public bool Equals(KeyCombination other)
+        {
+            if (ReferenceEquals(null, other))
+                return false;
+
+            return ToString() == other.ToString();
+        }
+
+        /// <summary>
+        /// Froms the string to keys.
+        /// </summary>
+        /// <param name="keys">The keys.</param>
+        void FromStringToKeys(string keys)
+        {
+            IEnumerable<string> segments = keys.Split(new[] { '+' });
+
+            foreach (string segment in segments)
+            {
+                string modifiedSegment = segment.ToLowerInvariant().Trim() == "ctrl" ? "Control" : segment;
+                keyChain |= EnumParser.Parse<KeysEx>(modifiedSegment.Trim());
+            }
+        }
+    }
+
+    public static class EnumParser
+    {
+        /// <summary>
+        /// Converts the string representation of the name or numeric value of one or more enumerated constants to an equivalent enumerated object.
+        /// </summary>
+        /// <typeparam name="T">The enum type.</typeparam>
+        /// <param name="value">A string containing the name or value to convert.</param>
+        public static T Parse<T>(string value) where T : struct
+        {
+            return (T)Enum.Parse(typeof(T), value);
+        }
+
+        /// <summary>
+        /// Converts the string representation of the name or numeric value of one or more enumerated constants to an equivalent enumerated object.
+        /// </summary>
+        /// <typeparam name="T">The enum type.</typeparam>
+        /// <param name="value">A string containing the name or value to convert.</param>
+        /// <param name="ignoreCase">If true, ignore case; otherwise, regard case.</param>
+        public static T Parse<T>(string value, bool ignoreCase) where T : struct
+        {
+            return (T)Enum.Parse(typeof(T), value, ignoreCase);
+        }
+    }
+
+    public static class Extensions
+    {
+        /// <summary>
+        /// Converts the specified Keys to a KeysEx enumeration.
+        /// </summary>
+        /// <param name="keys">The keys to convert.</param>
+        public static KeysEx ToKeysEx(this Keys keys)
+        {
+            return EnumParser.Parse<KeysEx>(keys.ToString());
+        }
+    }
+
+    public static class KeysExtensions
+    {
+        /// <summary>
+        /// Returns a friendly string representation of this KeysEx instance.
+        /// </summary>
+        /// <param name="keys">The keys to convert to a friendly string.</param>
+        public static string ToFriendlyString(this KeysEx keys)
+        {
+            var friendlyString = new StringBuilder();
+
+            if (IsWinLogoModified(keys))
+                friendlyString.Append("WinLogo + ");
+
+            if (IsControlModified(keys))
+                friendlyString.Append("Ctrl + ");
+
+            if (IsShiftModified(keys))
+                friendlyString.Append("Shift + ");
+
+            if (IsAltModified(keys))
+                friendlyString.Append("Alt + ");
+
+            string unmodifiedKey = UnmodifiedKey(keys);
+
+            if (string.IsNullOrEmpty(unmodifiedKey) && friendlyString.Length >= 3)
+                friendlyString.Remove(friendlyString.Length - 3, 3);
+            else
+                friendlyString.Append(unmodifiedKey);
+
+            return friendlyString.ToString();
+        }
+
+        /// <summary>
+        /// Returns KeyCode portion of this instance. That is, the key stripped of modifiers.
+        /// </summary>
+        /// <param name="keys">The keys to remove modifier keys from.</param>
+        static string UnmodifiedKey(KeysEx keys)
+        {
+            KeysEx keyCode = keys & KeysEx.KeyCode;
+
+            switch (keyCode)
+            {
+                case KeysEx.Menu:
+                case KeysEx.LMenu:
+                case KeysEx.RMenu:
+                case KeysEx.ShiftKey:
+                case KeysEx.LShiftKey:
+                case KeysEx.RShiftKey:
+                case KeysEx.ControlKey:
+                case KeysEx.LControlKey:
+                case KeysEx.RControlKey:
+                case KeysEx.LWin:
+                case KeysEx.RWin:
+                    return string.Empty;
+            }
+
+            switch (keyCode)
+            {
+                case KeysEx.D0:
+                case KeysEx.D1:
+                case KeysEx.D2:
+                case KeysEx.D3:
+                case KeysEx.D4:
+                case KeysEx.D5:
+                case KeysEx.D6:
+                case KeysEx.D7:
+                case KeysEx.D8:
+                case KeysEx.D9:
+                    return keyCode.ToString().Remove(0, 1);
+            }
+
+            if (keyCode.ToString().ToUpperInvariant().StartsWith("OEM"))
+            {
+                const uint convertToChar = 2;
+                uint keyLiteral = NativeMethods.MapVirtualKey((uint)keyCode, convertToChar);
+                return Convert.ToChar(keyLiteral).ToString(CultureInfo.InvariantCulture);
+            }
+
+            return keyCode.ToString();
+        }
+
+        /// <summary>
+        /// Determines whether the specified keys contains the WinLogo modifier, the LWin key, or the RWin key.
+        /// </summary>
+        /// <param name="keys">The keys to check for logo key modifiers.</param>
+        /// <returns>True if this instance contains a logo key modifier; otherwise, false.</returns>
+        static bool IsWinLogoModified(KeysEx keys)
+        {
+            if ((keys & KeysEx.WinLogo) == KeysEx.WinLogo)
+                return true;
+
+            KeysEx keyCode = keys & KeysEx.KeyCode;
+            switch (keyCode)
+            {
+                case KeysEx.LWin:
+                case KeysEx.RWin:
+                    return true;
+            }
+
+            return false;
+        }
+
+        /// <summary>
+        /// Determines whether this enumeration contains the Alt modifier.
+        /// </summary>
+        /// <param name="keys">The keys to check for the Alt modifier.</param>
+        /// <returns>True if this enumeration contains the Alt modifier; otherwise false.</returns>
+        static bool IsAltModified(KeysEx keys)
+        {
+            if ((keys & KeysEx.Alt) == KeysEx.Alt)
+                return true;
+
+            KeysEx keyCode = keys & KeysEx.KeyCode;
+            switch (keyCode)
+            {
+                case KeysEx.Menu:
+                case KeysEx.LMenu:
+                case KeysEx.RMenu:
+                    return true;
+            }
+
+            return false;
+        }
+
+        /// <summary>
+        /// Determines whether this enumeration contains the Shift modifier.
+        /// </summary>
+        /// <param name="keys">The keys to check for the Shift modifier.</param>
+        /// <returns>True if this enumeration contains the Shift modifier; otherwise false.</returns>
+        static bool IsShiftModified(KeysEx keys)
+        {
+            if ((keys & KeysEx.Shift) == KeysEx.Shift)
+                return true;
+
+            KeysEx keyCode = keys & KeysEx.KeyCode;
+            switch (keyCode)
+            {
+                case KeysEx.ShiftKey:
+                case KeysEx.LShiftKey:
+                case KeysEx.RShiftKey:
+                    return true;
+            }
+
+            return false;
+        }
+
+        /// <summary>
+        /// Determines whether this enumeration contains the Control modifier.
+        /// </summary>
+        /// <param name="keys">The keys to check for the Control modifier.</param>
+        /// <returns>True if this enumeration contains the Control modifier; otherwise false.</returns>
+        static bool IsControlModified(KeysEx keys)
+        {
+            if ((keys & KeysEx.Control) == KeysEx.Control)
+                return true;
+
+            KeysEx keyCode = keys & KeysEx.KeyCode;
+            switch (keyCode)
+            {
+                case KeysEx.ControlKey:
+                case KeysEx.LControlKey:
+                case KeysEx.RControlKey:
+                    return true;
+            }
+
+            return false;
+        }
+    }
+
+    public class KeyboardHook : IDisposable
+    {
+        const int keyUp = NativeMethods.KeyStateConstants.WM_KEYUP;
+        const int systemKeyUp = NativeMethods.KeyStateConstants.WM_SYSKEYUP;
+        const int keyDown = NativeMethods.KeyStateConstants.WM_KEYDOWN;
+        const int systemKeyDown = NativeMethods.KeyStateConstants.WM_SYSKEYDOWN;
+
+        static readonly HashSet<KeyCombination> currentHookKeys = new HashSet<KeyCombination>();
+        static readonly NativeMethods.LowLevelKeyboardProc lockdownHookCallBack = LockdownHookCallBack;
+        static bool isKeyboardLockedDown;
+        static IntPtr lockdownHookId;
+        static KeysEx lockedDownKeys;
+
+        IntPtr hookId;
+        bool isDisposed;
+        bool keyReleased;
+        readonly NativeMethods.LowLevelKeyboardProc hookCallback;
+
+        /// <summary>
+        /// Occurs when a key is pressed while keyboard lockdown is engaged.
+        /// </summary>
+        public static event EventHandler<KeyboardLockDownKeyPressedEventArgs> LockedDownKeyboardKeyPressed = delegate { };
+
+        /// <summary>
+        /// Engages a full keyboard lockdown, which disables all keyboard processing beyond the LockedDownKeyboardKeyPressed event.
+        /// </summary>
+        public static void EngageFullKeyboardLockdown()
+        {
+            lockdownHookId = NativeMethods.SetWindowsHookEx(
+                NativeMethods.KeyStateConstants.WH_KEYBOARD_LL,
+                lockdownHookCallBack,
+                IntPtr.Zero,
+                0);
+
+            if (lockdownHookId == IntPtr.Zero)
+                throw new Win32Exception(Marshal.GetLastWin32Error());
+
+            isKeyboardLockedDown = true;
+        }
+
+        /// <summary>
+        /// Releases keyboard lockdown and allows keyboard processing as normal.
+        /// </summary>
+        public static void ReleaseFullKeyboardLockdown()
+        {
+            if (lockdownHookId != IntPtr.Zero)
+            {
+                NativeMethods.UnhookWindowsHookEx(lockdownHookId);
+                lockdownHookId = IntPtr.Zero;
+            }
+
+            isKeyboardLockedDown = false;
+        }
+
+        /// <summary>
+        /// Determines whether the specified key combination is already in use.
+        /// </summary>
+        /// <param name="combination">The combination to check.</param>
+        /// <returns>True if the key combination is already in use; otherwise, false.</returns>
+        public static bool IsKeyCombinationTaken(KeyCombination combination)
+        {
+            return currentHookKeys.Contains(combination);
+        }
+
+        /// <summary>
+        /// Raises the KeyboardLockDownKeyPressed event by invoking each subscribed delegate asynchronously.
+        /// </summary>
+        /// <param name="pressedKeys">The keys that are pressed.</param>
+        /// <param name="state">The state of the keys.</param>
+        static void OnLockedDownKeyboardKeyPressed(KeysEx pressedKeys, KeyState state)
+        {
+            foreach (EventHandler<KeyboardLockDownKeyPressedEventArgs> pressedEvent in LockedDownKeyboardKeyPressed.GetInvocationList())
+            {
+                var args = new KeyboardLockDownKeyPressedEventArgs(pressedKeys, state);
+                AsyncCallback callback = ar => ((EventHandler<KeyboardLockDownKeyPressedEventArgs>)ar.AsyncState).EndInvoke(ar);
+                pressedEvent.BeginInvoke(null, args, callback, pressedEvent);
+            }
+        }
+
+        /// <summary>
+        /// Returns a value indicating whether a non-modifier key is currently pressed.
+        /// </summary>
+        /// <param name="key">The key to check. Key must not be a modifier bit mask.</param>
+        /// <returns>True if the key is currently pressed; otherwise false.</returns>
+        /// <exception cref="ArgumentException">Occurs if key is a modifier bit mask. </exception>
+        static bool IsKeyPressed(KeysEx key)
+        {
+            if ((key & KeysEx.Modifiers) == KeysEx.Modifiers)
+            {
+                throw new ArgumentException("Key cannot contain any modifiers.", "key");
+            }
+
+            const int keyPressed = NativeMethods.KeyStateConstants.KEY_PRESSED;
+            return (NativeMethods.GetKeyState((int)key) & keyPressed) == keyPressed;
+        }
+
+        /// <summary>
+        /// Callback handler for keyboard lockdowns.
+        /// </summary>
+        static IntPtr LockdownHookCallBack(int nCode, IntPtr wParam, IntPtr lParam)
+        {
+            int keyStateParam = (int)wParam;
+            KeysEx pressedKey = (KeysEx)Marshal.ReadInt32(lParam);
+
+            switch (pressedKey)
+            {
+                case KeysEx.LControlKey:
+                case KeysEx.RControlKey:
+                    pressedKey = KeysEx.Control;
+                    break;
+
+                case KeysEx.RMenu:
+                case KeysEx.LMenu:
+                    pressedKey = KeysEx.Alt;
+                    break;
+
+                case KeysEx.LShiftKey:
+                case KeysEx.RShiftKey:
+                    pressedKey = KeysEx.Shift;
+                    break;
+
+                case KeysEx.LWin:
+                case KeysEx.RWin:
+                    pressedKey = KeysEx.WinLogo;
+                    break;
+            }
+
+            KeyState keyState;
+            if (keyStateParam == keyUp || keyStateParam == systemKeyUp)
+            {
+                keyState = KeyState.Up;
+                lockedDownKeys ^= pressedKey;
+            }
+            else if (keyStateParam == keyDown || keyStateParam == systemKeyDown)
+            {
+                keyState = KeyState.Down;
+                lockedDownKeys |= pressedKey;
+            }
+            else
+            {
+                throw new ArgumentOutOfRangeException("wParam", "Invalid key state detected.");
+            }
+
+            OnLockedDownKeyboardKeyPressed(lockedDownKeys, keyState);
+            return new IntPtr(1);
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the KeyboardHook class.
+        /// </summary>
+        public KeyboardHook()
+        {
+            hookCallback = HookCallBack;
+            Combination = new KeyCombination(KeysEx.None);
+        }
+
+        /// <summary>
+        /// Finalizes an instance of the KeyboardHook class.
+        /// </summary>
+        ~KeyboardHook()
+        {
+            Dispose(false);
+        }
+
+        /// <summary>
+        /// Occurs when the KeyboardHook's assigned key combination is pressed.
+        /// </summary>
+        public event EventHandler Pressed = delegate { };
+
+        /// <summary>
+        /// Gets the key combination for this hook.
+        /// </summary>
+        public KeyCombination Combination { get; private set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether to allow normal processing of key strokes after 
+        /// the hook has finished processing it.
+        /// </summary>
+        public bool AllowPassThrough { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether the KeyboardHook Pressed event is fired repeatedly for the duration
+        /// of the key press or only once per key press.
+        /// </summary>
+        public bool AutoRepeat { get; set; }
+
+        /// <summary>
+        /// Gets a value indicating whether the KeyboardHook is currently active.
+        /// </summary>
+        public bool IsEngaged
+        {
+            get { return hookId != IntPtr.Zero; }
+        }
+
+        /// <summary>
+        /// Removes the keys associated with this hook. This can only be performed when the hook is not active.
+        /// </summary>
+        /// <exception cref="InvalidOperationException">Occurs if the hook is currently engaged.</exception>
+        public void RemoveKeys() //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------Was only public void before
+        {
+            if (Combination.Keys == KeysEx.None)
+                return;
+
+            if (IsEngaged)
+                throw new InvalidOperationException("Cannot remove keys while hook is engaged.");
+
+            if (Combination != null && currentHookKeys.Contains(Combination))
+                currentHookKeys.Remove(Combination);
+
+            Combination = new KeyCombination(KeysEx.None);
+        }
+
+        /// <summary>
+        /// Associates the specified key combination with this hook. This can only be performed when the hook is not active.
+        /// </summary>
+        /// <param name="combination">The key combination.</param>
+        /// <exception cref="InvalidOperationException">Occurs if this hook is currently engaged -OR- if the key combination is invalid
+        /// -OR- if the key combination is already in use by another hook.</exception>
+        public void SetKeys(KeyCombination combination)
+        {
+            if (Combination == combination)
+                return;
+
+            if (IsEngaged)
+                throw new InvalidOperationException("Cannot set keys while hook is engaged.");
+
+            if (!combination.IsValid)
+                throw new InvalidOperationException("Key combination is not valid.");
+
+            if (currentHookKeys.Contains(combination))
+                throw new InvalidOperationException(string.Format("The combination '{0}' is already in use.", combination));
+
+            if (Combination != null && currentHookKeys.Contains(Combination))
+                currentHookKeys.Remove(Combination);
+
+            currentHookKeys.Add(combination);
+            Combination = combination;
+        }
+
+        /// <summary>
+        /// Activates the KeyboardHook.
+        /// </summary>
+        /// <exception cref="InvalidOperationException">Occurs if the KeyboardHook is empty OR if the KeyboardHook is already engaged.</exception>
+        /// <exception cref="ObjectDisposedException">Occurs if the KeyboardHook has been disposed.</exception>
+        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
+        public void Engage()
+        {
+            if (isDisposed)
+                throw new ObjectDisposedException("KeyboardHook");
+
+            if (Combination == null)
+                throw new InvalidOperationException("Cannot engage hook when Combination is null.");
+
+            if (IsEngaged)
+                return;
+
+            hookId = NativeMethods.SetWindowsHookEx(
+                NativeMethods.KeyStateConstants.WH_KEYBOARD_LL,
+                hookCallback,
+                IntPtr.Zero,
+                0);
+
+            if (hookId == IntPtr.Zero)
+                throw new Win32Exception(Marshal.GetLastWin32Error());
+        }
+
+        /// <summary>
+        /// Removes the KeyboardHook from the system.
+        /// </summary>
+        /// <remarks>Disengage removes the hook from the system, but maintains all its data. Use Engage to re-install the hook. To
+        /// discard the hook and all its data, use Dispose. It is not necessary to call Disengage prior to Dispose.</remarks>
+        public void Disengage()
+        {
+            if (hookId != IntPtr.Zero)
+            {
+                NativeMethods.UnhookWindowsHookEx(hookId);
+                hookId = IntPtr.Zero;
+            }
+        }
+
+        /// <summary>
+        /// Returns the string representation of the KeyboardHook.
+        /// </summary>
+        /// <returns>A string representing the KeyboardHook.</returns>
+        public override string ToString()
+        {
+            return Combination == null ? string.Empty : Combination.ToString();
+        }
+
+        /// <summary>
+        /// Disengages the KeyboardHook and releases all associated resources.
+        /// </summary>
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+        /// <summary>
+        /// Disengages the KeyboardHook, releases all unmanaged resources, and optionally releases
+        /// all managed resources.
+        /// </summary>
+        /// <param name="isDisposing">True to release both managed and unmanaged resources; false to 
+        /// release only unmanaged resources.</param>
+        protected virtual void Dispose(bool isDisposing)
+        {
+            if (isDisposed)
+                return;
+
+            if (isDisposing)
+            {
+                // No managed resources to dispose.
+            }
+
+            Disengage();
+
+            if (Combination != null)
+                currentHookKeys.Remove(Combination);
+
+            isDisposed = true;
+        }
+
+        /// <summary>
+        /// Raises the Pressed event.
+        /// </summary>
+        /// <remarks>The Pressed event is executed asynchronously.</remarks>
+        protected virtual void OnPressed()
+        {
+            // Invoke these asychronously in case they're slow. (Testing revealed that Windows will reassert  
+            // responsibility for the key stroke(s) if the hookcallback doesn't immediately return.)
+            foreach (EventHandler pressedEvent in Pressed.GetInvocationList())
+                pressedEvent.BeginInvoke(this, EventArgs.Empty, ar => ((EventHandler)ar.AsyncState).EndInvoke(ar), pressedEvent);
+        }
+
+        /// <summary>
+        /// Determines whether the specified key, combined with all currently pressed modifier keys, matches this hook's key combination.
+        /// </summary>
+        /// <param name="unmodifiedKey">The unmodified key to combine with all currently pressed keyboard modifier keys.</param>
+        /// <returns>True if unmodifiedKey matches Combination.UnmodifiedKey and all modifier keys contained in the 
+        /// Combination property are currently pressed; otherwise, false.</returns>
+        protected bool CheckIsHookKeyCombination(KeysEx unmodifiedKey)
+        {
+            KeyCombination pressedKeyCombo = new KeyCombination(unmodifiedKey);
+
+            if (IsKeyPressed(KeysEx.ControlKey))
+                pressedKeyCombo.Add(KeysEx.Control);
+
+            if (IsKeyPressed(KeysEx.ShiftKey))
+                pressedKeyCombo.Add(KeysEx.Shift);
+
+            if (IsKeyPressed(KeysEx.LMenu) || IsKeyPressed(KeysEx.RMenu))
+                pressedKeyCombo.Add(KeysEx.Alt);
+
+            if ((IsKeyPressed(KeysEx.LWin) || IsKeyPressed(KeysEx.RWin)))
+                pressedKeyCombo.Add(KeysEx.WinLogo);
+
+            return Combination == pressedKeyCombo;
+        }
+
+        /// <summary>
+        /// The callback proceedure for the installed KeyboardHook. 
+        /// </summary>
+        /// <param name="nCode">A code the KeyboardHook procedure uses to determine how to process the message.</param>
+        /// <param name="wParam">The key state.</param>
+        /// <param name="lParam">The key pressed.</param>
+        /// <returns>A value indicating whether or not to process additional hooks in the current hook chain.</returns>
+        IntPtr HookCallBack(int nCode, IntPtr wParam, IntPtr lParam)
+        {
+            if (isKeyboardLockedDown)
+                return new IntPtr(1); // A non-zero return value blocks additional processing of key strokes.
+
+            // MSDN documentation indicates that nCodes less than 0 should always only invoke CallNextHookEx.
+            if (nCode < 0)
+                return NativeMethods.CallNextHookEx(hookId, nCode, wParam, lParam);
+
+            int keyStateParam = (int)wParam;
+            KeyState keyState;
+
+            if (keyStateParam == keyUp || keyStateParam == systemKeyUp)
+                keyState = KeyState.Up;
+            else if (keyStateParam == keyDown || keyStateParam == systemKeyDown)
+                keyState = KeyState.Down;
+            else
+                throw new ArgumentOutOfRangeException("wParam", "Invalid key state detected.");
+
+            var pressedKey = (KeysEx)Marshal.ReadInt32(lParam);
+
+            if (!CheckIsHookKeyCombination(pressedKey))
+                return NativeMethods.CallNextHookEx(hookId, nCode, wParam, lParam);
+
+            if (keyState == KeyState.Up)
+            {
+                keyReleased = true;
+                return NativeMethods.CallNextHookEx(hookId, nCode, wParam, lParam);
+            }
+
+            // If AutoRepeat is on, always process hook; otherwise, only process hook if they key has been released and re-pressed.
+            if (AutoRepeat || keyReleased)
+            {
+                keyReleased = false;
+                OnPressed();
+            }
+
+            if (AllowPassThrough)
+                return NativeMethods.CallNextHookEx(hookId, nCode, wParam, lParam);
+
+            return new IntPtr(1);
+        }
+    }
+
+    public class KeyboardLockDownKeyPressedEventArgs : EventArgs
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="KeyboardLockDownKeyPressedEventArgs"/> class.
+        /// </summary>
+        /// <param name="keys">The keys that were pressed.</param>
+        /// <param name="state">The state of the pressed keys.</param>
+        /// <remarks></remarks>
+        public KeyboardLockDownKeyPressedEventArgs(KeysEx keys, KeyState state)
+        {
+            Keys = keys;
+            State = state;
+        }
+
+        /// <summary>
+        /// Gets the keys that were pressed.
+        /// </summary>
+        public KeysEx Keys { get; private set; }
+
+        /// <summary>
+        /// Gets the state of the pressed keys.
+        /// </summary>
+        public KeyState State { get; private set; }
+    }
+}
\ No newline at end of file
diff --git a/src/Program.cs b/src/Program.cs
new file mode 100755
index 0000000..03c795f
--- /dev/null
+++ b/src/Program.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace TeamViewerController
+{
+    static class Program
+    {
+        /// <summary>
+        /// The main entry point for the application.
+        /// </summary>
+        [STAThread]
+        static void Main()
+        {
+            Application.EnableVisualStyles();
+            Application.SetCompatibleTextRenderingDefault(false);
+            Application.Run(new Form1());
+        }
+    }
+}
diff --git a/src/Properties/AssemblyInfo.cs b/src/Properties/AssemblyInfo.cs
new file mode 100755
index 0000000..e0136b0
--- /dev/null
+++ b/src/Properties/AssemblyInfo.cs
@@ -0,0 +1,38 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+//[assembly: AssemblyTitle("TeamViewerController")] //OLD ONE
+[assembly: AssemblyTitle("Jarlson Multiplayer")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+//[assembly: AssemblyProduct("TeamViewerController")] // OLD ONE
+[assembly: AssemblyProduct("Jarlson Multiplayer")]
+[assembly: AssemblyCopyright("Copyright ©  2020")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components.  If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("6a0d27e7-625d-452c-9f4f-941cd87b9bb3")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/src/Properties/Resources.Designer.cs b/src/Properties/Resources.Designer.cs
new file mode 100755
index 0000000..67074ec
--- /dev/null
+++ b/src/Properties/Resources.Designer.cs
@@ -0,0 +1,63 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.42000
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace TeamViewerController.Properties {
+    using System;
+    
+    
+    /// <summary>
+    ///   A strongly-typed resource class, for looking up localized strings, etc.
+    /// </summary>
+    // This class was auto-generated by the StronglyTypedResourceBuilder
+    // class via a tool like ResGen or Visual Studio.
+    // To add or remove a member, edit your .ResX file then rerun ResGen
+    // with the /str option, or rebuild your VS project.
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    internal class Resources {
+        
+        private static global::System.Resources.ResourceManager resourceMan;
+        
+        private static global::System.Globalization.CultureInfo resourceCulture;
+        
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal Resources() {
+        }
+        
+        /// <summary>
+        ///   Returns the cached ResourceManager instance used by this class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Resources.ResourceManager ResourceManager {
+            get {
+                if (object.ReferenceEquals(resourceMan, null)) {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("TeamViewerController.Properties.Resources", typeof(Resources).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+        
+        /// <summary>
+        ///   Overrides the current thread's CurrentUICulture property for all
+        ///   resource lookups using this strongly typed resource class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Globalization.CultureInfo Culture {
+            get {
+                return resourceCulture;
+            }
+            set {
+                resourceCulture = value;
+            }
+        }
+    }
+}
diff --git a/src/Properties/Resources.resx b/src/Properties/Resources.resx
new file mode 100755
index 0000000..ffecec8
--- /dev/null
+++ b/src/Properties/Resources.resx
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>
\ No newline at end of file
diff --git a/src/Properties/Settings.Designer.cs b/src/Properties/Settings.Designer.cs
new file mode 100755
index 0000000..f7c06a1
--- /dev/null
+++ b/src/Properties/Settings.Designer.cs
@@ -0,0 +1,26 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.42000
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace TeamViewerController.Properties {
+    
+    
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.3.0.0")]
+    internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+        
+        private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+        
+        public static Settings Default {
+            get {
+                return defaultInstance;
+            }
+        }
+    }
+}
diff --git a/src/Properties/Settings.settings b/src/Properties/Settings.settings
new file mode 100755
index 0000000..abf36c5
--- /dev/null
+++ b/src/Properties/Settings.settings
@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
+  <Profiles>
+    <Profile Name="(Default)" />
+  </Profiles>
+  <Settings />
+</SettingsFile>
diff --git a/src/TeamViewerController.csproj b/src/TeamViewerController.csproj
new file mode 100755
index 0000000..64d93a7
--- /dev/null
+++ b/src/TeamViewerController.csproj
@@ -0,0 +1,125 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{6A0D27E7-625D-452C-9F4F-941CD87B9BB3}</ProjectGuid>
+    <OutputType>WinExe</OutputType>
+    <RootNamespace>TeamViewerController</RootNamespace>
+    <AssemblyName>Jarlson Multiplayer</AssemblyName>
+    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
+    <Deterministic>true</Deterministic>
+    <PublishUrl>publish\</PublishUrl>
+    <Install>true</Install>
+    <InstallFrom>Disk</InstallFrom>
+    <UpdateEnabled>false</UpdateEnabled>
+    <UpdateMode>Foreground</UpdateMode>
+    <UpdateInterval>7</UpdateInterval>
+    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+    <UpdatePeriodically>false</UpdatePeriodically>
+    <UpdateRequired>false</UpdateRequired>
+    <MapFileExtensions>true</MapFileExtensions>
+    <ApplicationRevision>0</ApplicationRevision>
+    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+    <IsWebBootstrapper>false</IsWebBootstrapper>
+    <UseApplicationTrust>false</UseApplicationTrust>
+    <BootstrapperEnabled>true</BootstrapperEnabled>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Open.Nat, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f22a6a4582336c76, processorArchitecture=MSIL">
+      <HintPath>packages\Open.NAT.2.1.0.0\lib\net45\Open.Nat.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Deployment" />
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Net.Http" />
+    <Reference Include="System.Windows.Forms" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Form1.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="Form1.Designer.cs">
+      <DependentUpon>Form1.cs</DependentUpon>
+    </Compile>
+    <Compile Include="Form2.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="Form2.Designer.cs">
+      <DependentUpon>Form2.cs</DependentUpon>
+    </Compile>
+    <Compile Include="KeyboardLock.cs" />
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <EmbeddedResource Include="Form1.resx">
+      <DependentUpon>Form1.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="Form2.resx">
+      <DependentUpon>Form2.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="Properties\Resources.resx">
+      <Generator>ResXFileCodeGenerator</Generator>
+      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
+    <Compile Include="Properties\Resources.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DependentUpon>Resources.resx</DependentUpon>
+      <DesignTime>True</DesignTime>
+    </Compile>
+    <None Include="packages.config" />
+    <None Include="Properties\Settings.settings">
+      <Generator>SettingsSingleFileGenerator</Generator>
+      <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+    </None>
+    <Compile Include="Properties\Settings.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DependentUpon>Settings.settings</DependentUpon>
+      <DesignTimeSharedInput>True</DesignTimeSharedInput>
+    </Compile>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="App.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <BootstrapperPackage Include=".NETFramework,Version=v4.7.2">
+      <Visible>False</Visible>
+      <ProductName>Microsoft .NET Framework 4.7.2 %28x86 and x64%29</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project>
\ No newline at end of file
diff --git a/src/TeamViewerController.sln b/src/TeamViewerController.sln
new file mode 100755
index 0000000..7f5a0ea
--- /dev/null
+++ b/src/TeamViewerController.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29519.87
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TeamViewerController", "TeamViewerController.csproj", "{6A0D27E7-625D-452C-9F4F-941CD87B9BB3}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{6A0D27E7-625D-452C-9F4F-941CD87B9BB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{6A0D27E7-625D-452C-9F4F-941CD87B9BB3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{6A0D27E7-625D-452C-9F4F-941CD87B9BB3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{6A0D27E7-625D-452C-9F4F-941CD87B9BB3}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {62DF8BC2-3224-46C0-BDB2-916511CE469D}
+	EndGlobalSection
+EndGlobal
diff --git a/src/packages.config b/src/packages.config
new file mode 100755
index 0000000..9185792
--- /dev/null
+++ b/src/packages.config
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="Open.NAT" version="2.1.0.0" targetFramework="net472" />
+</packages>
\ No newline at end of file