תאימות הקלט

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

מפתחים שרוצים שהאפליקציה שלהם תפעל בצורה טובה עם קלט ב-ChromeOS ובמכשירים אחרים עם מסך גדול שתומכים ב-Android, צריכים לבצע את האופטימיזציות הבאות:

  • הוספה ובדיקה של תמיכה בסיסית במקלדת, כמו ניווט במקלדת באמצעות מקשי החיצים ומקש Tab, מקש Enter לאישור הזנת טקסט ומקש הרווח להפעלה או להשהיה באפליקציות מדיה.
  • להוסיף מקשי קיצור רגילים במקומות הרלוונטיים, למשל ctrl+z לביטול פעולה, ctrl+s לשמירה.
  • בודקים אינטראקציות בסיסיות עם העכבר, כמו לחיצה ימנית לפתיחת תפריט הקשר, שינויים בסמלים כשמעבירים מעליהם את העכבר ואירועי גלילה באמצעות גלגל העכבר או משטח המגע בתצוגות בהתאמה אישית.
  • בודקים מכשירי קלט ספציפיים לאפליקציות, כמו עט סטיילוס לאפליקציות ציור, שלטים למשחקים ובקרי MIDI לאפליקציות מוזיקה.
  • כדאי לשקול תמיכה מתקדמת בקלט שיכולה להבליט את האפליקציה בסביבות מחשב: לוח מגע כפיידר צולב לאפליקציות של תקליטנים, לכידת עכבר למשחקים ומקשי קיצור נרחבים למשתמשים מתקדמים.

מקלדת

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

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

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

yourView.isFocusable = true

אפשרות אחרת היא להגדיר את מאפיין focusable בקובץ הפריסה:

android:focusable="true"

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

// Arrow keys
yourView.nextFocusLeftId = R.id.view_to_left
yourView.nextFocusRightId = R.id.view_to_right
yourView.nextFocusTopId = R.id.view_above
yourView.nextFocusBottomId = R.id.view_below

// Tab key
yourView.nextFocusForwardId = R.id.next_view

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

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

הקשות

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

לדוגמה, אפליקציות צ'אט שמשתמשות במקש Enter כדי לשלוח הודעה, אפליקציות מדיה שמתחילות או מפסיקות את ההפעלה באמצעות מקש הרווח ומשחקים ששולטים בתנועה באמצעות המקשים w,‏ a,‏ s ו-d.

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

override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean {
    return when (keyCode) {
        KeyEvent.KEYCODE_ENTER -> {
            sendChatMessage()
            true
        }
        KeyEvent.KEYCODE_SPACE -> {
            playOrPauseMedia()
            true
        }
        else -> super.onKeyUp(keyCode, event)
    }
}

השימוש ב-onKeyUp מונע מאפליקציות לקבל כמה אירועים אם מקש מוחזק או משוחרר לאט. משחקים ואפליקציות שמצפים מהמשתמשים ללחוץ לחיצה ממושכת על מקשי המקלדת יכולים לחפש את האירוע onKeyDown.

בהתאם לצרכים של האפליקציה, בדרך כלל אפשר להגדיר את onKeyUp לכל הפעילות כדי לקבל את ההתנהגות הרצויה. אם צריך, אפשר להוסיף onKeyListener לתצוגה מפורטת ספציפית במקום. לדוגמה, אפליקציה יכולה להאזין למקש Enter רק ב-EditText ספציפי, ולא ב-Activity, כדי להטמיע פונקציונליות של שליחה רק כשהמשתמש מקליד בתיבת צ'אט.

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

קיצורי דרך

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

חלק ממקשי הקיצור הנפוצים כוללים שמירה (‎ctrl+s), ביטול פעולה (‎ctrl+z) וביצוע חוזר (‎ctrl+shift+z). כדי לראות דוגמה למקשי קיצור מתקדמים יותר, אפשר לעיין ברשימת מקשי הקיצור של VLC Media Player.

אפשר להטמיע קיצורי דרך באמצעות dispatchKeyShortcutEvent. הפונקציה הזו מיירטת את כל השילובים של מקשי מטא (alt,‏ ctrl ו-shift) עבור קוד מקש נתון. כדי לבדוק מטא-מפתח ספציפי, משתמשים ב-KeyEvent.isCtrlPressed(),‏ KeyEvent.isShiftPressed(),‏ KeyEvent.isAltPressed() או KeyEvent.hasModifiers().

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

