2018/12/17

[C#] WPF Keyboard Simulator

這篇用WPF 寫一個模擬Windows 鍵盤的APP。
其實關鍵就只是利用C# SendKeys 的功能而已(這篇有寫過)
但如果要寫一個完整模擬鍵盤的APP,會有些比較複雜的功能。
先準備好所有鍵盤的圖檔(圖檔來源),Layout 的部分這邊主要都會用程式碼來寫,要不然在xaml 要做一堆物件實在是有點麻煩。

一開始會打算先用字串陣列的方式,順序就依照鍵盤的設計去準備每個按鍵的圖案跟Keycode。
首先是鍵盤圖檔所有的檔名,包含大小寫轉換的圖案。
路徑的部分依照按下的狀態分為兩個資料夾來放(Keyup and Keydown),Keydown 是按下去時反白的圖案,圖檔格式為.png:
private String FileType = ".png";
private String FilePathKeyUp = "Image/KeyUp/keyup_";
private String FilePathKeyDown = "Image/KeyDown/keydown_";

private String[] CapsLetterFileName = {"q","w","e","r","t","y","u","i","o","p","delete","one","two","three",
                                        "a","s","d","f","g","h","j","k","l","double_quote","enter","four","five","six",
                                        "shift","z","x","c","v","b","n","m","semicolon","colon","exclamation_mark_screamer","shift2","seven","eight","nine",
                                        "ctrl","alt","windows","spacebar","left","right","keyboard","zero","lperiod_full_stop"};

private String[] SmallLetterFileName = {"lq","lw","le","lr","lt","ly","lu","li","lo","lp","delete","one","two","three",
                                        "la","ls","ld","lf","lg","lh","lj","lk","ll","lsingle_quote","enter","four","five","six",
                                        "shift","lz","lx","lc","lv","lb","ln","lm","lcomma","lperiod_full_stop","lquestion_mark","shift2","seven","eight","nine",
                                        "ctrl","alt","windows","spacebar","left","right","keyboard","zero","lperiod_full_stop"};

再來是Keycode的部分,對應到上面的陣列位置,分別準備大、小寫的陣列。
private String[] KeyCodeCapsLetter = {"Q","W","E","R","T","Y","U","I","O","P", "{backspace}","1","2","3",
                                        "A","S","D","F","G","H","J","K","L","\"","{enter}","4","5","6",
                                        "shift","Z","X","C","V","B","N","M",";",":","!","shift","7","8","9",
                                        "^","%","^" + "{esc}"," ","{left}","{right}","keyboard","0","."};

private String[] KeyCodeSmallLetter = {"q","w","e","r","t","y","u","i","o","p", "{backspace}","1","2","3",
                                        "a","s","d","f","g","h","j","k","l","'","{enter}","4","5","6",
                                        "shift","z","x","c","v","b","n","m",",",".","?","shift","7","8","9",
                                        "^","%","^" + "{esc}"," ","{left}","{right}","keyboard","0","."};

這樣之後程式碼寫輸入的部分,就可以用for 迴圈搭配if 判斷陣列位置這樣來寫:
for (int i = 0; i < key_amount; i++)
{
    if (mImage.Name == CapsLetterFileName[i])
    {
        if (isCaps)
        {
            SendKeys.SendWait(KeyCodeCapsLetter[i]);
        }
        else
        {
            SendKeys.SendWait(KeyCodeSmallLetter[i]);
        }
    }
}

寫到這邊先來講一個問題,一般APP 出現在螢幕上的時候,視窗一定要Focus 才能用,但是要模擬鍵盤功能的話,是要針對APP 以外的其他視窗打字。
所以這邊的作法是先把APP 設定為Topmost (在xaml 中的Window 物件 > 屬性 > 一般 > Topmost)。
然後在cs 程式碼中宣告的地方import 需要的dll :
// import dll to control on Topmost
[DllImport("user32", SetLastError = true)]
private extern static int GetWindowLong(IntPtr hwnd, int nIndex);
[DllImport("user32", SetLastError = true)]
private extern static int SetWindowLong(IntPtr hwnd, int nIndex, int dwNewValue);

在程式碼中建立一個函式 initTopmostControl() :
private void initTopmostControl()
{
    WindowInteropHelper wih = new WindowInteropHelper(this);
    int exstyle = GetWindowLong(wih.Handle, -20);
    exstyle |= 0x08000000;
    SetWindowLong(wih.Handle, -20, exstyle);
}

這邊也讓Keyboard APP 模擬真實的鍵盤,可以在右下角看到APP 的圖示,甚至可以點它來開啟/隱藏Keyboard。
可以參考之前寫過的NotifyIcon 寫法(參考這篇):
建立一個函式 initNotifyIcon():
// init NotifyIcon
private void initNotifyIcon()
{
    notifyIcon = new NotifyIcon();
    Stream iconStream = System.Windows.Application.GetResourceStream(new Uri(@"Image/icon2.ico", UriKind.Relative)).Stream;
    notifyIcon.Icon = new System.Drawing.Icon(iconStream);
    System.Windows.Forms.ContextMenu notifyIconMenu = new System.Windows.Forms.ContextMenu();
    System.Windows.Forms.MenuItem notifyIconMenuItem = new System.Windows.Forms.MenuItem();
    notifyIconMenuItem.Index = 0;
    notifyIconMenuItem.Text = "Exit";
    notifyIconMenuItem.Click += new EventHandler(notifyIconMenuItem_Click);
    notifyIconMenu.MenuItems.Add(notifyIconMenuItem);
    notifyIcon.ContextMenu = notifyIconMenu;
    notifyIcon.Visible = true;
    notifyIcon.Click += new EventHandler(TouckKeyboard_state);
}

這邊NotifyIcon 想要加入的功能是,在icon 上點右鍵選擇Exit 來關閉APP。
notifyIconMenuItem.Click += new EventHandler(notifyIconMenuItem_Click);
其中notifyIconMenuItem_Click就是寫直接關閉APP
private void notifyIconMenuItem_Click(object sender, EventArgs e)
{
    this.Close();
}

另外,可以在右下角的icon 上,點左鍵來顯示/隱藏APP,
notifyIcon.Click += new EventHandler(TouckKeyboard_state);
其中TouckKeyboard_state 就是來控制Keyboard APP 視窗顯示的位置,判斷isShow 然後利用Top 值來設定式窗位置,所以程式碼還要加入:
// show or hide keyboard
private void TouckKeyboard_state(object sender, EventArgs e)
{
    isShow = !isShow;
    TouckKeyboard_position();
}

// show or hide keyboard position
private void TouckKeyboard_position()
{
    if (!isShow)
    {
        while (this.Top < workArea.Height + 50)
        {
            this.Top++;
        }
    }
    else
    {
        while (this.Top >= workArea.Height - this.Height + 1)
        {
            this.Top--;
        }
    }
}

workArea 的部分是建立一個Rect 來抓系統中,整個螢幕的範圍,可以透過它來設定視窗位置,或是做APP 等比例的縮放:
private Rect workArea;
workArea = System.Windows.SystemParameters.WorkArea;

以上三個函式initTopmostControl()、initNotifyIcon()、TouckKeyboard_position() 建議寫在Window_Loaded() 裡面比較保險。
在xaml 中的Window 物件 > 屬性 > 事件 > Loaded 點開產生函式:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
    initTopmostControl();

    initNotifyIcon();

    TouckKeyboard_position();
}


