mirror of https://github.com/jetkvm/kvm.git
				
				
				
			Fix ghost keys issue, properly implemented modifer mapping
This commit is contained in:
		
							parent
							
								
									f1de6639ef
								
							
						
					
					
						commit
						8732a6aff8
					
				|  | @ -23,7 +23,7 @@ export default function WebRTCVideo() { | ||||||
|   const [modifiers, setModifiers] = useState(useKeyboardMappingsStore.modifiers); |   const [modifiers, setModifiers] = useState(useKeyboardMappingsStore.modifiers); | ||||||
| 
 | 
 | ||||||
|   // This map is used to maintain consistency between localised key mappings
 |   // This map is used to maintain consistency between localised key mappings
 | ||||||
|   const activeKeyState = useRef<Map<string, { mappedKey: string; modifiers: { shift: boolean, altLeft?: boolean, altRight?: boolean, bitmask: number }; }>>(new Map()); |   const activeKeyState = useRef<Map<string, { mappedKey: string; modifiers: { shift: boolean, altLeft?: boolean, altRight?: boolean}; }>>(new Map()); | ||||||
| 
 | 
 | ||||||
|   useEffect(() => { |   useEffect(() => { | ||||||
|     const unsubscribeKeyboardStore = useKeyboardMappingsStore.subscribe(() => { |     const unsubscribeKeyboardStore = useKeyboardMappingsStore.subscribe(() => { | ||||||
|  | @ -170,14 +170,16 @@ export default function WebRTCVideo() { | ||||||
|     sendMouseMovement(0, 0, 0); |     sendMouseMovement(0, 0, 0); | ||||||
|   }, [sendMouseMovement]); |   }, [sendMouseMovement]); | ||||||
| 
 | 
 | ||||||
|   // TODO this needs reworked ot work with mappings.
 |   // TODO this needs reworked ot work with mappings
 | ||||||
|   // Keyboard-related
 |   // Keyboard-related
 | ||||||
|   const handleModifierKeys = useCallback( |   const handleModifierKeys = useCallback( | ||||||
|     (e: KeyboardEvent, activeModifiers: number[]) => { |     (e: KeyboardEvent, activeModifiers: number[], mappedKeyModifers: { shift: boolean; altLeft: boolean; altRight: boolean; }) => { | ||||||
|       const { shiftKey, ctrlKey, altKey, metaKey } = e; |       const { shiftKey, ctrlKey, altKey, metaKey } = e; | ||||||
| 
 | 
 | ||||||
|       const filteredModifiers = activeModifiers.filter(Boolean); |       // TODO remove debug logging
 | ||||||
|  |       console.log(shiftKey + " " +ctrlKey + " " +altKey + " " +metaKey + " " +mappedKeyModifers.shift + " "+mappedKeyModifers.altLeft + " "+mappedKeyModifers.altRight + " ") | ||||||
| 
 | 
 | ||||||
|  |       const filteredModifiers = activeModifiers.filter(Boolean);3 | ||||||
|       // Example: activeModifiers = [0x01, 0x02, 0x04, 0x08]
 |       // Example: activeModifiers = [0x01, 0x02, 0x04, 0x08]
 | ||||||
|       // Assuming 0x01 = ControlLeft, 0x02 = ShiftLeft, 0x04 = AltLeft, 0x08 = MetaLeft
 |       // Assuming 0x01 = ControlLeft, 0x02 = ShiftLeft, 0x04 = AltLeft, 0x08 = MetaLeft
 | ||||||
|       return ( |       return ( | ||||||
|  | @ -188,6 +190,7 @@ export default function WebRTCVideo() { | ||||||
|           .filter( |           .filter( | ||||||
|             modifier => |             modifier => | ||||||
|               shiftKey || |               shiftKey || | ||||||
|  |               mappedKeyModifers.shift || | ||||||
|               (modifier !== modifiers["ShiftLeft"] && |               (modifier !== modifiers["ShiftLeft"] && | ||||||
|                 modifier !== modifiers["ShiftRight"]), |                 modifier !== modifiers["ShiftRight"]), | ||||||
|           ) |           ) | ||||||
|  | @ -206,6 +209,8 @@ export default function WebRTCVideo() { | ||||||
|           .filter( |           .filter( | ||||||
|             modifier => |             modifier => | ||||||
|               altKey || |               altKey || | ||||||
|  |               mappedKeyModifers.altLeft || | ||||||
|  |               mappedKeyModifers.altRight || | ||||||
|               (modifier !== modifiers["AltLeft"] && modifier !== modifiers["AltRight"]), |               (modifier !== modifiers["AltLeft"] && modifier !== modifiers["AltRight"]), | ||||||
|           ) |           ) | ||||||
|           // Meta: Keep if Meta is pressed or if the key isn't a Meta key
 |           // Meta: Keep if Meta is pressed or if the key isn't a Meta key
 | ||||||
|  | @ -247,40 +252,38 @@ export default function WebRTCVideo() { | ||||||
|         code = "IntlBackslash"; |         code = "IntlBackslash"; | ||||||
|       }*/ |       }*/ | ||||||
| 
 | 
 | ||||||
|       const { key: mappedKey, shift, altLeft, altRight } = useKeyboardMappingsStore.chars[localisedKey] ?? { key: e.code }; |       const { key: mappedKey, shift, altLeft, altRight } = chars[localisedKey] ?? { key: code }; | ||||||
|       //if (!key) continue; 
 |       //if (!key) continue; 
 | ||||||
|       console.log("Mapped Key: " + mappedKey) |       console.log("Mapped Key: " + mappedKey) | ||||||
|       console.log("Current KB Layout:" + useKeyboardMappingsStore.getLayout()); |       console.log("Current KB Layout:" + useKeyboardMappingsStore.getLayout()); | ||||||
|       console.log(chars[localisedKey]); |       console.log(chars[localisedKey]); | ||||||
| 
 | 
 | ||||||
|       // Build the modifier bitmask
 |  | ||||||
|       const modifierBitmask = |  | ||||||
|       (shift ? modifiers["ShiftLeft"] : 0) | |  | ||||||
|       (altLeft ? modifiers["AltLeft"] : 0) | |  | ||||||
|       (altRight ? modifiers["AltRight"] : 0); // This is important for a lot of keyboard layouts, right and left alt have different functions
 |  | ||||||
|                                               // On second thought this may not be relevant here, may be best to just send altRight through, needs testing
 |  | ||||||
|       console.log("Modifier Bitmask: " + modifierBitmask) |  | ||||||
|       console.log("Shift: " + shift + ", altLeft: " + altLeft + ", altRight: " + altRight) |       console.log("Shift: " + shift + ", altLeft: " + altLeft + ", altRight: " + altRight) | ||||||
|        |        | ||||||
|       // Add the mapped key to keyState
 |       // Add the mapped key to keyState
 | ||||||
|       activeKeyState.current.set(e.code, { mappedKey, modifiers: {shift, altLeft, altRight, bitmask: modifierBitmask}}); |       activeKeyState.current.set(e.code, { mappedKey, modifiers: {shift, altLeft, altRight}}); | ||||||
|       console.log(activeKeyState) |       console.log(activeKeyState) | ||||||
| 
 | 
 | ||||||
|       // Add the key to the active keys
 |       // Add the key to the active keys
 | ||||||
|       const newKeys = [...prev.activeKeys, keys[mappedKey]].filter(Boolean); |       const newKeys = [...prev.activeKeys, keys[mappedKey]].filter(Boolean); | ||||||
| 
 | 
 | ||||||
|  |       // TODO I feel this may not be applying the modifiers correctly, specifically altRight  
 | ||||||
|       // Add the modifier to the active modifiers
 |       // Add the modifier to the active modifiers
 | ||||||
|       const newModifiers = handleModifierKeys(e, [ |       const newModifiers = handleModifierKeys(e, [ | ||||||
|         ...prev.activeModifiers, |         ...prev.activeModifiers, | ||||||
|         modifiers[code], |         modifiers[code], | ||||||
|         modifierBitmask, //Is this bad, will we have duplicate modifiers?
 |         (shift? modifiers['ShiftLeft'] : 0), | ||||||
|       ]); |         (altLeft? modifiers['AltLeft'] : 0), | ||||||
|  |         (altRight? modifiers['AltRight'] : 0),], | ||||||
|  |         {shift: shift, altLeft: altLeft? true : false, altRight: altRight ? true : false} | ||||||
|  |       ); | ||||||
| 
 | 
 | ||||||
|       // When pressing the meta key + another key, the key will never trigger a keyup
 |       // When pressing the meta key + another key, the key will never trigger a keyup
 | ||||||
|       // event, so we need to clear the keys after a short delay
 |       // event, so we need to clear the keys after a short delay
 | ||||||
|       // https://bugs.chromium.org/p/chromium/issues/detail?id=28089
 |       // https://bugs.chromium.org/p/chromium/issues/detail?id=28089
 | ||||||
|       // https://bugzilla.mozilla.org/show_bug.cgi?id=1299553
 |       // https://bugzilla.mozilla.org/show_bug.cgi?id=1299553
 | ||||||
|       // TODO add this to the activekey state
 |       // TODO add this to the activekey state
 | ||||||
|  |       // TODO set this to remove from activekeystate as well
 | ||||||
|       if (e.metaKey) { |       if (e.metaKey) { | ||||||
|         setTimeout(() => { |         setTimeout(() => { | ||||||
|           const prev = useHidStore.getState(); |           const prev = useHidStore.getState(); | ||||||
|  | @ -305,6 +308,7 @@ export default function WebRTCVideo() { | ||||||
|   const keyUpHandler = useCallback( |   const keyUpHandler = useCallback( | ||||||
|     (e: KeyboardEvent) => { |     (e: KeyboardEvent) => { | ||||||
|       e.preventDefault(); |       e.preventDefault(); | ||||||
|  |       console.log(e) | ||||||
|       const prev = useHidStore.getState(); |       const prev = useHidStore.getState(); | ||||||
| 
 | 
 | ||||||
|       // if (document.activeElement?.id !== "videoFocusTrap") {
 |       // if (document.activeElement?.id !== "videoFocusTrap") {
 | ||||||
|  | @ -321,12 +325,15 @@ export default function WebRTCVideo() { | ||||||
|       e.code === "ShiftLeft" || |       e.code === "ShiftLeft" || | ||||||
|       e.code === "ShiftRight" || |       e.code === "ShiftRight" || | ||||||
|       e.code === "AltLeft" || |       e.code === "AltLeft" || | ||||||
|       e.code === "AltRight"; |       e.code === "AltRight" || | ||||||
|       //e.code === "ControlLeft" || These shouldn't make a difference for mappings
 |       e.code === "ControlLeft" || | ||||||
|       //e.code === "ControlRight";
 |       e.code === "ControlRight"; | ||||||
|  | 
 | ||||||
|  |       var newKeys = prev.activeKeys; | ||||||
| 
 | 
 | ||||||
|       // Handle modifier release
 |       // Handle modifier release
 | ||||||
|       if (isModifierKey) { |       if (isModifierKey) { | ||||||
|  |         console.log("ITS A MODIFER") | ||||||
|         // Update all affected keys when this modifier is released
 |         // Update all affected keys when this modifier is released
 | ||||||
|         activeKeyState.current.forEach((value, code) => { |         activeKeyState.current.forEach((value, code) => { | ||||||
|           const { mappedKey, modifiers: mappedModifiers} = value; |           const { mappedKey, modifiers: mappedModifiers} = value; | ||||||
|  | @ -355,16 +362,21 @@ export default function WebRTCVideo() { | ||||||
|             removeCurrentKey = true; |             removeCurrentKey = true; | ||||||
|           }; |           }; | ||||||
| 
 | 
 | ||||||
|           var newKeys = prev.activeKeys; |  | ||||||
| 
 |  | ||||||
|           if (removeCurrentKey) { |           if (removeCurrentKey) { | ||||||
|             newKeys = prev.activeKeys |             newKeys = newKeys | ||||||
|             .filter(k => k !== keys[mappedKey]) // Remove the previously mapped key
 |             .filter(k => k !== keys[mappedKey]) // Remove the previously mapped key
 | ||||||
|             //.concat(keys[updatedMappedKey]) // Add the new remapped key, don't need to do this.
 |             //.concat(keys[updatedMappedKey]) // Add the new remapped key, don't need to do this.
 | ||||||
|             .filter(Boolean); |             .filter(Boolean); | ||||||
|           }; |           }; | ||||||
| 
 |         }); | ||||||
|           const newModifiers = prev.activeModifiers.filter(k => k !== modifiers[e.code]); |         console.log("prev.activemodifers: " + prev.activeModifiers) | ||||||
|  |         console.log("prev.activemodifers.filtered: " + prev.activeModifiers.filter(k => k !== modifiers[e.code])) | ||||||
|  |         const newModifiers = handleModifierKeys( | ||||||
|  |           e, | ||||||
|  |           prev.activeModifiers.filter(k => k !== modifiers[e.code]), | ||||||
|  |           {shift: false, altLeft: false, altRight: false} | ||||||
|  |         ); | ||||||
|  |           console.log("New modifiers in keyup: " + newModifiers) | ||||||
| 
 | 
 | ||||||
|           // Update the keyState
 |           // Update the keyState
 | ||||||
|           /*activeKeyState.current.delete(code);/*.set(code, { |           /*activeKeyState.current.delete(code);/*.set(code, { | ||||||
|  | @ -376,9 +388,14 @@ export default function WebRTCVideo() { | ||||||
|           // Remove the modifer key from keyState
 |           // Remove the modifer key from keyState
 | ||||||
|           activeKeyState.current.delete(e.code); |           activeKeyState.current.delete(e.code); | ||||||
| 
 | 
 | ||||||
|  |           // This is required to filter out the alt keys as well as the modifier.
 | ||||||
|  |           newKeys = newKeys | ||||||
|  |             .filter(k => k !== keys[e.code]) // Remove the previously mapped key
 | ||||||
|  |             //.concat(keys[updatedMappedKey]) // Add the new remapped key, don't need to do this.
 | ||||||
|  |             .filter(Boolean); | ||||||
|  | 
 | ||||||
|           // Send the updated HID payload
 |           // Send the updated HID payload
 | ||||||
|           sendKeyboardEvent([...new Set(newKeys)], [...new Set(newModifiers)]); |           sendKeyboardEvent([...new Set(newKeys)], [...new Set(newModifiers)]); | ||||||
|         }); |  | ||||||
| 
 | 
 | ||||||
|         return; // Exit as we've already handled the modifier release
 |         return; // Exit as we've already handled the modifier release
 | ||||||
|       } |       } | ||||||
|  | @ -393,14 +410,20 @@ export default function WebRTCVideo() { | ||||||
|       activeKeyState.current.delete(e.code); |       activeKeyState.current.delete(e.code); | ||||||
| 
 | 
 | ||||||
|       // Filter out the key that was just released
 |       // Filter out the key that was just released
 | ||||||
|       const newKeys = prev.activeKeys.filter(k => k !== keys[mappedKey]).filter(Boolean); |       newKeys = newKeys.filter(k => k !== keys[mappedKey]).filter(Boolean); | ||||||
|       console.log(activeKeyState) |       console.log(activeKeyState) | ||||||
| 
 | 
 | ||||||
|       // Filter out the associated modifier
 |       // Filter out the associated modifier
 | ||||||
|       //const newModifiers = prev.activeModifiers.filter(k => k !== modifier).filter(Boolean);
 |       //const newModifiers = prev.activeModifiers.filter(k => k !== modifier).filter(Boolean);
 | ||||||
|       const newModifiers = handleModifierKeys( |       const newModifiers = handleModifierKeys( | ||||||
|         e, |         e, | ||||||
|         prev.activeModifiers.filter(k => k !== modifier.bitmask), |         prev.activeModifiers.filter(k => { | ||||||
|  |           if (modifier.shift && k == modifiers["ShiftLeft"]) return false; | ||||||
|  |           if (modifier.altLeft && k == modifiers["AltLeft"]) return false; | ||||||
|  |           if (modifier.altRight && k == modifiers["AltRight"]) return false; | ||||||
|  |           return true; | ||||||
|  |         }), | ||||||
|  |         {shift: modifier.shift, altLeft: modifier.altLeft? true : false, altRight: modifier.altRight ? true : false} | ||||||
|       ); |       ); | ||||||
|     /* |     /* | ||||||
|       const { key: mappedKey/*, shift, altLeft, altRight*//* } = chars[e.key] ?? { key: e.code }; |       const { key: mappedKey/*, shift, altLeft, altRight*//* } = chars[e.key] ?? { key: e.code }; | ||||||
|  |  | ||||||
|  | @ -387,6 +387,8 @@ export const useHidStore = create<HidState>(set => ({ | ||||||
|   activeKeys: [], |   activeKeys: [], | ||||||
|   activeModifiers: [], |   activeModifiers: [], | ||||||
|   updateActiveKeysAndModifiers: ({ keys, modifiers }) => { |   updateActiveKeysAndModifiers: ({ keys, modifiers }) => { | ||||||
|  |     // TODO remove debug logs
 | ||||||
|  |     console.log("keys: " + keys + "modifiers: " + modifiers) | ||||||
|     return set({ activeKeys: keys, activeModifiers: modifiers }); |     return set({ activeKeys: keys, activeModifiers: modifiers }); | ||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue