Google은 흑인 공동체를 위한 인종 간 평등을 진전시키기 위해 노력하고 있습니다. Google에서 어떤 노력을 하고 있는지 확인하세요.

Chromebook 입력 호환성

Chrome OS 기기에서 많은 사용자가 키보드, 마우스, 트랙패드, 스타일러스 또는 게임패드를 사용하여 앱과 상호작용합니다. 이러한 입력 기기는 Android 휴대전화에서도 사용되지만 일반적이지 않으며 개발자가 간과하는 경우가 많습니다.

앱이 Chrome OS 및 화면이 큰 기타 Android 지원 기기에서 입력 시 제대로 작동하도록 하려면 개발자는 다음 최적화를 검토해야 합니다.

  • 화살표 및 탭 키를 통한 키보드 탐색, 텍스트 입력 확인을 위한 Enter 키, 미디어 앱에서 재생/일시중지를 위한 스페이스 바 같은 기본 키보드 지원을 추가하고 테스트합니다.

  • 해당하는 경우 표준 단축키를 추가합니다(예: 실행취소의 경우 Ctrl + Z, 저장의 경우 Ctrl + S).

  • 마우스 오른쪽 버튼으로 클릭 시 컨텍스트 메뉴 표시, 마우스 오버 시 아이콘 변경 및 맞춤 뷰에서 마우스 휠/트랙패드 스크롤 이벤트와 같은 방식으로 기본 마우스 상호작용을 테스트합니다.

  • 그리기 앱용 스타일러스, 게임용 게임 컨트롤러 및 음악 앱용 MIDI 컨트롤러와 같이 특정 앱에 사용되는 입력 기기를 테스트합니다.

  • 데스크톱 환경에서 앱을 돋보이게 만들 수 있는 고급 입력 지원 기능을 고려합니다(예: DJ 앱의 크로스페이더로 사용되는 터치패드, 게임용 마우스 캡처, 고급 사용자용 확장 단축키).

키보드

앱이 키보드 입력에 어떻게 반응하는지는 원활한 데스크톱 환경에 기여합니다. 키보드 입력에는 탐색, 키 입력, 단축키의 세 가지 종류가 있습니다.

키보드 탐색은 터치 중심 앱에서는 거의 실행되지 않지만, 사용자는 앱을 사용하고 키보드에 손을 댈 때 키보드 탐색을 사용할 수 있을 것으로 생각합니다. 또한 휴대전화와 데스크톱 기기 모두에 대해 접근성과 관련한 요구사항을 가진 사용자에게 필수적일 수 있습니다.

많은 앱에서 간단한 화살표 키와 탭 탐색만으로도 충분하며 이는 대부분 Android 프레임워크에 의해 자동으로 처리됩니다. 예를 들어 Button 뷰는 기본적으로 포커스가 가능하며, 키보드 탐색은 일반적으로 추가 코드 없이 작동해야 합니다. 기본적으로 포커스가 가능하지 않은 뷰에 키보드 탐색을 사용 설정하려면 개발자는 이러한 뷰를 포커스 가능으로 표시해야 합니다. 이 작업은 아래와 같이 프로그램상에서 또는 XML로 할 수 있습니다. 자세한 내용은 포커스 처리 문서를 참조하세요.

Kotlin

yourView.isFocusable = true

자바

yourView.setFocusable(true);

또는 다음과 같이 레이아웃 파일에서 focusable 속성을 설정할 수 있습니다.

android:focusable="true"

포커스가 사용 설정되면 Android 프레임워크는 위치를 기반으로 포커스 가능한 모든 뷰의 탐색 매핑을 생성합니다. 이 매핑은 일반적으로 예상대로 작동하며 추가 작업이 필요하지 않습니다. 기본 매핑이 앱의 요구에 적합하지 않을 때는 다음과 같이 재정의할 수 있습니다.

Kotlin

// 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

자바