目前是寫針對APP 方面前提的一些基本的功能,接下來是比較重要的部分,就是每個按鍵的設定跟功能寫法。

在MainWindow() 先利用前面寫的workArea 來設定APP是窗的位置跟大小:
public MainWindow()
{
    InitializeComponent();
            
    // set keyboard window x,y,w,h by workArea
    workArea = System.Windows.SystemParameters.WorkArea;
    this.Left = 0;
    this.Top = workArea.Height;
    this.Width = workArea.Width;
    this.Height = workArea.Height * 0.435;
}

這邊補上一個Layout 的參數來參考一下(參考圖檔來源的 spec.jpg):

建立一個函式initKeyImage() 來設定所有的按鍵圖案,包括圖檔、大小、位置:
private void initKeyImage()
{
    key_amount = CapsLetterFileName.Length;
    LetterFileName = new String[key_amount];
    imageLetter = new Image[key_amount];
            
    for (int i = 0; i < key_amount; i++)
    {
        // create key image
        imageLetter[i] = new Image();
        imageLetter[i].Name = CapsLetterFileName[i];
        imageLetter[i].Source = new BitmapImage(new Uri(@FilePathKeyUp + CapsLetterFileName[i] + FileType, UriKind.Relative));
        imageLetter[i].Stretch = Stretch.Fill;
        imageLetter[i].MouseDown += new MouseButtonEventHandler(imageLetterMouseDown);
        imageLetter[i].MouseUp += new MouseButtonEventHandler(imageLetterMouseUp);
        imageLetter[i].MouseLeave += new System.Windows.Input.MouseEventHandler(imageLetterMouseLeave);
        CanvasWindow.Children.Add(imageLetter[i]);

        // set left of each key image
        if (imageLetter[i].Name == "q" || imageLetter[i].Name == "shift" || imageLetter[i].Name == "ctrl")
        {
            Canvas.SetLeft(imageLetter[i], workArea.Width * 0.04);
        }
        else if (imageLetter[i].Name == "a")
        {
            Canvas.SetLeft(imageLetter[i], workArea.Width * 0.053);
        }
        else
        {
            Canvas.SetLeft(imageLetter[i], Canvas.GetLeft(imageLetter[i - 1]) + imageLetter[i - 1].Width + 10);
        }

        // set top of each key image
        if (i >= 0 && i <= 13)
        {
            Canvas.SetTop(imageLetter[i], workArea.Width * 0.01);
        }
        else if (i >= 14 && i <= 27)
        {
            Canvas.SetTop(imageLetter[i], (workArea.Width * 0.01 + (workArea.Height * 0.091 + workArea.Width * 0.004) * 1));
        }
        else if (i >= 28 && i <= 42)
        {
            Canvas.SetTop(imageLetter[i], (workArea.Width * 0.01 + (workArea.Height * 0.091 + workArea.Width * 0.004) * 2));
        }
        else
        {
            Canvas.SetTop(imageLetter[i], (workArea.Width * 0.01 + (workArea.Height * 0.091 + workArea.Width * 0.004) * 3));
        }

        // set width of each key iamge
        if (imageLetter[i].Name == "delete" || imageLetter[i].Name == "zero")
        {
            imageLetter[i].Width = workArea.Width * 0.111;
        }
        else if (imageLetter[i].Name == "enter")
        {
            imageLetter[i].Width = workArea.Width * 0.098;
        }
        else if (imageLetter[i].Name == "spacebar")
        {
            imageLetter[i].Width = workArea.Width * 0.345;
        }
        else
        {
            imageLetter[i].Width = workArea.Width * 0.053;
        }

        // set height of each key iamge
        imageLetter[i].Height = workArea.Height * 0.091;
    }
}

