העברת מידע באמצעות סמן העכבר

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


(וידאו באנגלית)

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

בעבר רכשתי שני לוחות תואמי-DigiSpark, שמבוססים על ATtiny85 ונעזרים בתוכנת V-USB כדי לדמות מקלדת או עכבר. הלוחות פעלו, אך לא הצלחתי למצוא דרך נורמלית לתקשר איתם בחיבור סריאלי מכיוון שהחומרה בהם לא תומכת בתקשורת כזו.

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

מידע בתנועה

שפות תכנות עם ספריות לסביבת עבודה גרפית מסוגלות להבחין בתנועה של סמן העכבר על גבי אלמנטים גרפיים (לחצנים, תמונות וכדומה) ולקרוא, בין השאר, את ערכי ה-X וה-Y המשתנים שלו. אנחנו יכולים לכתוב בקלות תוכנה שתקרא את הערכים האלה ותחלץ מהם ביטים. לדוגמה פשטנית, נגדיר שאם הסמן זז ימינה זה 0 ואם הוא זז שמאלה זה 1. גם בצד הלאונרדו, התוכנה שתקודד ותשדר את הביטים ככה תהיה פשוטה מאד. אבל זה ישגע את המשתמש, כי אם יהיו רצפים לא מאוזנים של 0 ו-1 הסמן ינדוד לכל מיני כיוונים לא רצויים.

אפשר לשפר את המצב אם נגדיר ביטים בעזרת רצפי תנועה קצרים שחוזרים תמיד לנקודת המוצא. לדוגמה, ימינה ואז שמאלה זה 0, מעלה ואז מטה זה 1. הלאונרדו מסוגל לבצע את התנועות האלה בקנה מידה של פיקסל בודד ובמהירות על-אנושית, עד כדי כך שהמשתמש כמעט לא יבחין בהן (פרט למקרים קיצוניים).

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

סכמת התנועות האינפורמטיביות לסמן העכבר
סכמת התנועות האינפורמטיביות לסמן העכבר

פספוסים

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

שנית, בסופו של דבר נרצה לשדר בייטים שלמים, אבל כל דפוס תנועה משדר רק חצי בייט (4 ביטים). עם כל ההפרעות הפוטנציאליות, איך נוכל לדעת איזה חצי הוא הראשון ואיזה השני? כדי לפתור את הבעיה הוספתי דפוס ייחודי לסנכרון, שמשודר לפני תחילת כל בייט.

שידור הביטים הלכה למעשה

את המערכת לדוגמה כאן יצרתי על בסיס ארדואינו לאונרדו, כי הוא נוח יותר מה-DigiSpark. ראשית, קודדתי את 17 הדפוסים (16 ערכים + סינכרון) לטבלה, שכל ערך בה הוא של 12 ביטים נטו (שני בייטים ברוטו). כתבתי פונקציה שקוראת דפוס מהטבלה לפי אינדקס 0-15, מפענחת ומשדרת אותו, ופונקציה נוספת שמשתמשת בקודמת כדי לשדר בייט שלהם – אות סינכרון ואז שני החצאים. על בסיס כל זה כתבתי תוכנית שקוראת ערך ממחלק מתח עם נגד תלוי-אור, ממירה אותו לסולם של 0-255 ומשדרת את התוצאה בתנועות עכבר עשר פעמים בשניה.

בצד המחשב כתבתי תוכנה קטנה ב-Lazarus, שמציגה מלבן גדול ועוקבת אחרי תנועות העכבר (כשהסמן נמצא מעל המלבן). התוכנה מנסה לזהות את הדפוסים שהצגתי קודם ואם היא מצליחה, היא משחזרת לפיהם את הבייט המקורי וצובעת את המלבן בגוון אפור מתאים.

מלכודת עכברים

כפי שראיתם בסרטון למעלה, זה עובד – אבל בתנאי אחד: חייבים להשבית את כל ה"שיפורים" שמערכת ההפעלה מוסיפה לתנועת הסמן, אם יש כאלה. פקודת Mouse.move של ארדואינו מקבלת כפרמטרים את מספר הפיקסלים שצריך לזוז בצירי X ו-Y, אך אם יש שיפורים פעילים, התנועה לא תתורגם בהכרח למספר זהה של פיקסלים על המסך וכל העסק ירד לטמיון.

במחשב הנייד שלי עם מערכת הפעלה Windows 7, האפשרויות האלה נמצאות ב-Control Panel->Hardware and Sound->Mouse, והן נראות ככה:

ביטול שיפורי תנועת עכבר ב-Windows 7
ביטול שיפורי תנועת עכבר ב-Windows 7

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

קצב העברת הנתונים שהצלחתי להשיג בשיטה שתוארה הוא כ-150 בייט (1200 ביט) לשניה. זהו ערך נטו, לא כולל הביטים של אות הסינכרון.

קוד מקור וכאלה

הנה כל קוד המקור לארדואינו לאונרדו:

#define SYNC 16
const uint16_t MOUSE_SEQUENCE[17] = {
  0x0492, 0x0960, 0x0618, 0x014A, 0x0A41,   
  0x0249, 0x0096, 0x0861, 0x041A, 0x0168,    
  0x0690, 0x0942, 0x0A14, 0x0294, 0x0069, 
  0x0816, 0x04A1 };

void sendMouseNybble(const uint8_t index) {

  uint16_t s = MOUSE_SEQUENCE[index];
  uint8_t steps = 3;
  int8_t dx, dy;

  while (steps--) {
      dx = ((s >> 10) & 3) - 1; 
      dy = ((s >> 8) & 3) - 1; 
      s <<= 4;
      Mouse.move(dx, dy);
  }
} 

void sendMouseByte(uint8_t b) {
  // Sync signal, then high nybble, then low
  sendMouseNybble(SYNC);
  sendMouseNybble(b >> 4);
  sendMouseNybble(b & 0x0F);
}

void setup() {
  Mouse.begin();
}

void loop() {
  sendMouseByte(analogRead(A0) >> 2);
  delay(100); 
}

כדי ליצור את מחלק המתח לניסוי, חברו נגד תלוי-אור רגיל בין פין 5V ל-A0, ונגד עם ערך גבוה (למשל 20K) בין A0 ל-GND. אנחנו מניחים כאן, כמובן, שפין A0 נשאר תמיד פין קלט, כי אם הוא יהפוך בשלב כלשהו לפין פלט עם ערך LOW, והתאורה על הנגד תלוי-האור תהיה חזקה, עלול לעבור שם זרם חזק מדי שיגרום לנזק.

מחלק מתח תלוי אור למערכת ההדגמה
מחלק מתח תלוי אור למערכת ההדגמה

התוכנה ל-Lazarus מורכבת ממספר קבצים. את המעניין מביניהם העליתי ל-Pastebin, ואתם מוזמנים לקרוא אותו שם ולהתאים אותו לשפה ולסביבת הפיתוח החביבים עליכם. את התוכנה המלאה – קוד מקור בלבד – תוכלו להוריד, אם אתם חייבים, מכאן (נבדק על Lazarus 1.4.0 ב-Windows 7 בלבד).

תוספת מאוחרת: פרויקט זה נשלח והתקבל לפרסום באתר hackaday. הנה הקישור: http://hackaday.com/2015/08/30/use-your-mouse-pointer-to-send-data

להרשמה
הודע לי על
0 תגובות
מהכי חדשה
מהכי ישנה לפי הצבעות
Inline Feedbacks
הראה את כל התגובות