override fun dispatchKeyShortcutEvent(event: KeyEvent): Boolean {
  return when (event.keyCode) {
    KeyEvent.KEYCODE_O -> {
      openFile() // Ctrl+O, Shift+O, Alt+O
      true
    }
    KeyEvent.KEYCODE_Z-> {
      if (event.isCtrlPressed) {
        if (event.isShiftPressed) {
          redoLastAction() // Ctrl+Shift+Z pressed
          true
        } else {
          undoLastAction() // Ctrl+Z pressed
          true
        }
      }
    }
    else -> {
      return super.dispatchKeyShortcutEvent(event)
    }
  }
}

אפשר גם להטמיע קיצורי דרך ב-onKeyUp על ידי בדיקה של KeyEvent.isCtrlPressed(), KeyEvent.isShiftPressed() או KeyEvent.isAltPressed() באותו אופן. יכול להיות שיהיה קל יותר לתחזק את זה אם התנהגות המטא היא יותר שינוי בהתנהגות האפליקציה מאשר קיצור דרך. לדוגמה, כש-w מייצג 'הליכה קדימה' ו-Shift+w מייצג 'ריצה קדימה'.

override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean {
  return when(keyCode) {
    KeyEvent.KEYCODE_W-> {
      if (event.isShiftPressed) {
        if (event.isCtrlPressed) {
          flyForward() // Ctrl+Shift+W pressed
          true
        } else {
          runForward() // Shift+W pressed
          true
        }
      } else {
        walkForward() // W pressed
      }
    }
    else -> super.onKeyUp(keyCode, event)
  }
}

תמיכה בעכבר ובמשטח מגע

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

לחיצה ימנית

כל פעולה שגורמת לאפליקציה להציג תפריט הקשר, כמו לחיצה ארוכה על פריט ברשימה, צריכה להגיב גם לאירועי לחיצה ימנית. כדי לטפל באירועים של לחיצה ימנית, האפליקציות צריכות לרשום View.OnContextClickListener. לפרטים על יצירת תפריט הקשר, אפשר לעיין בתיעוד של תפריט ההקשר ב-Android.

yourView.setOnContextClickListener { view ->
  showContextMenu()
  true
}

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

ריחוף

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

  • שינוי של סמל מצביע העכבר כדי לציין למשתמשים אם לרכיב יש התנהגות אינטראקטיבית, למשל אם אפשר ללחוץ עליו או לערוך אותו
  • הוספת משוב חזותי לפריטים ברשימה גדולה או ברשת כשמצביעים עליהם עם העכבר
// Change the icon to a "hand" pointer on hover,
// Highlight the view by changing the background.
yourView.setOnHoverListener { view, _ ->
  addVisualHighlighting(true)
  view.pointerIcon =
    PointerIcon.getSystemIcon(applicationContext,
    PointerIcon.TYPE_HAND)
  false // listener did not consume the event.
}

גרירה ושחרור

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

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

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

שיקולים מיוחדים לגבי ChromeOS

  • כדי לטפל בקבצים מאפליקציית הקבצים של ChromeOS, מחפשים את סוג ה-MIME application/x-arc-uri-list
  • חשוב לזכור לבקש הרשאה באמצעות requestDragAndDropPermissions כדי לגשת לפריטים שנגררו מחוץ לאפליקציה
  • כדי שיהיה אפשר לגרור פריט לאפליקציות אחרות, צריך להוסיף לו את הדגל View.DRAG_FLAG_GLOBAL

תמיכה בבחירה מרובה

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

דוגמה לבחירה מרובה של רצועות באמצעות עכבר וסמן.

תמיכה מתקדמת במצביע

אפליקציות שמבצעות טיפול מתקדם בקלט של עכבר ולוח מגע צריכות לפעול בהתאם לתיעוד של Android בנושא View.onGenericMotionEvent() ולהשתמש ב-MotionEvent.getSource() כדי להבחין בין SOURCE_MOUSE לבין SOURCE_TOUCHSCREEN.