建立滑鼠按下事件函式,圖案會呈現反白的樣子:
private void imageLetterMouseDown(object sender, RoutedEventArgs e)
{
    isDown = true;
    Image mImage = (Image) sender;

    // set key pressed
    for (int i = 0; i < key_amount; i++)
    {
        if (mImage.Name == CapsLetterFileName[i])
        {
            key_pressed = i;
        }
    }

    // set the keydown status and image
    setKeyStatus("down");
            
    // set long press
    if (mImage.Name != "shift" && mImage.Name != "shift2")
    {
        SetLongPressTimer(true);
    }
}

建立滑鼠移開事件函式,做類似 mouse up的功能,但不要做任何事情:
private void imageLetterMouseLeave(object sender, RoutedEventArgs e)
{
    Image mImage = (Image)sender;

    // set the keyup status and image
    setKeyStatus("up");
    SetLongPressTimer(false);
}

建立滑鼠放開事件函式,在這裡就要寫判斷按了哪一個按鍵,做出對應的Keycode 功能:
private void imageLetterMouseUp(object sender, RoutedEventArgs e)
{
Image mImage = (Image)sender;

    // set the keyup status and image
    setKeyStatus("up");

    // send key function
    if (isDown)
    {
        // shift function
        if (mImage.Name == "shift" || mImage.Name == "shift2")
        {
            isCaps = !isCaps;
            setLetterCaps(isCaps);
        }

        // keyboard show function
        else if (mImage.Name == "keyboard")
        {
            isShow = !isShow;
            TouckKeyboard_position();
        }
                
        // letter function
        else
        {
            for (int i = 0; i < key_amount; i++)
            {
                if (mImage.Name == CapsLetterFileName[i])
                {
                    if (isCaps)
                    {
                        SendKeys.SendWait(KeyCodeCapsLetter[i]);
                    }
                    else
                    {
                        SendKeys.SendWait(KeyCodeSmallLetter[i]);
                    }
                }
            }
        }
        SetLongPressTimer(false);
    }
}

