import { DRC_METHOD } from '@/const/drc.js' import { ElMessage } from 'element-plus' import { postPayloadCommands, ptzControlApi } from '@/api/payload' import _, { throttle } from 'lodash' import EventBus from '@/utils/eventBus' import store from '@/store/' let myInterval export const KeyCode = { KEY_W: 'KeyW', KEY_A: 'KeyA', KEY_S: 'KeyS', KEY_D: 'KeyD', KEY_Q: 'KeyQ', KEY_E: 'KeyE', KEY_J: 'KeyJ', KEY_K: 'KeyK', KEY_L: 'KeyL', KEY_X: 'KeyX', KEY_Z: 'KeyZ', KEY_C: 'KeyC', KEY_I: 'KeyI', KEY_O: 'KeyO', ARROW_UP: 'ArrowUp', ARROW_DOWN: 'ArrowDown', ARROW_LEFT: 'ArrowLeft', ARROW_RIGHT: 'ArrowRight', NUMPAD_SUBTRACT: 'NumpadSubtract', NUMPAD_ADD: 'NumpadAdd', // 提升速度 KEY_EQUAL: 'Equal', KEY_MINUS: 'Minus', // 录音 KEY_N: 'KeyN', KEY_M: 'KeyM', } export function useManualControl(mqttHooks,deviceTopicInfo,paramsRef,isManualControl,modelCode,activeBtnList) { let activeCodeKey = null let genPortOne = true //是一代机场 let seq = 0 let downTime = null; // 按键按下时间 const keysPressed = [ {key: 'KeyQ', value: false}, {key: 'KeyW', value: false}, {key: 'KeyE', value: false}, {key: 'KeyA', value: false}, {key: 'KeyS', value: false}, {key: 'KeyD', value: false}, {key: 'KeyC', value: false}, {key: 'KeyZ', value: false}, {key: 'ArrowUp', value: false}, {key: 'ArrowDown', value: false}, {key: 'ArrowLeft', value: false}, {key: 'ArrowRight', value: false}, ] // QE按键额外处理 function qKeyEKeyHandle() { let ratio = (Date.now()-downTime) / 4000 if (ratio > 1) ratio = 1; if (ratio < 0.1) ratio = 0.1; const W_SPEED = (genPortOne ? 90 : 600) * ratio let obj if (activeCodeKey === 'KeyQ'){ obj = { yaw: 1024-W_SPEED } if (genPortOne) {obj = {w: -W_SPEED}} }else{ obj = { yaw: 1024+W_SPEED } if (genPortOne) {obj = {w: W_SPEED}} } return obj } // 云台参数处理,最大20° function ptzKeyHandle() { let ratio = (Date.now()-downTime) / 4000 if (ratio > 1) ratio = 1; if (ratio < 0.1) ratio = 0.1; return 20 * ratio } // 变焦倍数处理,最大5倍 function getZoomFactor() { let ratio = (Date.now()-downTime) / 4000 if (ratio > 1) ratio = 1; if (ratio < 0.1) ratio = 0.2; return 5 * ratio } // 处理无人机控制指令的发布逻辑 function handlePublish(params) { const body = { method: genPortOne ? DRC_METHOD.DRONE_CONTROL : DRC_METHOD.DRONE_CONTROL2, data: params, } handleClearInterval() myInterval = setInterval(() => { body.data.seq = seq++ seq++ // q,e额外处理 if (['KeyQ', 'KeyE'].includes(activeCodeKey)){ body.data = qKeyEKeyHandle() } window.console.log('keyCode>>>>', activeCodeKey, body) mqttHooks?.publishMqtt(deviceTopicInfo.pubTopic, body, { qos: 0 }) }, 50) } let downKeyCode // 案件按下逻辑 function handleKeyup(keyCode) { console.log(keyCode,'keyCodekeyCode') const droneControl = [3, 16, 17].includes(modelCode.value) if ( !['KeyJ', 'KeyK', 'KeyI', 'KeyO', 'ArrowUp', 'ArrowRight', 'ArrowDown', 'ArrowLeft',].includes(keyCode) && !droneControl ) { return } if (downKeyCode !== keyCode){ downKeyCode = keyCode downTime = Date.now() } const {droneSn,speed} = paramsRef.value genPortOne = droneSn === '1581F5BMD22CK0014H2U' || droneSn === 'BA0BA1C3D38157A49E1B16574FA474F7'; const exactMapping = [0,3,5,6,7,8,9,10,11,12,12,13,14,14,15,15] const SPEED = genPortOne ? speed : (exactMapping[speed] * 44) const HEIGHT = genPortOne ? 5 : 500; // check // 机头角速度 一代-90, 90,二三代 -600,600 const W_SPEED = genPortOne ? 90 : 600 let arrList = [] if (genPortOne) { arrList = [ { Key: 'KeyQ', category: 'w', value: -W_SPEED },{ Key: 'KeyW',category: 'x', value: SPEED }, { Key: 'KeyE', category: 'w', value: W_SPEED},{ Key: 'KeyA', category: 'y', value: -SPEED}, { Key: 'KeyS', category: 'x', value: -SPEED},{ Key: 'KeyD', category: 'y', value: SPEED} ] } else { arrList = [ { Key: 'KeyQ', category: 'yaw', value: 1024-W_SPEED },{ Key: 'KeyW',category: 'pitch', value: 1024+SPEED }, { Key: 'KeyE', category: 'yaw', value: 1024+W_SPEED},{ Key: 'KeyA', category: 'roll', value: 1024-SPEED}, { Key: 'KeyS', category: 'pitch', value: 1024-SPEED},{ Key: 'KeyD', category: 'roll', value: 1024+SPEED} ] } let resultObj = [] let resultArr = [] // 遍历被选中得数组 if (keyCode === 'assemblyKeys') { keysPressed.map(key => { if (key.value) { let result = arrList.filter(item =>item.Key===key.key) resultObj.push(result[0]) } }) // 相同属性值进行计算 resultArr = resultObj.reduce((acc, item) => { // 如果累加器中已经有这个 category,则累加 value if (acc[item.category]) { // acc[item.category] += item.value; acc[item.category] = genPortOne ? 0 : 1024; } else { // 否则,初始化这个 category 的 value acc[item.category] = item.value; } return acc; }, {}); } seq = 0 switch (keyCode) { case 'assemblyKeys': // 针对Q W E A S D 组合键 if (activeCodeKey === keyCode) return handlePublish(resultArr) activeCodeKey = keyCode break case 'KeyQ': if (activeCodeKey === keyCode) return console.log(88888888888888) let objQ = { yaw: 1024-W_SPEED } if (genPortOne) {objQ = {w: -W_SPEED}} handlePublish(objQ) activeCodeKey = keyCode break case 'KeyW': if (activeCodeKey === keyCode) return let objW = { pitch: 1024+SPEED } if (genPortOne) {objW = {x: SPEED}} handlePublish(objW) activeCodeKey = keyCode break case 'KeyE': if (activeCodeKey === keyCode) return let objE = { yaw: 1024+W_SPEED } if (genPortOne) {objE = {w: W_SPEED}} handlePublish(objE) activeCodeKey = keyCode break case 'KeyA': if (activeCodeKey === keyCode) return let objA = { roll: 1024-SPEED } if (genPortOne) {objA = {y: -SPEED}} handlePublish(objA) activeCodeKey = keyCode break case 'KeyS': if (activeCodeKey === keyCode) return let objS = { pitch: 1024-SPEED } if (genPortOne) {objS = {x: -SPEED}} handlePublish(objS) activeCodeKey = keyCode break case 'KeyD': if (activeCodeKey === keyCode) return let objD = { roll: 1024+SPEED } if (genPortOne) {objD = {y: SPEED}} handlePublish(objD) activeCodeKey = keyCode break case 'KeyZ': if (activeCodeKey === keyCode) return let objZ = { throttle: 1024-HEIGHT } if (genPortOne) {objZ = {h: -HEIGHT}} handlePublish(objZ) activeCodeKey = keyCode break case 'KeyC': if (activeCodeKey === keyCode) return let objC = { throttle: 1024+HEIGHT } if (genPortOne) {objC = {h: HEIGHT}} handlePublish(objC) activeCodeKey = keyCode break case 'NumpadAdd': if (activeCodeKey === keyCode) return EventBus.emit('controlPanel-editSpeed',1) activeCodeKey = keyCode break case 'NumpadSubtract': if (activeCodeKey === keyCode) return EventBus.emit('controlPanel-editSpeed',-1) activeCodeKey = keyCode break case 'ArrowUp': if (activeCodeKey === keyCode) return ptzControlInterval('up') activeCodeKey = keyCode break case 'ArrowDown': if (activeCodeKey === keyCode) return ptzControlInterval('down') activeCodeKey = keyCode break case 'ArrowLeft': if (activeCodeKey === keyCode) return ptzControlInterval('left') activeCodeKey = keyCode break case 'ArrowRight': if (activeCodeKey === keyCode) return ptzControlInterval('right') activeCodeKey = keyCode break case 'KeyJ': //拍照 if (activeCodeKey === keyCode) return EventBus.emit('TaskDetailsLeft-takePictures') activeCodeKey = keyCode break case 'KeyK'://录像 if (activeCodeKey === keyCode) return EventBus.emit('TaskDetailsLeft-recordFun') activeCodeKey = keyCode break case 'KeyI': //放大变焦 if (activeCodeKey === keyCode) return zoomFactorChange(1) activeCodeKey = keyCode break case 'KeyO': //缩小变焦 if (activeCodeKey === keyCode) return zoomFactorChange(0) activeCodeKey = keyCode break case 'KeyX': //悬停 break case 'KeyB': // 文字转广播 if (!isManualControl.value) { return ElMessage.warning('请先接管!') } if (activeCodeKey === keyCode) return EventBus.emit('TaskDetailsLeft-txtShoutList', 'keyB') activeCodeKey = keyCode break case 'KeyN': // 喊话 if (!isManualControl.value) { return ElMessage.warning('请先接管!') } if (activeCodeKey === keyCode) return EventBus.emit('TaskDetailsLeft-shoutList', 'videoNKey') activeCodeKey = keyCode break case 'KeyM': //广播 if (!isManualControl.value) { return ElMessage.warning('请先接管!') } if (activeCodeKey === keyCode) return EventBus.emit('TaskDetailsLeft-broadcastList', 'keyM') activeCodeKey = keyCode break default: break } } function ptzControl(key) { let pitchSpeed = ptzKeyHandle() const {dockSn} = paramsRef.value if (key === 'down' || key === 'left'){ pitchSpeed = -pitchSpeed } ptzControlApi(key, { sn: dockSn,pitchSpeed }) } // 云台控制上下左右 function ptzControlInterval(key){ handleClearInterval() ptzControl(key) myInterval = setInterval(()=>ptzControl(key), 200) } // 按键变焦 const zoomFactorControl = _.throttle((amplify)=>{ let zoom = getZoomFactor() zoom = amplify ? zoom : (zoom * -1) EventBus.emit('TaskDetailsLeft-quickZoomIn', zoom) },1000) function zoomFactorChange(amplify) { handleClearInterval() zoomFactorControl(amplify) myInterval = setInterval(()=>zoomFactorControl(amplify), 1000) } function handleClearInterval() { clearInterval(myInterval) myInterval = undefined } // 重置所有控制状态 function resetControlState() { downTime = null downKeyCode = null keysPressed.map(item => (item.value = false)) activeCodeKey = null seq = 0 handleClearInterval() } // 按键弹起 function onKeyup(e) { if (store?.state?.task?.keysDisabled) return keysPressed.forEach(item => { if (e.code === item.key) item.value = false }) const keyList = keysPressed.filter(item => item.value === true); if (keyList.length === 1) { handleKeyup(keyList[0].key); } else { resetControlState(); } activeBtnList.value = keyList.map(i => i.key) } let timedReset = _.debounce(resetControlState,2000) // 按键按下 function onKeydown(e) { if (store?.state?.task?.keysDisabled) return e.preventDefault() keysPressed.forEach(item => { if(e.code === item.key) item.value = true }) let result = keysPressed.filter(item=>item.value===true) if (result && result.length >= 2) { handleKeyup('assemblyKeys') } else { handleKeyup(e.code) } // 保底措施,避免长时间不操作导致控制状态不重置 timedReset() activeBtnList.value = result.map(i => i.key) } // 紧急停止 function handleEmergencyStop() { resetControlState() if (!deviceTopicInfo.pubTopic) { ElMessage.error('请确保已经建立DRC链路') return } const body = { method: DRC_METHOD.DRONE_EMERGENCY_STOP, data: {}, } window.console.log('handleEmergencyStop>>>>', deviceTopicInfo.pubTopic, body) mqttHooks?.publishMqtt(deviceTopicInfo.pubTopic, body, { qos: 1 }) } function openKeyMonitor() { removeKeyMonitor() console.log('开启键盘监听事件') window.addEventListener('keydown', onKeydown) window.addEventListener('keyup', onKeyup) } function removeKeyMonitor() { resetControlState() console.log('关闭键盘监听事件') window.removeEventListener('keydown', onKeydown) window.removeEventListener('keyup', onKeyup) } return { activeCodeKey, handleKeyup, handleEmergencyStop, resetControlState, openKeyMonitor, removeKeyMonitor, } }