/* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.eyedropper.util import android.hardware.input.InputManager import android.os.Handler import android.view.InputDevice import androidx.compose.ui.geometry.Offset import javax.inject.Inject import javax.inject.Singleton @Singleton // Match scope of InputManager class InputHelper @Inject constructor( private val inputManager: InputManager, private val mainThreadHandler: Handler, ) { fun getInputDeviceIds(): IntArray { return inputManager.inputDeviceIds } fun isDesktopMode(): Boolean { return hasMouseConnected() && hasKeyboardConnected() } fun hasKeyboardConnected(): Boolean { return inputManager.inputDeviceIds.any { deviceId -> isFullKeyboard(deviceId) } } fun hasMouseConnected(): Boolean { return inputManager.inputDeviceIds.any { deviceId -> isMouse(deviceId) } } fun isFullKeyboard(deviceId: Int): Boolean { val device = inputManager.getInputDevice(deviceId) ?: return false return device.isEnabled && device.isFullKeyboard && !device.isVirtual } fun isMouse(deviceId: Int): Boolean { val device = inputManager.getInputDevice(deviceId) ?: return false return device.supportsSource(InputDevice.SOURCE_MOUSE) && !device.isVirtual && device.isEnabled } fun registerInputDeviceListener(listener: InputManager.InputDeviceListener) { inputManager.registerInputDeviceListener(listener, mainThreadHandler) } fun unregisterInputDeviceListener(listener: InputManager.InputDeviceListener) { inputManager.unregisterInputDeviceListener(listener) } /** * Returns the coordinates of the cursor alongside its displayId. * Exhaustively search all displays until finds one with cursor, else null. */ fun getCursorPosition(displayIds: Set): Pair? { displayIds.forEach { displayId -> val pos = inputManager.getCursorPosition(displayId) if (pos != null) { return Pair(displayId, Offset(pos.x, pos.y)) } } return null } }