在以上滑鼠事件中,down 跟up 事件裡有狀態切換的函式setKeyStatus(),跟計時器的函式SetLongPressTimer()。
在setKeyStatus() 裡面做的就是鍵盤沒按/按下的狀態切換,按下會反白,寫一個setKeyImage()函式來切換不同狀態的圖案。
// set key status
private void setKeyStatus(String status)
{
    if(status == "down")
    {
        setKeyImage(imageLetter[key_pressed], FilePathKeyDown + LetterFileName[key_pressed] + FileType);
    }
    else if (status == "up")
    {
        setKeyImage(imageLetter[key_pressed], FilePathKeyUp + LetterFileName[key_pressed] + FileType);
    }
}

// set key image source
private void setKeyImage(Image image, String filepath)
{
    image.Source = new BitmapImage(new Uri(@filepath, UriKind.Relative));
}

另外就是函式SetLongPressTimer() 來控制長按用的計時器LongPressTimer 開啟/結束:
private void SetLongPressTimer(bool isStart)
{
    if (isStart)
    {
        LongPressTimer.Start();
    }
    else
    {
        LongPressTimer.Stop();
        pressed_count = 0;
        isDown = false;
    }
}

當按下shift 時會切換大小寫模式,所以要建立一個函式setLetterCaps() 來切換大小寫模式:
private void setLetterCaps(bool isCaps)
{
    for (int i = 0; i < key_amount; i++)
    {
        if (isCaps)
        {
            LetterFileName[i] = CapsLetterFileName[i];
        }
        else
        {
            LetterFileName[i] = SmallLetterFileName[i];
        }
        setKeyImage(imageLetter[i], FilePathKeyUp + LetterFileName[i] + FileType);
    }
}

MainWindow() 加入initKeyImage() 跟 setLetterCaps(true),另外也加入長按功能:
private bool isCaps = true;
private DispatcherTimer LongPressTimer;

public MainWindow()
{
    InitializeComponent();
            
    // set keyboard window x,y,w,h by workArea
    workArea = System.Windows.SystemParameters.WorkArea;
    this.Left = 0;
    this.Top = workArea.Height;
    this.Width = workArea.Width;
    this.Height = workArea.Height * 0.435;

    // set long press timer
    LongPressTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(0.01) };
    LongPressTimer.Tick += LongPressTimerTick;

    initKeyImage();
    setLetterCaps(isCaps);
}

在程式碼中加入計時器函式 LongPressTimerTick(),當長按時會一直輸入:
private void LongPressTimerTick(object sender, EventArgs e)
{
    pressed_count ++;
    if (pressed_count > 15)
    {
        if (isCaps)
        {
            SendKeys.SendWait(KeyCodeCapsLetter[key_pressed]);
        }
        else
        {
            SendKeys.SendWait(KeyCodeSmallLetter[key_pressed]);
        }
    }
}

APP 執行的時候,可以從工具列的右下角看程式有沒有打開。
最後附上全部完整的程式碼:
MainWindow.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Forms;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Runtime.InteropServices;
using System.IO;
using System.Windows.Threading;
using System.Windows.Input;

