البرنامج المكتوب بجافا وكما نعلم يعمل على أي جهاز أو نظام تشغيل يحتوي على مكتبات التشغيل الأساسيه ومفسر الجافا (JRE - Java Run Time Environment ) . وهذه بالطبع من أفضل ميزات لغه الجافا .. ونظرا لأن البرنامج سوف يعمل على بيئه خاصه فيه MV فالتحكم في نظام التشغيل بلغه جافا أمر غير سهل ويحتاج الى أستخدام طرق أخرى مثل JNI .
منذ صدور جافا 1.3 وفرت sun كلاس يسمى Robot الهدف منه كما قالت sun :
إقتباس
The primary purpose of Robot is to facilitate automated testing of Java platform implementations.
عن طريق هذا الكلاس سوف تستطيع اصدار أحداث مباشره لنظام التشغيل ، طبعا سوف يريح المبرمج من أستخدام كتابه البرنامج بلغه سي ثم يستدعي الكود من خلال جافا .. فقط كل ما علينا استدعاء الداله الفلانيه وهي من الداخل it's Implementation سوف تقوم بالعمليه المطلوبه .
أهم الدوال interface التي يزودنا بها الكلاس Robot :
كود
BufferedImage createScreenCapture(Rectangle screenRect)
void delay(int ms)
Color getPixelColor(int x, int y)
void keyPress(int keycode
void keyRelease(int keycode)
void mouseMove(int x, int y)
void mousePress(int buttons)
void mouseRelease(int buttons)
void delay(int ms)
Color getPixelColor(int x, int y)
void keyPress(int keycode
void keyRelease(int keycode)
void mouseMove(int x, int y)
void mousePress(int buttons)
void mouseRelease(int buttons)
تبقى بضعه (3) دوال أخرى لا أري لها أهميه كبيره في تطبيقنا ، حيث كلها تنحصر التعامل مع صف انتظار الأحداث ... راجع الـ documentation للمزيد.
الدوال السابقه ، كما هو واضح من اسمها تقوم بعملها مباشره فور الأستدعاء ، فمثلا اذا استدعينا الداله mouseMove بالموقع 10 و 10 ، سوف يتحرك الماوس مباشره لهذا الموقع .. مثلا اذا استدعيت الداله keyPress ومررت لها حرف a (الأسكي 97) فسوف يتم اصدار هذا الحدث ويكتب a في حال كانت النافذه الحاليه فيها خانه للكتابه ..
كود
Robot robot = new Robot();
robot.mouseMove(20,20);
robot.mouseMove(20,20);
هنا سيذهب الماوس للموقع 20 و 20 ...
كود
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
هنا سيتم الضغط على زر الفأره الأيسر (ضغطه واحد) ...
InputEvent.BUTTON1_MASK هي للزر الأيسر
InputEvent.BUTTON2_MASK هي للزر المتوسط (اذا كان الماوس يحتوي على ذلك)
InputEvent.BUTTON3_MASK هي للزر الأيمن
مثال بسيط ، سوف نقوم بتحريك الماوس الى الموقع 20 20 ثم نضغط دبل كليك (بالطبع نحن لا نعرف ما هي محتويات الموقع 20 و 20 في الشاشه الحاليه لديك ... لذلك فور أن تقوم بتنفيذ البرنامج قم بتصغير جميع النوافذ التي تعمل (اي أظهر سطح المكتب) وسيتحرك الماوس بعدها في الموقع 20 و20 وسيتم الضغط مرتين على الشيء الموجود في الموقع (وفي حالتنا هو My Document) .
لاحظ أن هناك فتره تأخير قليله delay في البدايه حتى يمكنك من تصغير جميع التوافذ ، هذه الداله تأخذ وقت بالملي ثانيه ، وتأخر الـ robot قليلا بعدها تكمل العمل ..
كود
import java.awt.Robot;
import java.awt.AWTException;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
public class Demo
{
public static void main (String args[])
{
try
{
Robot robot = new Robot();
robot.delay(1000);
robot.mouseMove(20,20);
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
}
catch (AWTException e)
{
e.printStackTrace();
}
}
}
import java.awt.AWTException;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
public class Demo
{
public static void main (String args[])
{
try
{
Robot robot = new Robot();
robot.delay(1000);
robot.mouseMove(20,20);
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
}
catch (AWTException e)
{
e.printStackTrace();
}
}
}
الأن استطعنا فتح MyDocument بدون مجهود ، فقط تشغيل البرنامج ، ونفس الأمر نستطيع ضغط الزر الأيمن ونستطيع أختيار أي خيار منها أيضا .. نستطيع كتابه أي شيء من الكيبورد عن طريق الدوال KeyPress . نستطيع أخذ لقطه من الصوره الحاليه SnapShot باستخدام الداله createScreenCapture ..
هذه هي أمكانيات الكلاس Robot .. يمكنك كتابه برنامج لعمل Sheduling لشيء ما ، بحيث يعمل ويكتب الأشياء التي تريد عملها بشكل متكرر كل فتره ، مثلا عمل برنامج لاغلاق الجهاز ShutDown الساعه الفلانيه ...فكره البرنامج بانك ستقوم بجعله يقارن هل الساعه الأن هي الساعه المطلوبه لأغلاق الجهاز ، في حال كان كذلك يمكنك أن تولد حدث ضغط على ALT+F4 ثم أضغط مرتين على المفتاح الأيمن ثم ENTER .. أو حرك الفأره الى الموقع الذي توجد به Start وبعدها أكمل العمل
من خلال هذه الأدوات يمكننا عمل برنامج يتحكم بالجهاز الأخر ، عمليه التحكم أقصد بها تحريك الماوس وكتابه كلمات والتقاط صوره (وليس منع المستخدم من استخدام جهازه) .
الفكره بشكل مبسط :
برنامج Server ينتظر أن يتصل به Client ، يحتوي على Robot ، فيه Thread لاستقبال الأمر من الـ Client ، مثلا قال الكلاينت أريد تحريك الماوس الى الموقع الفلاني ، سوف نقوم في الserver باستدعاء الداله mouseMove وبالتالي يتحرك الماوس ...
ونفس الأمر للكتابه .. السؤال الأن كيف يمكن أن أشاهد شاشه السيرفر وأشاهد كل التحركات فيها ؟ بالطبع عن طريق الـcreateScreenCapture التي ترجع لي لقطه من الشاشه وبالتي سأشاهد كل التحركات ..
وسوف نقوم في كل ثانيه (Thread يعمل في الكلاينت) بارسال رساله للسيرفر بأننا نريد لقطه ، ويقوم السيرفر باستدعاء الداله createScreenCapture وارجاع الصوره للكلاينت وثم نقوم باظهار الصوره ، وبالتي سوف نعطى الأنطباع بأن العرض مباشر Live ..
هناك مشكله بسيطه ، وهي أن الداله createScreenCapture ترجع الصوره الحاليه، ولكن بدون موقع الماوس الحالى ، وبالتالي عندما يعمل الكلاينت ويشاهد الصوره فلن يعرف موقع الماوس الحالي .. بالطبع لن توجد فائده من البرنامج اذا لم يظهر الماوس .. حيث أننا لن نعرف أين نحن حتى نصدر الحدث الفلاني ..
الحل هو بالطبع يجب أن نرسم ماوس أو علامه ما في الموقع الحالي للماوس قبل أن نرسل الصوره للكلاينت ، حتى يعرف الموقع .. في المثال رسمت علامه + باللون الأحمر .
كيف يمكن معرفه الموقع الحالي للماوس ؟ للأسف لا توجد داله لهذا الأمر ، لكن بالتأكيد يوجد أكثر من حل ، أسهل حل هو في أني أول لما أبدأ التحكم سأحرك الماوس الى منتصف الشاشه وهكذا أكون لدي البعد ، وبعدها أي عمليه تحريك سأزيد على ذلك البعد .. فقط
صوره من البرنامج :
ملف الـ Server :
ملف الكلاينت Client :
(جربت البرنامج في الجهاز المحلى ، وفعلا التجربه في نفس الجهاز ترهق كثيرا ، حيث كما ذكرت أن أي داله أقوم باستدعائها ستنفذ على المكان الحالى للماوس لذلك المفترض أن الماوس في Server لا يتحرك لأنه الكلاينت يتحكم به ، وبما أني أجرب البرنامجين في جهاز واحد سأضطر الى تحريك الماوس كثيرا حتى لا يأخذ ScreenShot لشاشه الكلاينت وبالتالى تخرب الرؤيه ، لهذا وضعت سطر تأخير Delay في السيرفر عند تنفيذ أي أمر ، حتى اكون نزلت شاشه العميل) .
من الصوره في العميل ، لدينا الأزرار الأربعه للتحكم بموقع الفاره ، عند الضغط على أي منها سوف نرسل رساله للسيرفر بأننا نريد الحركه باتجاه الفلاني ، مثلا ضغت على الزر الأيمن سوف يزيد موقع الفاره الحالي بمقدار خمسه لليمين :
كود
else if ( in.startsWith("RIGHT"))
{
px += 5;
robot.mouseMove(px,py);
}
{
px += 5;
robot.mouseMove(px,py);
}
in هي الرساله التي جائت من الكلاينت ، بالطبع سوف أختبرها هل هي للألتقاط الصوره أو هل هي خاصه بالضغط على Left Click أو mouse move . المهم هنا كانت لحركه الماوس لليمين ، سوف نزيد المتغير px بمقدار 5 بكسل (يمكنك زيادتها كما تشاء) ، وpy بالطبع سوف تكون كما هي حتى تكون الحركه في خط مستقيم ، الا لو أدرت الحركه في اتجاه نحو الزاويه (لكني تجاهلتها في البرنامج للتبسيط) ..
في حال كتبتنا كلام في الـ Text Field سوف يقوم السيرفر باستدعاء دالهkeyPress و keyRelease لكل حرف من الكلام المكتوب ، سنقوم أولا بمعرفه هل الحرف حرف صغير Small Letter :
كود
if(chars[charIndex] >= 'a' && chars[charIndex] <= 'z')
{
robot.keyPress((int) chars[charIndex] - ('a' -'A'));
robot.keyRelease((int)chars[charIndex]- ('a' -'A'));
}
{
robot.keyPress((int) chars[charIndex] - ('a' -'A'));
robot.keyRelease((int)chars[charIndex]- ('a' -'A'));
}
واذا كان الحرف كبير Capital ، سوف نضغط Shift مع كل حرف :
كود
else if(chars[charIndex] >= 'A' &&chars[charIndex] <= 'Z')
{
robot.keyPress(KeyEvent.VK_SHIFT);
robot.keyPress((int)chars[charIndex]);
robot.keyRelease((int) chars[charIndex]);
robot.keyRelease(KeyEvent.VK_SHIFT);
}
{
robot.keyPress(KeyEvent.VK_SHIFT);
robot.keyPress((int)chars[charIndex]);
robot.keyRelease((int) chars[charIndex]);
robot.keyRelease(KeyEvent.VK_SHIFT);
}
غير ذلك سوف نقوم بالضغط على المفتاح صاحب الرقم المطابق بعد تحويل الحرف الى رقم :
كود
robot.keyPress((int) chars[charIndex]);
robot.keyRelease((int)chars[charIn);
robot.keyRelease((int)chars[charIn);
في حال ضغنا على الزر Delete في شاشه العميل :
كود
robot.delay(2 * 1000);
robot.mouseMove(px,py);
robot.keyPress(KeyEvent.VK_DELETE);
robot.keyRelease(KeyEvent.VK_DELETE);
robot.mouseMove(px,py);
robot.keyPress(KeyEvent.VK_DELETE);
robot.keyRelease(KeyEvent.VK_DELETE);
في البدايه ننتظر قليلا ، كما ذكرت لأني أجرب البرنامج في الجهاز المحلي ، ولا يوجد داعي للتأخير في حال كان البرنامج في جهاز أخر ..ومن نضغط على المفتاح Del .. وسوف يحذف الملف .
(اذا كنت تفكر بأن تضغط معها مفتاح Shift ، ومن ثم Enter وهكذا تمسح الملف نهائي ، فهذا صحيح ، اذا كنت تفكر بتحريك الماوس الى محث الدوز وكتابه format فهذا أيضا صحيح
وهكذا لبقيه الدوال ، مجرد أستدعاء في حال طلب الكلاينت الشيء الفلاني .. تذكر بأن الكلاينت كل ثانيه سيطلب الصوره الحاليه للشاشه .. تقريبا الشفره واضحه لكل من كتب برنامج Client-Server يدعم الـ Threads .
أخيرا ، لم أجرب البرنامج في جهازين لذلك لا أعرف بالضبط مدى صحه البرنامج السابق ، أتمنى أن يقوم أحد هنا بتجربته لكي نتأكد من الطريقه .. ربما تكون مجرد أوهام في رأسي قمت بصياغتها بطريقه خاطئه
أيضا في حال كانت هناك طريق أخرى لـ Remote Desktop Access غير هذه فالرجاء تزويدنها بها ..
في حال عمل البرنامج يمكن أن نضيف خصائص أخرى ، مثلا ساعه توقيت حتى نعرف كم بقينا ، أو أن يقوم السيرفر بتحديد زمن معين للكلاينت لكي يتحكم به وبعدها يقطع الأتصال .. أيضا ممكن أن يكون في السيرفر أسماء مستخدمين ومعها صلاحيات معينه مثلا لا يوجد صلاحيات للRight Click وبعدها عندما يتصل الكلاينت نقوم باعطائه الصلاحيات المناسبه .. ورسم ماوس ، ووالكثير من الاضافات في حال كان البرنامج "واقعي" .. غير ذلك في حال لم يعمل نهائي أرجوا المعذره على أضاعه وقتك
إقتباس
"facilitate automated testing of Java platform implementations"
أي سؤال حول الموضوع ..
في المرفق تجد البرنامج (ملف السيرفر والكلاينت) ، مكتوب بـ Netbeans 5 .