// Arrow keys
yourView.setNextFocusLeftId(R.id.view_to_left);
yourView.setNextFocusRightId(R.id.view_to_left);
yourView.setNextFocusTopId(R.id.view_to_left);
yourView.setNextFocusBottomId(R.id.view_to_left);

// Tab key
yourView.setNextFocusForwardId(R.id.next_view);

각각의 출시 전에 키보드만 사용하여 앱의 모든 기능에 액세스해 보는 것이 좋습니다. 마우스나 터치 입력 없이 가장 일반적인 작업에 쉽게 액세스할 수 있어야 합니다.

접근성과 관련한 요구사항을 가진 사용자에게는 키보드 지원이 필수적일 수 있습니다.

키 입력

EditText와 같은 화면 가상 키보드(IME)로 처리되는 텍스트 입력의 경우 앱은 개발자의 추가 작업 없이 Chrome OS에서 예상대로 작동해야 합니다. 프레임워크에서 예상할 수 없는 키 입력의 경우 앱이 동작을 직접 처리해야 합니다. 이는 맞춤 뷰가 있는 앱의 경우에 특히 그렇습니다.

몇 가지 예로 Enter 키를 사용하여 메시지를 보내는 채팅 앱, 스페이스 바로 재생을 시작/중지하는 미디어 앱, w, a, s, d 키로 움직임을 제어하는 게임이 있습니다.

대부분의 앱은 아래와 같이 onKeyUp 이벤트를 재정의하고 수신된 키 코드마다 예상되는 동작을 추가합니다.

Kotlin

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)
    }
}

자바

@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_ENTER) {
        sendMessage();
        return true;
    } else if (KeyEvent.KEYCODE_SPACE){
        playOrPauseMedia();
        return true;
    } else {
        return super.onKeyUp(keyCode, event);
    }
}

onKeyUp을 사용하면 키를 누른 채로 있거나 천천히 손을 뗄 때 앱이 여러 이벤트를 수신하지 못합니다. 사용자가 키보드 키를 누르고 있어야 하는 게임 및 앱에서는 onKeyDown 이벤트를 기대하고 찾을 수 있습니다.

키보드 지원 추가 시 Android 키보드 처리 문서를 따르세요.

단축키

데스크톱 환경에서는 일반적인 Ctrl, Alt 및 Shift 기반 단축키가 예상됩니다. 앱에서 이러한 단축키를 구현하지 않으면 사용자가 앱 사용 환경에 불편과 혼란을 겪을 수 있습니다. 또한 고급 사용자는 개별 앱별로 자주 사용하는 작업을 위한 단축키도 유용하게 사용합니다. 단축키가 있으면 앱을 편리하게 사용할 수 있으며 단축키가 없는 앱과 차별화됩니다.

몇 가지 일반적인 단축키로는 Ctrl + S(저장), Ctrl + Z(실행취소) 및 Ctrl + Shift + Z(다시 실행)가 있습니다. 고급 단축키의 몇 가지 예는 VLC 미디어 플레이어 단축키 목록을 참조하세요.

단축키는 dispatchKeyShortcutEvent를 사용하여 구현할 수 있습니다. 이 메서드는 지정된 키 코드의 모든 메타 키 조합(Alt, Ctrl 및 Shift)을 대체합니다. 특정 메타 키를 확인하려면 KeyEvent.isCtrlPressed(), KeyEvent.isShiftPressed(), KeyEvent.isAltPressed() 또는 KeyEvent.hasModifiers()를 사용하세요.

다른 키 입력 처리(예: onKeyUp 또는 onKeyDown)에서 단축키 코드를 분리하면 코드 유지관리가 더 쉬워지며 모든 경우에 메타 키 확인을 수동으로 구현할 필요 없이 메타 키의 기본 수용을 유지할 수 있습니다. 모든 메타 키 조합을 허용하면 다양한 키보드 레이아웃 및 운영체제에 익숙한 사용자에게 더 편리할 수 있습니다.

Kotlin

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)
    }
  }
}

자바

@Override
public boolean dispatchKeyShortcutEvent(KeyEvent event) {
  if (event.getKeyCode() == KeyEvent.KEYCODE_O) {
      openFile(); // Ctrl+O, Shift+O, Alt+O
      return true;
  } else if(event.getKeyCode() == KeyEvent.KEYCODE_Z) {
      if (event.isCtrlPressed()) {
          if (event.isShiftPressed()) {
              redoLastAction();
              return true;
          }
          else {
              undoLastAction();
              return true;
          }
      }
  }
  return super.dispatchKeyShortcutEvent(event);
}

위와 동일한 방식으로 KeyEvent.isCtrlPressed(), KeyEvent.isShiftPressed() 또는 KeyEvent.isAltPressed()를 확인하여 onKeyUp에서 단축키를 구현할 수도 있습니다. 메타 동작이 단축키보다는 오히려 앱 동작에 대한 수정이라면 이 방법이 유지관리하기 더 쉬울 수 있습니다. W가 '앞으로 걷기'를 의미하고 Shift + W가 '앞으로 달리기'를 의미할 때를 예로 들 수 있습니다.

Kotlin

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
        true
      }
    }
    else -> super.onKeyUp(keyCode, event)
  }
}

자바

@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_W) {
        if (event.isShiftPressed()) {
            if (event.isCtrlPressed()) {
                flyForward(); // Ctrl+Shift+W pressed
                return true;
            } else {
                runForward(); // Shift+W pressed
                return true;
            }
        } else {
            walkForward();
            return true;
        }
    }
    return super.onKeyUp(keyCode, event);
}

마우스 및 터치패드 지원

Chrome OS는 대부분의 마우스 및 트랙패드 이벤트를 자동으로 처리하므로 이러한 이벤트는 Android 휴대전화에서 터치 이벤트처럼 작동합니다. 여기에는 두 손가락 터치패드/마우스 휠 스크롤이 포함됩니다. 대부분의 앱은 일반적으로 세 가지 데스크톱 중심 이벤트 즉, 마우스 오른쪽 버튼 클릭, 마우스 오버, 드래그 앤 드롭만 처리하면 됩니다.

마우스 오른쪽 버튼 클릭

목록 항목을 길게 누르는 것과 같이 앱이 컨텍스트 메뉴를 표시하게 하는 작업은 마우스 오른쪽 버튼 클릭 이벤트에도 반응해야 합니다. 마우스 오른쪽 버튼 클릭 이벤트를 처리하려면 앱에서 View.OnContextClickListener를 등록해야 합니다. 컨텍스트 메뉴 구성에 관한 자세한 내용은 Android 컨텍스트 메뉴 문서를 참조하세요.

Kotlin

yourView.setOnContextClickListener {
  showContextMenu()
  true
}

자바

yourView.setOnContextClickListener(v -> {
    showContextMenu();
    return true;
});

마우스 오버

개발자는 마우스 오버 이벤트를 처리하여 앱 레이아웃을 세련되고 사용하기 쉽게 만들 수 있습니다. 이는 맞춤 뷰의 경우에 특히 그렇습니다. 이와 관련한 가장 일반적인 두 가지 예는 다음과 같습니다.

  • 마우스 포인터 아이콘을 변경하여 요소에 클릭 가능 또는 수정 가능과 같은 상호작용 동작이 있는지 사용자에게 표시
  • 큰 목록 또는 그리드의 항목 위에 마우스 포인터를 가져가면 해당 항목에 시각적 피드백 추가

Kotlin

// 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(view.context,
    PointerIcon.TYPE_HAND)
  false // listener did not consume the event.
}

자바

yourView.setOnHoverListener((view, event) -> {
    addVisualHighlighting(true);
    view.setPointerIcon(PointerIcon
            .getSystemIcon(view.getContext(), PointerIcon.TYPE_HAND));
    return true;
});