namespace TouchKeyboard
{
    public partial class MainWindow : Window
    {
        private bool isShow = true, isCaps = true, isDown = false;

        private int key_amount, key_pressed, pressed_count = 0;
        
        private String FileType = ".png";
        private String FilePathKeyUp = "Image/KeyUp/keyup_";
        private String FilePathKeyDown = "Image/KeyDown/keydown_";

        private String[] CapsLetterFileName = {"q","w","e","r","t","y","u","i","o","p","delete","one","two","three",
                                                "a","s","d","f","g","h","j","k","l","double_quote","enter","four","five","six",
                                                "shift","z","x","c","v","b","n","m","semicolon","colon","exclamation_mark_screamer","shift2","seven","eight","nine",
                                                "ctrl","alt","windows","spacebar","left","right","keyboard","zero","lperiod_full_stop"};

        private String[] SmallLetterFileName = {"lq","lw","le","lr","lt","ly","lu","li","lo","lp","delete","one","two","three",
                                                "la","ls","ld","lf","lg","lh","lj","lk","ll","lsingle_quote","enter","four","five","six",
                                                "shift","lz","lx","lc","lv","lb","ln","lm","lcomma","lperiod_full_stop","lquestion_mark","shift2","seven","eight","nine",
                                                "ctrl","alt","windows","spacebar","left","right","keyboard","zero","lperiod_full_stop"};

        private String[] KeyCodeCapsLetter = {"Q","W","E","R","T","Y","U","I","O","P", "{backspace}","1","2","3",
                                                "A","S","D","F","G","H","J","K","L","\"","{enter}","4","5","6",
                                                "shift","Z","X","C","V","B","N","M",";",":","!","shift","7","8","9",
                                                "^","%","^" + "{esc}"," ","{left}","{right}","keyboard","0","."};

        private String[] KeyCodeSmallLetter = {"q","w","e","r","t","y","u","i","o","p", "{backspace}","1","2","3",
                                                "a","s","d","f","g","h","j","k","l","'","{enter}","4","5","6",
                                                "shift","z","x","c","v","b","n","m",",",".","?","shift","7","8","9",
                                                "^","%","^" + "{esc}"," ","{left}","{right}","keyboard","0","."};

        private String[] LetterFileName;
        private Image[] imageLetter;

        private Rect workArea;
        private NotifyIcon notifyIcon;
        private DispatcherTimer LongPressTimer;

        // import dll to control on Topmost
        [DllImport("user32", SetLastError = true)]
        private extern static int GetWindowLong(IntPtr hwnd, int nIndex);
        [DllImport("user32", SetLastError = true)]
        private extern static int SetWindowLong(IntPtr hwnd, int nIndex, int dwNewValue);
        
        public MainWindow()
        {
            InitializeComponent();
            
            // set keyboard window x,y,w,h by workArea
            workArea = System.Windows.SystemParameters.WorkArea;
            this.Left = 0;
            this.Top = workArea.Height;
            this.Width = workArea.Width;
            this.Height = workArea.Height * 0.435;

            // set long press timer
            LongPressTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(0.01) };
            LongPressTimer.Tick += LongPressTimerTick;

            initKeyImage();
            setLetterCaps(isCaps);
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            initTopmostControl();

            initNotifyIcon();

            TouckKeyboard_position();
        }

        // control on Topmost
        private void initTopmostControl()
        {
            WindowInteropHelper wih = new WindowInteropHelper(this);
            int exstyle = GetWindowLong(wih.Handle, -20);
            exstyle |= 0x08000000;
            SetWindowLong(wih.Handle, -20, exstyle);
        }

        // init NotifyIcon
        private void initNotifyIcon()
        {
            notifyIcon = new NotifyIcon();
            Stream iconStream = System.Windows.Application.GetResourceStream(new Uri(@"Image/icon2.ico", UriKind.Relative)).Stream;
            notifyIcon.Icon = new System.Drawing.Icon(iconStream);
            System.Windows.Forms.ContextMenu notifyIconMenu = new System.Windows.Forms.ContextMenu();
            System.Windows.Forms.MenuItem notifyIconMenuItem = new System.Windows.Forms.MenuItem();
            notifyIconMenuItem.Index = 0;
            notifyIconMenuItem.Text = "Exit";
            notifyIconMenuItem.Click += new EventHandler(notifyIconMenuItem_Click);
            notifyIconMenu.MenuItems.Add(notifyIconMenuItem);
            notifyIcon.ContextMenu = notifyIconMenu;
            notifyIcon.Visible = true;
            notifyIcon.Click += new EventHandler(TouckKeyboard_state);
        }

