יום שבת, 24 במאי 2014

Remote Control Application - Keyboard



במאמר הראשון ראינו כיצד ניתן לדמות תנועה של עכבר בעזרת תוכנה בלבד, השלב הבא הוא להשתלט על המקלדת וכך להשלים את מנגנוני השליטה של הלקוח על השרת, נבנה מחלקה יעודית שדרכה נזריק את המידע כאירועים של לחיצה במקלדת,נתחבר לפונקציה חיצונית נוספת בקובץ  user32.dll ונעביר בה את המצבים של המקשים.


keyboardControl.cs

  public class keyboardControl
    {
        //key event signature
        [DllImport("user32.dll")]
        public static extern void keybd_event(byte bVk, byte bScan,
            uint dwFlags, uint dwExtraInfo);

        //keys:up, down, left, right
        //for more keys visit
        //http://msdn.microsoft.com/en-us/library/dd375731%28v=vs.85%29.aspx
        //const int VK_UP = 0x26; 
        //const int VK_DOWN = 0x28;
        //const int VK_LEFT = 0x25;
        //const int VK_RIGHT = 0x27;
        //...

        //set key status
        const uint KEYEVENTF_KEYUP = 0x0002;
        const uint KEYEVENTF_EXTENDEDKEY = 0x0001;
      

        /// <summary>
        /// set the key as press
        /// </summary>
        /// <param name="key">the number as ascii</param>
        public void press(int key)
        {
            //make key press
            keybd_event((byte)key, 0, 
                KEYEVENTF_EXTENDEDKEY | 0, 0);

        }

        /// <summary>
        /// release the press key
        /// </summary>
        /// <param name="key">the number as ascii</param>
        public  void release(int key)
        {
            //make the key release
            keybd_event((byte)key, 0, 
                KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
        }
    }

תלחצו על Send וישר תעברו ל Notepad


תוכנית הבדיקה עבור המנגנון מכילה תיבת טקסט וכפתור כאשר נלחץ עליו היו לנו 5 שניות למצוא את הטופס שאליו אנחנו רוצים להזריק את המחרוזת, בדומה לבקשה שמגיעה מהלקוח לשרת, חשוב מאוד להשים לב שאנחנו מחקים את המקלדת לחלוטין כלומר במקרה שנרצה לרשום את האות a נצטרך להעביר את הערך 0x41 שהוא הערך לאות A בטבלת  Ascii במקרה שנרצה להעביר את האות  A  נצטרך ללחוץ על Shift לרשום את הערך 0x41 ואח"כ לשחרר את ה Shift כפי שניתן לראות בדוגמה:

KeyboardForm.cs

 public partial class keyboardForm : Form
    {
        public keyboardForm()
        {
            InitializeComponent();
        }

        keyboardControl d;
        private void keyboardForm_Load(object sender, EventArgs e)
        {
            d = new keyboardControl();
        }

        /// <summary>
        /// start inject the message to keyboard
        /// </summary>
        private void btn_send_Click(object sender, EventArgs e)
        {

            if (txb_message.Text != "")
            {
                //wait 5 second this is enougth time to find application and inject it
                Thread.Sleep(5000);
                send();

                txb_message.Text = "";
            }
        }

        /// <summary>
        /// send the message as key press
        /// </summary>
        private void send()
        {
            string message = txb_message.Text;

            for (int i = 0; i < message.Length; i++)
            {
                //set shift key on
                if (char.IsUpper(message[i]))
                    d.press(0x10);

                //set the keys
                d.press(char.ToUpper(message[i]));
                d.release(char.ToUpper(message[i]));

                //release shift key
                if (char.IsUpper(message[i]))
                    d.release(0x10);

            }
        }
    }


סיכום

עד עכשיו טיפלנו בשליטה של הלקוח על החומרה, השלב הבא הוא לבצע לכידה של המסך בשרת ולהעביר למשתמש מרוחק.

קצת שליטה לא תזיק...

Remote Control Application - Mouse




תוכנות לשליטה מרחוק הן כלי חיוני בניהול מחשבים, זה כלי תמיכה מעולה ולגיטמי ברוב המקרים אבל יש מקרים שזה עלול להיות כלי מסוכן שיכול לעלות לנו ביוקר, בסדרת המאמרים הקרובה אתמקד כיצד לבנות תוכנית שתאפשר לנו לשלוט במחשבים מבוססי Windows מרחוק, התוכנית מחולקת ל 2 חלקים כיאה לעבודה עם Sockets אבל לפני שנתחיל לכתוב את צד השרת והלקוח קודם נגדיר על איזה מנגנונים נאפשר שליטה.

המנגנון הראשון הוא העכבר, אנחנו רוצים להזיז וללחוץ עליו מרחוק, נגדיר מחלקה שדרכה ניגשים למשאבים של העכבר, בעזרת קריאה לפונקציה mouse_event נוכל לדמות אירועים של כפתורים, נוסיף פונקציות נוספות שדרכן נזיז את העכבר לנקודה במסך ונקבל את מיקום הסמן.

 mouseControl.cs

    public class mouseControl
    {
        /// <summary>
        /// mouse virtual buttons
        /// </summary>
        public enum mouseButtons
        {
            LEFT,
            RIGHT
        }

        //mouse event signature
        [DllImport("user32.dll", CharSet = CharSet.Auto, 
            CallingConvention = CallingConvention.StdCall)]

        public static extern void mouse_event(long dwFlags, long dx,
            long dy, long cButtons, long dwExtraInfo);

        //mouse event types, for more events visit this link
        //http://msdn.microsoft.com/en-us/library/windows/desktop/ms646260(v=vs.85).aspx
        private const int MOUSEEVENTF_LEFTDOWN = 0x02;
        private const int MOUSEEVENTF_LEFTUP = 0x04;
        private const int MOUSEEVENTF_RIGHTDOWN = 0x08;
        private const int MOUSEEVENTF_RIGHTUP = 0x10;

        /// <summary>
        /// raise mouse click event
        /// </summary>
        /// <param name="btn">left / right buttons</param>
        public void mouseClick(mouseButtons btn)
        {
            switch (btn)
            {
                case mouseButtons.LEFT:
                    mouse_event(MOUSEEVENTF_LEFTDOWN | 
                        MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
                    break;
                case mouseButtons.RIGHT:
                    mouse_event(MOUSEEVENTF_RIGHTDOWN |
                        MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0);
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// move the mouse to new location
        /// </summary>
        /// <param name="x">x position</param>
        /// <param name="y">y position</param>
        public void mouseMove(int x, int y)
        {
            Cursor.Position = new Point(x, y); 
        }

        /// <summary>
        /// get the cursor location on screen
        /// </summary>
        /// <returns>cursor location</returns>
        public Point screenLocation()
        {
            return Cursor.Position;
        }

    }


על מנת שנוכל לבדוק את המחלקה נבנה תוכנית מאוד פשוטה, מדובר על טופס שמכיל מספר כפתורים ושדות שדרכם נשלוט בעכבר, בנוסף נגדיר שעון שדוגם כל 100ms את המיקום הנוכחי של העכבר ע"ג המסך, המטרה של התוכנית היא קודם כל לבדוק את הקוד מקומית ואח"כ מרחוק כפי שנראה במאמרים הבאים.




   mouseForm.cs

    public partial class mouseForm : Form
    {
        mouseControl c;

        public mouseForm()
        {
            InitializeComponent();
        }

        private void mouseForm_Load(object sender, EventArgs e)
        {
            txb_x.Text = "0";
            txb_y.Text = "0";
            c = new mouseControl();
        }

        /// <summary>
        /// timer for polling the location every 100ms
        /// </summary>
        private void timer1_Tick(object sender, EventArgs e)
        {
            Point p = c.screenLocation();

            lbl_x.Text = "X:" + p.X.ToString();
            lbl_y.Text = "Y:" + p.Y.ToString();
        }

        /// <summary>
        /// getting the location of the cursor
        /// </summary>
        private void setLocation()
        {
            int x = 0, y = 0;

            int.TryParse(txb_x.Text, out x);
            int.TryParse(txb_y.Text, out y);

            c.mouseMove(x, y);
        }

        /// <summary>
        /// move the cursor by x and y
        /// </summary>
        private void btn_move_Click(object sender, EventArgs e)
        {
            //set the cursor location
            setLocation();
        }

        /// <summary>
        /// move the cursor and make double click on the left button
        /// </summary>
        private void btn_left_Click(object sender, EventArgs e)
        {
            //set the cursor location
            setLocation();

            //single click
            c.mouseClick(mouseControl.mouseButtons.LEFT);
            //add other request for double click
            c.mouseClick(mouseControl.mouseButtons.LEFT);
        }

        /// <summary>
        /// move the cursor and make double click on right button
        /// </summary>
        private void btn_right_Click(object sender, EventArgs e)
        {
            //set the cursor location
            setLocation();

            //single click
            c.mouseClick(mouseControl.mouseButtons.RIGHT);
            //add other request for double click
            c.mouseClick(mouseControl.mouseButtons.RIGHT);
        }
    }


סיכום

אז אחרי שיש שליטה על העכבר נעבור למנגנונים נוספים כמו המקלדת ולכידת מסך אח"כ נכתוב את צד השרת ואת צד הלקוח ונשלב בהם את המחלקות שבנינו יחד עם אובייקט מרכזי שיעבור בניהם.

תחילת של דלת סתרים....

יום שבת, 10 במאי 2014

WebView Interfaces




כשניגשים לפתח אפליקציה נשאלת השאלה מה הפלטפורמה המתאימה ביותר?, חלק יגידו שכתיבה מסורתית בקוד Native היא הפתרון המתאים ויש כאלה שחולקים על זה ומעדיפים לכתוב ב HTML 5  במעטפת Webkit ותוספות נוספות כמו PhoneGap, האמת שככל שעובר זמן יש יתרון בולט ל Html 5 כי אינו מצריך התייחסות מיוחדת כלפי מערכת ההפעלה והופך את האפליקציה ל Cross Platform אבל ברגע שצריכים לבצע פעולות מיוחדות בחומרה כל העסק מתחיל להתפרק כמו מגדל קלפים ברוח.

אופי האפליקציה חשוב מאוד לבחירת הפלטפורמה למשל אם זו תוכנית לתצוגת נתונים מ Database שמזכירה בהתנהגות שלה אתר אינטרנט מומלץ להשתמש ב Html 5, זו הדרך הפשוטה והמהירה ביותר, אבל אם רוצים להשתמש במצלמה או בכל רכיב חומרתי אחר Native Code חזק יותר אז מה עושים עם אפליקציות שקשה להגדיר? נקודת המוצא היא להשתמש ב Native אבל אם ניתן להגדיר תחומי אחריות ברורים ניתן לשלב גם Html וכך להקטין את התלות במערכות ההפעלה.

סביבות משולבות

ההתממשקות הראשונה היא בסיסית ביותר ונעשת בעזרת האזנה מאחורי הקלעים ל Redirects שקורים ב WebKit ומאפשרת לשנות את ההתנהגות של האפליקציה, הדוגמה מתחילה מ Activity שמכיל בתוכו כפתור, לחיצה עליו מעבירה ל Activity אחר עם Webview שטוען דף Html עם מספר קישורים שמובילים לאיזורים שונים באפליקציה:



BrowserActivity

כשמתמקדים בקוד של ה Activity ניתן לראות כיצד אפשר לדרוס את הפונקציה המקורית של ה WebKit בפונקציה חדשה דרכה ניתן לנתח את הבקשות של המשתמש.

import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class BrowserActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_browser);
WebView _view = (WebView)findViewById(R.id.webView1);
class MainScreenActivity extends WebViewClient {

//every redirect active this function
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
//checking the url and change behavior
if(url.toLowerCase().contains("back:mainactivity"))
{
finish();
return true;
}
else if(url.toLowerCase().contains("goto:otheractivity"))
{
Intent intent = new Intent(BrowserActivity.this,OtherActivity.class);
startActivity(intent);
return true;
}
else
{
//send back to the original call
return super.shouldOverrideUrlLoading(view, url);
}
}
}
//overwrite the WebViewClient class with new implementation 
_view.setWebViewClient(new MainScreenActivity());
//make the first call
_view.loadUrl("file:///android_asset/www/index.html"); 
}

}