드래그 앤 드롭

멀티 윈도우 환경에서 사용자는 앱 간에 항목을 드래그 앤 드롭할 수 있을 것으로 기대합니다. 이러한 기대는 화면 분할 모드의 태블릿, 휴대전화 및 폴더블뿐만 아니라 Chrome OS 기기에도 적용됩니다.

개발자는 사용자가 항목을 앱으로 드래그할 가능성이 있는지 고려해야 합니다. 몇 가지 일반적인 예를 들면 사진 편집기에서 사진을 받거나 오디오 플레이어에서 오디오 파일을 받거나 그리기 프로그램에서 사진을 받는 것을 예상할 수 있습니다.

드래그 앤 드롭 지원을 추가하려면 Android 드래그 앤 드롭 문서를 따르고 이 Chrome OS 블로그 게시물을 살펴보세요.

Chrome OS의 특별 고려사항

  • Chrome OS Files 앱의 파일을 처리하려면 MIME 유형 application/x-arc-uri-list를 찾습니다.
  • 앱 외부에서 드래그한 항목에 액세스하려면 requestDragAndDropPermissions를 통해 권한을 요청해야 합니다.
  • 항목을 다른 애플리케이션으로 드래그하려면 항목에 View.DRAG_FLAG_GLOBAL 플래그가 있어야 합니다.

고급 포인터 지원

마우스 및 터치패드 입력의 고급 처리를 실행하는 앱은 View.onGenericMotionEvent()에 관한 Android 문서를 따르고 MotionEvent.getSource()를 사용하여 SOURCE_MOUSESOURCE_TOUCHSCREEN을 구분해야 합니다.

MotionEvent를 검토하여 필요한 동작을 구현합니다.

  • 움직임은 ACTION_HOVER_MOVE 이벤트를 생성합니다.
  • 버튼은 ACTION_BUTTON_PRESSACTION_BUTTON_RELEASE 이벤트를 생성합니다. 또한 getButtonState()를 사용하여 모든 마우스/트랙패드 버튼의 현재 상태를 확인할 수도 있습니다.
  • 마우스 휠 스크롤은 ACTION_SCROLL 이벤트를 생성합니다.

스타일러스

대부분의 Chromebook에는 스타일러스가 함께 제공되며 Android 앱은 이를 터치스크린 입력으로 처리합니다. 일부 기기에는 Wacom Intuos와 같은 USB 또는 블루투스 그리기 테이블이 있을 수도 있습니다. Android 앱은 블루투스 입력을 수신할 수 있지만 USB 입력에서는 작동하지 않습니다.

스타일러스 이벤트는 View.onTouchEvent() 또는 View.onGenericMotionEvent()를 통해 터치스크린 이벤트로 보고되며 SOURCE_STYLUS 유형의 MotionEvent.getSource()를 포함합니다. MotionEvent는 다음과 같이 추가 데이터도 포함합니다.

이전 포인트

Android는 입력 이벤트를 일괄 처리하며 프레임당 한 번씩 전달합니다. 스타일러스 펜은 디스플레이보다 훨씬 자주 이벤트를 보고할 수 있습니다. 그리기 앱을 만들 때는 다음과 같은 getHistorical API를 사용하여 최근에 발생한 이벤트를 확인하는 것이 중요합니다.

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

손바닥 움직임 무시

Chrome OS는 사용자의 손바닥이 터치스크린에 닿으면 감지하려고 시도합니다. 그러나 이러한 감지가 항상 가능한 것은 아닙니다. 때로 OS가 터치를 손바닥으로 인식하기 전에 터치 이벤트가 앱에 보고될 수 있습니다. 이 경우 ACTION_CANCEL 이벤트를 보고하면 터치가 취소됩니다.