        // init key image object
        private void initKeyImage()
        {
            key_amount = CapsLetterFileName.Length;
            LetterFileName = new String[key_amount];
            imageLetter = new Image[key_amount];
            
            for (int i = 0; i < key_amount; i++)
            {
                // create key image
                imageLetter[i] = new Image();
                imageLetter[i].Name = CapsLetterFileName[i];
                imageLetter[i].Source = new BitmapImage(new Uri(@FilePathKeyUp + CapsLetterFileName[i] + FileType, UriKind.Relative));
                imageLetter[i].Stretch = Stretch.Fill;
                imageLetter[i].MouseDown += new MouseButtonEventHandler(imageLetterMouseDown);
                imageLetter[i].MouseUp += new MouseButtonEventHandler(imageLetterMouseUp);
                imageLetter[i].MouseLeave += new System.Windows.Input.MouseEventHandler(imageLetterMouseLeave);
                CanvasWindow.Children.Add(imageLetter[i]);

                // set left of each key image
                if (imageLetter[i].Name == "q" || imageLetter[i].Name == "shift" || imageLetter[i].Name == "ctrl")
                {
                    Canvas.SetLeft(imageLetter[i], workArea.Width * 0.04);
                }
                else if (imageLetter[i].Name == "a")
                {
                    Canvas.SetLeft(imageLetter[i], workArea.Width * 0.053);
                }
                else
                {
                    Canvas.SetLeft(imageLetter[i], Canvas.GetLeft(imageLetter[i - 1]) + imageLetter[i - 1].Width + 10);
                }

                // set top of each key image
                if (i >= 0 && i <= 13)
                {
                    Canvas.SetTop(imageLetter[i], workArea.Width * 0.01);
                }
                else if (i >= 14 && i <= 27)
                {
                    Canvas.SetTop(imageLetter[i], (workArea.Width * 0.01 + (workArea.Height * 0.091 + workArea.Width * 0.004) * 1));
                }
                else if (i >= 28 && i <= 42)
                {
                    Canvas.SetTop(imageLetter[i], (workArea.Width * 0.01 + (workArea.Height * 0.091 + workArea.Width * 0.004) * 2));
                }
                else
                {
                    Canvas.SetTop(imageLetter[i], (workArea.Width * 0.01 + (workArea.Height * 0.091 + workArea.Width * 0.004) * 3));
                }

                // set width of each key iamge
                if (imageLetter[i].Name == "delete" || imageLetter[i].Name == "zero")
                {
                    imageLetter[i].Width = workArea.Width * 0.111;
                }
                else if (imageLetter[i].Name == "enter")
                {
                    imageLetter[i].Width = workArea.Width * 0.098;
                }
                else if (imageLetter[i].Name == "spacebar")
                {
                    imageLetter[i].Width = workArea.Width * 0.345;
                }
                else
                {
                    imageLetter[i].Width = workArea.Width * 0.053;
                }

                // set height of each key iamge
                imageLetter[i].Height = workArea.Height * 0.091;
            }
        }

        private void imageLetterMouseDown(object sender, RoutedEventArgs e)
        {
            isDown = true;
            Image mImage = (Image) sender;

            // set key pressed
            for (int i = 0; i < key_amount; i++)
            {
                if (mImage.Name == CapsLetterFileName[i])
                {
                    key_pressed = i;
                }
            }

            // set the keydown status and image
            setKeyStatus("down");
            
            // set long press
            if (mImage.Name != "shift" && mImage.Name != "shift2")
            {
                SetLongPressTimer(true);
            }
        }