JavaScript Interface

ההתממשקות הבאה יותר מורכבת ומאפשרת לקרוא לפונקציות Native בעזרת פונקציות JavaScript , יוצרים מחלקה ייעודית שדרכה נוצר גשר שמחבר בין 2 הפלטפורמות.

import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.webkit.WebView;

public class BrowserActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_browser);
WebView _view = (WebView)findViewById(R.id.webView1);
//add javascript support to webview
_view.getSettings().setJavaScriptEnabled(true);
//interface implementation
        class jsInterface{
        Context mContext;
        String mMsg;
     
          public jsInterface(Context m) {
          mContext = m;
        }
   
         //@JavascriptInterface
         //add in higher sdk version  4.0.1 +
         public void SetInterface(String Msg)
         {
            mMsg = Msg;
         }
   
            //@JavascriptInterface
          //add in higher sdk version  4.0.1 +
          public String GetInterface()
         {
            return mMsg;
          }
   
}
//add interface to webview, with bridge name
_view.addJavascriptInterface(new jsInterface(this), "Android");
//make the first call
_view.loadUrl("file:///android_asset/www/index.html"); 
}

}

קובץ ה JavaScript קורא לפונקציות החשופות בעזרת השם של הממשק:

function setMessage()
{
Android.SetInterface(document.getElementById('txt_msg').value);
}

function getMessage()
{
document.getElementById('lbl_msg').innerHTML = Android.GetInterface();
}



סיכום

אני לא יודע מה יקרה בעתיד אבל הדילמה אם להשתמש ב Native או ב Html 5 עדיין קיימת ומצריכה חשיבה מחוץ לקופסה,המון חברות לקחו את הרעיון של ה HTML5 ויצרו סביבות פיתוח שלמות שמבוססות על הרעיון, אם זו השיטה הטובה ביותר, לא תמיד ולפעמים אין ברירה ולדבר עם המכשיר בשפה שהוא מכיר.

מידע נוסף

בהצלחה...