1/* 2 * Copyright (c) 2023 Fujian Newland Auto-ID Tech.Co.,Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15import { InputDeviceInfo } from '../model/InputDeviceInfo' 16import { logger } from '@ohos/common' 17import inputDevice from '@ohos.multimodalInput.inputDevice' 18 19const TAG: string = '[Sample_InputDeviceUtil]' 20 21/** 22 * 获取设备列表 23 * @param callback 回调 24 */ 25export function getDeviceList(callback: (data: InputDeviceInfo[]) => void) { 26 // 获取所有输入设备ID列表 27 try { 28 inputDevice.getDeviceList().then(async (ids) => { 29 logger.info(`${TAG} Device id list: ${JSON.stringify(ids)}`) 30 if (!ids || ids.length <= 0) { 31 return 32 } 33 // 根据设备ID获取设备信息 34 try { 35 let devices: InputDeviceInfo[] = [] 36 for (const item of ids) { 37 logger.info(`${TAG} get device info, id: ${item}`) 38 let deviceData: InputDeviceInfo | null = await getDeviceInfo(item); 39 if (deviceData !== null && devices.indexOf(deviceData) === -1) { 40 logger.info(`${TAG} add device, deviceId: ${deviceData.id}`) 41 devices.push(deviceData) 42 } 43 } 44 callback(devices) 45 } catch (error) { 46 logger.error(`${TAG} Failed to get device info, error: ${JSON.stringify(error, [`code`, `message`])}`) 47 } 48 }) 49 } catch (error) { 50 logger.error(`${TAG} Failed to get device id list, error: ${JSON.stringify(error, [`code`, `message`])}`) 51 } 52} 53 54/** 55 * 获取设备信息 56 * @param deviceId 设备ID 57 */ 58export async function getDeviceInfo(deviceId: number): Promise<InputDeviceInfo | null> { 59 60 try { 61 let deviceData: InputDeviceInfo; 62 let inputDeviceData: inputDevice.InputDeviceData = await inputDevice.getDeviceInfo(deviceId) 63 logger.info(`${TAG} get device info ${JSON.stringify(inputDeviceData)}`) 64 deviceData = { 65 id: inputDeviceData.id, 66 name: inputDeviceData.name, 67 sources: inputDeviceData.sources, 68 axisRanges: inputDeviceData.axisRanges, 69 bus: inputDeviceData.bus, 70 product: inputDeviceData.product, 71 vendor: inputDeviceData.vendor, 72 version: inputDeviceData.version, 73 phys: inputDeviceData.phys, 74 uniq: inputDeviceData.uniq, 75 icon_source: getDeviceIcon(inputDeviceData.sources), 76 connect: false 77 } 78 return deviceData; 79 } catch (error) { 80 logger.error(`${TAG} Failed to get device info, error: ${JSON.stringify(error, [`code`, `message`])}`) 81 } 82 83 return null; 84} 85 86/** 87 * 获取设备的图标 88 * @param sources 输入设备支持的源类型 89 */ 90function getDeviceIcon(sources: string[]): Resource { 91 logger.info(`${TAG} getDeviceIcon: ${sources}`) 92 if (!sources || sources.length <= 0) { 93 return $r('app.media.icon_input_device_default') 94 } 95 let res: Resource 96 let sourceType = sources[0] 97 if (sourceType === 'keyboard') { 98 res = $r('app.media.icon_keyboard') 99 } else if (sourceType === 'mouse') { 100 res = $r('app.media.icon_mouse') 101 } else if (sourceType === 'touchpad') { 102 res = $r('app.media.icon_touchpad') 103 } else if (sourceType === 'touchscreen') { 104 res = $r('app.media.icon_touchscreen') 105 } else if (sourceType === 'joystick') { 106 res = $r('app.media.icon_joystick') 107 } else if (sourceType === 'trackball') { 108 res = $r('app.media.icon_trackball') 109 } else { 110 res = $r('app.media.icon_input_device_default') 111 } 112 return res 113} 114 115class InputDevice { 116 private callback: Function | null = null; 117 private deviceList: InputDeviceInfo[] = [] 118 119 public registerChange(callback: Function): void { 120 logger.info(`${TAG} registerChange`) 121 try { 122 this.callback = callback 123 inputDevice.on('change', (data: inputDevice.DeviceListener) => this.onChangeCallback(data)); 124 } catch (error) { 125 logger.error(`${TAG} Listen device event failed, error: ${JSON.stringify(error, [`code`, `message`])}`) 126 } 127 } 128 129 public unregisterChange(): void { 130 try { 131 inputDevice.off('change') 132 this.deviceList = [] 133 if (this.callback && this.callback !== null) { 134 this.callback(this.deviceList) 135 this.callback = null 136 } 137 logger.info(`${TAG} Monitor off success`) 138 } catch (error) { 139 logger.error(`${TAG} Cancel listening device event failed, error: ${JSON.stringify(error, [`code`, `message`])}`) 140 } 141 142 } 143 144 private async onChangeCallback(data: inputDevice.DeviceListener) { 145 logger.info(`${TAG} onChangeCallback event: ${JSON.stringify(data)}`) 146 // 获取设备信息 147 let deviceId: number = data.deviceId 148 let deviceInfo: InputDeviceInfo | null = null; 149 let curIndex: number = -1 150 let tempIndex: number = -1 151 let delCount: number = 0 152 if (this.deviceList && this.deviceList.length > 0) { 153 for (const element of this.deviceList) { 154 tempIndex++ 155 if (element.id === deviceId) { 156 deviceInfo = element 157 curIndex = tempIndex 158 delCount = 1 159 break 160 } 161 } 162 } 163 164 if (deviceInfo == null) { 165 deviceInfo = await getDeviceInfo(deviceId) 166 } 167 // 根据状态修改 168 let type: inputDevice.ChangedType = data.type 169 if (type === 'add' && deviceInfo !== null && deviceInfo !== undefined) { 170 // 连接 171 deviceInfo.connect = true 172 } else if (type === 'remove' && deviceInfo !== null && deviceInfo !== undefined) { 173 // 断开 174 deviceInfo.connect = false 175 } 176 177 if (deviceInfo !== null) { 178 this.deviceList.splice(curIndex, delCount, deviceInfo); 179 } 180 logger.info(`${TAG} get device info deviceId count:${this.deviceList.length}}`) 181 // fixme xjs 当前OH 3.2 release系统存在应用多次启动后出现回调多次,所以这里进行数据去重处理 182 this.deviceList = this.removeDuplicate(this.deviceList) 183 logger.info(`${TAG} get device info deviceId: ${deviceId} deviceInfo: ${JSON.stringify(deviceInfo)} count:${this.deviceList.length}}`) 184 185 if (this.callback && this.callback !== null) { 186 this.callback(this.deviceList) 187 } 188 } 189 190 /** 191 * 列表对象去重 192 * @param arr 列表 193 */ 194 private removeDuplicate(arr: InputDeviceInfo[]): InputDeviceInfo[] { 195 const newArr: InputDeviceInfo[] = []; 196 for (const item of arr) { 197 // 检查缓存中是否已经存在 198 if (newArr.find((cur: InputDeviceInfo) => 199 cur.id === item.id && 200 cur.name === item.name && 201 cur.connect === item.connect) 202 ) { 203 // 已经存在说明以前记录过,现在这个就是多余的,直接忽略 204 continue; 205 } 206 // 不存在就说明以前没遇到过,把它记录下来 207 newArr.push(item) 208 } 209 // 记录结果就是过滤后的结果 210 return newArr 211 } 212} 213 214export default new InputDevice()