        private void imageLetterMouseLeave(object sender, RoutedEventArgs e)
        {
            Image mImage = (Image)sender;

            // set the keyup status and image
            setKeyStatus("up");
            SetLongPressTimer(false);
        }

        private void imageLetterMouseUp(object sender, RoutedEventArgs e)
        {
            Image mImage = (Image)sender;

            // set the keyup status and image
            setKeyStatus("up");

            // send key function
            if (isDown)
            {
                // shift function
                if (mImage.Name == "shift" || mImage.Name == "shift2")
                {
                    isCaps = !isCaps;
                    setLetterCaps(isCaps);
                }

                // keyboard show function
                else if (mImage.Name == "keyboard")
                {
                    isShow = !isShow;
                    TouckKeyboard_position();
                }
                
                // letter function
                else
                {
                    for (int i = 0; i < key_amount; i++)
                    {
                        if (mImage.Name == CapsLetterFileName[i])
                        {
                            if (isCaps)
                            {
                                SendKeys.SendWait(KeyCodeCapsLetter[i]);
                            }
                            else
                            {
                                SendKeys.SendWait(KeyCodeSmallLetter[i]);
                            }
                        }
                    }
                }
                SetLongPressTimer(false);
            }
        }

        // set all letter caps or little
        private void setLetterCaps(bool isCaps)
        {
            for (int i = 0; i < key_amount; i++)
            {
                if (isCaps)
                {
                    LetterFileName[i] = CapsLetterFileName[i];
                }
                else
                {
                    LetterFileName[i] = SmallLetterFileName[i];
                }
                setKeyImage(imageLetter[i], FilePathKeyUp + LetterFileName[i] + FileType);
            }
        }

        // set key status
        private void setKeyStatus(String status)
        {
            if(status == "down")
            {
                setKeyImage(imageLetter[key_pressed], FilePathKeyDown + LetterFileName[key_pressed] + FileType);
            }
            else if (status == "up")
            {
                setKeyImage(imageLetter[key_pressed], FilePathKeyUp + LetterFileName[key_pressed] + FileType);
            }
        }

        // set key image source
        private void setKeyImage(Image image, String filepath)
        {
            image.Source = new BitmapImage(new Uri(@filepath, UriKind.Relative));
        }

        // show or hide keyboard
        private void TouckKeyboard_state(object sender, EventArgs e)
        {
            isShow = !isShow;
            TouckKeyboard_position();
        }

        // show or hide keyboard position
        private void TouckKeyboard_position()
        {
            if (!isShow)
            {
                while (this.Top < workArea.Height + 50)
                {
                    this.Top++;
                }
            }
            else
            {
                while (this.Top >= workArea.Height - this.Height + 1)
                {
                    this.Top--;
                }
            }
        }
        
        private void SetLongPressTimer(bool isStart)
        {
            if (isStart)
            {
                LongPressTimer.Start();
            }
            else
            {
                LongPressTimer.Stop();
                pressed_count = 0;
                isDown = false;
            }
        }

        private void LongPressTimerTick(object sender, EventArgs e)
        {
            pressed_count ++;
            if (pressed_count > 15)
            {
                if (isCaps)
                {
                    SendKeys.SendWait(KeyCodeCapsLetter[key_pressed]);
                }
                else
                {
                    SendKeys.SendWait(KeyCodeSmallLetter[key_pressed]);
                }
            }
        }
        
        private void notifyIconMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void Window_Closed(object sender, EventArgs e)
        {
            notifyIcon.Dispose();
        }
    } 
}

xaml:
<Window x:Class="TouchKeyboard.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:TouchKeyboard"
        mc:Ignorable="d"
        Title="MainWindow" Topmost="True" Loaded="Window_Loaded" Left="0" Top="0" Height="296" Width="1280" WindowStyle="None" Visibility="Visible" AllowsTransparency="True" Closed="Window_Closed" ResizeMode="NoResize" Focusable="False" ShowInTaskbar="False" Background="Black">
    <Grid>
        <Canvas x:Name="CanvasWindow">
            
        </Canvas>
    </Grid>
</Window>


END

沒有留言:

張貼留言