בודקים את MotionEvent כדי להטמיע את ההתנהגות הנדרשת:

  • תנועה יוצרת אירועים של ACTION_HOVER_MOVE
  • הלחצנים יוצרים אירועים מסוג ACTION_BUTTON_PRESS ו-ACTION_BUTTON_RELEASE. אפשר גם לבדוק את המצב הנוכחי של כל הלחצנים בעכבר או בלוח המגע באמצעות getButtonState().
  • גלילה באמצעות גלגל העכבר יוצרת אירועים מסוג ACTION_SCROLL

סטיילוס

במכשירי Chromebook רבים יש סטיילוס, ואפליקציות ל-Android מתייחסות לסטיילוס כקלט למסך מגע. יכול להיות שיהיו לכם גם מכשירים עם לוח ציור USB או Bluetooth, כמו Wacom Intuos. אפליקציות ל-Android יכולות לקבל קלט מ-Bluetooth, אבל לא יפעלו עם קלט מ-USB.

אירוע של עט סטיילוס מדווח כאירוע של מסך מגע באמצעות View.onTouchEvent() או View.onGenericMotionEvent(), והוא מכיל MotionEvent.getSource() מסוג SOURCE_STYLUS. הקובץ MotionEvent יכיל גם נתונים נוספים:

נקודות היסטוריות

מערכת Android מאגדת אירועי קלט ומעבירה אותם פעם אחת לכל פריים. עט סטיילוס יכול לדווח על אירועים בתדירות גבוהה בהרבה מזו של המסך. כשיוצרים אפליקציות לציור, חשוב לבדוק אירועים שאולי התרחשו לאחרונה באמצעות ממשקי ה-API של getHistorical:

  • MotionEvent.getHistoricalX()
  • MotionEvent.getHistoricalY()
  • MotionEvent.getHistoricalPressure()
  • MotionEvent.getHistoricalAxisValue()

דחיית מגע כף היד

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

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

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

אפליקציות לרישום הערות

ל-ChromeOS יש כוונה מיוחדת להציג למשתמשים אפליקציות רשומות לכתיבת פתקים. כדי לרשום אפליקציה כאפליקציה לרישום הערות, מוסיפים את השורה הבאה למניפסט של Android:

<intent-filter>
    <action android:name="org.chromium.arc.intent.action.CREATE_NOTE" />
    <category android:name="android.intent.category.DEFAULT" />
  </intent-filter>

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

בדיקת כוונות של כתיבת הערות ללא סטיילוס

כדי לבדוק אם אפליקציה מגיבה בצורה נכונה לכוונות של יצירת הערות בלי עט פעיל, אפשר להשתמש בשיטה הבאה כדי להציג את האפשרויות ליצירת הערות:

  1. מעבר למצב פיתוח והפיכת המכשיר לניתן לכתיבה
  2. מקישים על ctrl+alt+f2כדי לפתוח טרמינל
  3. מריצים את הפקודה sudo vi /etc/chrome_dev.conf
  4. מקישים על i כדי לערוך ולהוסיף את --ash-enable-palette לשורה חדשה בסוף הקובץ
  5. כדי לשמור, מקישים על Esc, מקלידים :,‏ w,‏ q ומקישים על Enter.
  6. מקישים על ctrl+alt+f1 כדי לחזור לממשק המשתמש הרגיל של ChromeOS

עכשיו אמור להופיע תפריט עט הסטיילוס במדף:

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

בקרי משחקים

מכשירי Chromebook תומכים בעד ארבעה בקרי משחקים. מפתחים צריכים להשתמש בממשקי API סטנדרטיים של בקר משחקים ב-Android כדי לטפל בהם.

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

שיטת קלט לתרגום

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

אם באפליקציה מיושמת התנהגות קלט מותאמת אישית, למשל הגדרה של פעולת צביטה מותאמת אישית בלוח מגע עם שתי אצבעות, או אם תרגומי הקלט האלה לא מספקים את אירועי הקלט שהאפליקציה מצפה להם, אפשר להשבית את מצב תרגום הקלט על ידי הוספת התג הבא למניפסט של Android:

<uses-feature android:name="android.hardware.type.pc"
              android:required="false" />