이 이벤트는 특정 터치가 무효이며 이 터치로 인해 발생하는 모든 상호작용을 실행취소해야 한다고 앱에 알립니다. 예를 들어 그리기 앱은 새로운 선이 수신되는 즉시 이 선을 임시로 그려서 지연 시간을 최소화할 수 있지만 터치 시리즈가 완전히 완료된 후에만 이 선을 캔버스에 영구적으로 그릴 수 있습니다. 그사이 터치 이벤트가 취소되면 임시 선을 쉽게 삭제할 수 있습니다.

메모 작성 앱

Chrome OS에는 등록된 메모 작성 앱을 사용자에게 표시하는 특별한 인텐트가 있습니다. 앱을 메모 작성 앱으로 등록하려면 Android 매니페스트에 다음을 추가합니다.

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

앱이 등록되면 사용자는 이 앱을 기본 메모 작성 앱으로 선택할 수 있습니다. 새 메모가 요청되면 앱에서 스타일러스 입력을 위한 빈 메모를 생성할 것입니다. 사용자가 이미지(예: 스크린샷 또는 다운로드한 이미지)에 주석을 추가하려는 경우 content:// URI가 있는 하나 이상의 항목이 포함된 ClipData를 사용하여 앱이 실행됩니다. 앱은 처음 첨부된 이미지를 배경 이미지로 사용하는 메모를 생성하고 사용자가 스타일러스를 사용하여 그릴 수 있는 모드로 전환해야 합니다.

스타일러스 없이 메모 작성 인텐트 테스트

앱이 활성화된 스타일러스 없이 메모 작성 인텐트에 올바르게 응답하는지 테스트하려면 다음 방법을 사용하여 메모 작성 옵션을 표시합니다.

  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을 눌러 일반 Chrome OS UI로 돌아갑니다.
  7. 로그아웃했다가 다시 로그인합니다.

이제 실행기에 스타일러스 메뉴가 있을 것입니다.

  • 실행기에서 스타일러스 버튼을 탭하고 새 메모를 선택합니다. 그러면 비어 있는 그리기 메모가 열립니다.
  • 스크린샷을 찍습니다. 실행기에서 스타일러스 버튼 > 화면 캡처를 선택하거나 이미지를 다운로드합니다. 알림에 '이미지에 주석 달기' 옵션이 있을 것입니다. 그러면 주석을 추가할 준비가 된 이미지와 함께 앱이 실행됩니다.

게임 컨트롤러

Chromebook은 최대 4개의 게임 컨트롤러를 지원합니다. 개발자는 표준 Android 게임 컨트롤러 API를 사용하여 게임 컨트롤러를 처리해야 합니다.

버튼은 일반 매핑에 따라 일반 값에 매핑됩니다. 안타깝게도 모든 게임 컨트롤러 제조업체가 동일한 매핑 규칙을 따르는 것은 아닙니다. 사용자가 널리 사용되는 다양한 컨트롤러 매핑을 선택하도록 허용하면 훨씬 더 나은 환경을 제공할 수 있습니다.

입력 변환 모드

Chrome OS는 기본적으로 입력 변환 모드를 사용 설정합니다. 대부분의 Android 앱에서 이 모드를 사용하면 앱이 데스크톱 환경에서 예상대로 작동합니다. 몇 가지 예로는 터치패드에서 두 손가락 스크롤, 마우스 휠 스크롤, 창 좌표에 원시 디스플레이 좌표 매핑 자동 사용 설정 등이 있습니다. 일반적으로 앱 개발자는 이러한 동작을 직접 구현할 필요가 없습니다.

앱에서 맞춤 입력 동작을 구현하거나(예: 터치패드에서 두 손가락 모으기 동작의 맞춤 정의) 이러한 입력 변환이 앱에서 예상하는 입력 이벤트를 제공하지 않는다면 Android 매니페스트에 다음 태그를 추가하여 입력 변환 모드를 사용 중지할 수 있습니다.

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