Пример #1
0
        private void SetFilterState(bool state)
        {
            ManagedWrapper.SetFilter(_deviceContext, IsMonitoredDevice,
                                     state ? ManagedWrapper.Filter.All : ManagedWrapper.Filter.None);

            _filterState = state;
        }
Пример #2
0
        private void PollThread()
        {
            var stroke = new ManagedWrapper.Stroke();

            while (true)
            {
                for (var i = 1; i < 11; i++)
                {
                    while (ManagedWrapper.Receive(_deviceContext, i, ref stroke, 1) > 0)
                    {
                        ManagedWrapper.Send(_deviceContext, i, ref stroke, 1);
                        FireKeyboardCallback(i, stroke);
                    }
                }

                for (var i = 11; i < 21; i++)
                {
                    while (ManagedWrapper.Receive(_deviceContext, i, ref stroke, 1) > 0)
                    {
                        ManagedWrapper.Send(_deviceContext, i, ref stroke, 1);
                        FireMouseCallback(i, stroke);
                    }
                }
                Thread.Sleep(10);
            }
        }
Пример #3
0
        /// <summary>
        ///     Sends Mouse button events
        /// </summary>
        /// <param name="id"></param>
        /// <param name="btn"></param>
        /// <param name="state"></param>
        /// <returns></returns>
        public void SendMouseButtonEvent(int id, int btn, int state)
        {
            HelperFunctions.IsValidDeviceId(true, id);

            var stroke = HelperFunctions.MouseButtonAndStateToStroke(btn, state);

            ManagedWrapper.Send(_deviceContext, id, ref stroke, 1);
        }
Пример #4
0
 public Manager()
 {
     _deviceContext = ManagedWrapper.CreateContext();
     _timer         = new MultimediaTimer()
     {
         Interval = _pollRate
     };
     _timer.Elapsed += DoPoll;
 }
Пример #5
0
        /// <summary>
        ///     Same as <see cref="SendMouseButtonEvent" />, but sends button events in Absolute mode (with coordinates)
        /// </summary>
        /// <param name="id"></param>
        /// <param name="btn"></param>
        /// <param name="state"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        public void SendMouseButtonEventAbsolute(int id, int btn, int state, int x, int y)
        {
            var stroke = HelperFunctions.MouseButtonAndStateToStroke(btn, state);

            stroke.mouse.x     = x;
            stroke.mouse.y     = y;
            stroke.mouse.flags = (ushort)ManagedWrapper.MouseFlag.MouseMoveAbsolute;
            ManagedWrapper.Send(_deviceContext, id, ref stroke, 1);
        }
Пример #6
0
        /// <summary>
        /// Sends Absolute  Mouse Movement
        /// Note: Newing up a stroke seems to make Absolute input be relative to main monitor
        /// Calling Send on an actual stroke from an Absolute device results in input relative to all monitors
        /// </summary>
        /// <param name="id"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public void SendMouseMoveAbsolute(int id, int x, int y)
        {
            IsValidDeviceId(true, id);

            var stroke = new ManagedWrapper.Stroke {
                mouse = { x = x, y = y, flags = (ushort)ManagedWrapper.MouseFlag.MouseMoveAbsolute }
            };

            ManagedWrapper.Send(_deviceContext, id, ref stroke, 1);
        }
Пример #7
0
        /// <summary>
        ///     Sends Relative Mouse Movement
        /// </summary>
        /// <param name="id"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public void SendMouseMoveRelative(int id, int x, int y)
        {
            HelperFunctions.IsValidDeviceId(true, id);

            var stroke = new ManagedWrapper.Stroke
            {
                mouse = { x = x, y = y, flags = (ushort)ManagedWrapper.MouseFlag.MouseMoveRelative }
            };

            ManagedWrapper.Send(_deviceContext, id, ref stroke, 1);
        }
Пример #8
0
        /// <summary>
        /// Sends a keyboard key event
        /// </summary>
        /// <param name="id">The ID of the Keyboard to send as</param>
        /// <param name="code">The ScanCode to send</param>
        /// <param name="state">The State to send (1 = pressed, 0 = released)</param>
        public void SendKeyEvent(int id, ushort code, int state)
        {
            IsValidDeviceId(false, id);
            var st     = 1 - state;
            var stroke = new ManagedWrapper.Stroke();

            if (code > 255)
            {
                code -= 256;
                st   += 2;
            }
            stroke.key.code  = code;
            stroke.key.state = (ushort)st;
            ManagedWrapper.Send(_deviceContext, id, ref stroke, 1);
        }
Пример #9
0
        public void Subscribe(int vid, int pid, dynamic callback)
        {
            _callback       = callback;
            _filteredDevice = HelperFunctions.GetDeviceId(_deviceContext, false, vid, pid, 1);
            if (_filteredDevice == 0)
            {
                throw new Exception($"Could not find device with VID {vid}, PID {pid}");
            }

            ManagedWrapper.SetFilter(_deviceContext, IsMonitoredDevice, ManagedWrapper.Filter.All);
            _timer = new MultimediaTimer()
            {
                Interval = 10
            };
            _timer.Elapsed += DoPoll;
            _timer.Start();
        }
Пример #10
0
        public void DoPoll(object sender, EventArgs e)
        {
            var stroke    = new ManagedWrapper.Stroke();
            var keyEvents = new List <KeyEvent>();

            while (ManagedWrapper.Receive(_deviceContext, _filteredDevice, ref stroke, 1) > 0)
            {
                keyEvents.Add(new KeyEvent {
                    Code = stroke.key.code, State = stroke.key.state
                });
                ManagedWrapper.Send(_deviceContext, _filteredDevice, ref stroke, 1);
            }

            if (keyEvents.Count > 0)
            {
                _callback(keyEvents.ToArray());
            }
        }
Пример #11
0
        /// <summary>
        ///     Sends a keyboard key event
        /// </summary>
        /// <param name="id">The ID of the Keyboard to send as</param>
        /// <param name="code">The ScanCode to send</param>
        /// <param name="state">The State to send (1 = pressed, 0 = released)</param>
        public void SendKeyEvent(int id, ushort code, int state)
        {
            HelperFunctions.IsValidDeviceId(false, id);
            var st     = 1 - state;
            var stroke = new ManagedWrapper.Stroke();

            if (code > 255)
            {
                code -= 256;
                if (code != 54) // RShift has > 256 code, but state is 0/1
                {
                    st += 2;
                }
            }

            stroke.key.code  = code;
            stroke.key.state = (ushort)st;
            ManagedWrapper.Send(_deviceContext, id, ref stroke, 1);
        }
Пример #12
0
        private void PollThread()
        {
            ManagedWrapper.SetFilter(_deviceContext, IsMonitoredDevice, ManagedWrapper.Filter.All);
            int deviceId1;
            int deviceId2;
            var stroke1 = new ManagedWrapper.Stroke();
            var stroke2 = new ManagedWrapper.Stroke();

            while (true)
            {
                var strokes = new List <ManagedWrapper.Stroke>();
                if (ManagedWrapper.Receive(_deviceContext, deviceId1 = ManagedWrapper.WaitWithTimeout(_deviceContext, 10), ref stroke1, 1) > 0)
                {
                    strokes.Add(stroke1);
                    if (deviceId1 < 11)
                    {
                        if (ManagedWrapper.Receive(_deviceContext, deviceId2 = ManagedWrapper.WaitWithTimeout(_deviceContext, 0), ref stroke2, 1) > 0)
                        {
                            strokes.Add(stroke2);
                        }
                    }
                    if (!_block)
                    {
                        for (int i = 0; i < strokes.Count; i++)
                        {
                            var stroke = strokes[i];
                            ManagedWrapper.Send(_deviceContext, _deviceId, ref stroke, 1);
                        }
                    }
                    // Use array for callback, as the callback may be AHK code, and dealing with arrays in AHK is way simpler that Lists
                    var keyEvents = new KeyEvent[strokes.Count];
                    for (int i = 0; i < strokes.Count; i++)
                    {
                        var s = strokes[i];
                        keyEvents[i] = new KeyEvent {
                            Code = s.key.code, State = s.key.state
                        };
                    }
                    _callback(keyEvents);
                }
            }
        }
Пример #13
0
        /// <summary>
        /// Tries to get Device ID from Hardware String
        /// </summary>
        /// <param name="isMouse">Whether the device is a mouse or a keyboard</param>
        /// <param name="handle">The Hardware String (handle) of the device</param>
        /// <param name="instance">The instance of the VID/PID (Optional)</param>
        /// <returns></returns>
        public int GetDeviceIdFromHandle(bool isMouse, string handle, int instance = 1)
        {
            var start = isMouse ? 11 : 0;
            var max   = isMouse ? 21 : 11;

            for (var i = start; i < max; i++)
            {
                var hardwareStr = ManagedWrapper.GetHardwareStr(_deviceContext, i, 1000);
                if (hardwareStr != handle)
                {
                    continue;
                }

                if (instance == 1)
                {
                    return(i);
                }
                instance--;
            }

            //ToDo: Should throw here?
            return(0);
        }
Пример #14
0
        /// <summary>
        /// Tries to get Device ID from VID/PID
        /// </summary>
        /// <param name="isMouse">Whether the device is a mouse or a keyboard</param>
        /// <param name="vid">The VID of the device</param>
        /// <param name="pid">The PID of the device</param>
        /// <param name="instance">The instance of the VID/PID (Optional)</param>
        /// <returns></returns>
        public int GetDeviceId(bool isMouse, int vid, int pid, int instance = 1)
        {
            var start = isMouse ? 11 : 0;
            var max   = isMouse ? 21 : 11;

            for (var i = start; i < max; i++)
            {
                var hardwareStr = ManagedWrapper.GetHardwareStr(_deviceContext, i, 1000);
                int foundVid = 0, foundPid = 0;
                GetVidPid(hardwareStr, ref foundVid, ref foundPid);
                if (foundVid != vid || foundPid != pid)
                {
                    continue;
                }
                if (instance == 1)
                {
                    return(i);
                }
                instance--;
            }

            //ToDo: Should throw here?
            return(0);
        }
Пример #15
0
 public Manager()
 {
     _deviceContext = ManagedWrapper.CreateContext();
 }
Пример #16
0
 public ScanCodeChecker()
 {
     _deviceContext = ManagedWrapper.CreateContext();
 }
Пример #17
0
        // ScanCode notes: https://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html
        private void PollThread()
        {
            var stroke = new ManagedWrapper.Stroke();

            while (_pollThreadRunning)
            {
                // Iterate through all Keyboards
                for (var i = 1; i < 11; i++)
                {
                    var isMonitoredKeyboard = IsMonitoredDevice(i) == 1;
                    var hasSubscription     = false;
                    var hasContext          = _contextCallbacks.ContainsKey(i);

                    // Process any waiting input for this keyboard
                    while (ManagedWrapper.Receive(_deviceContext, i, ref stroke, 1) > 0)
                    {
                        var block = false;
                        // If this is not a monitored keyboard, skip.
                        // This check should not really be needed as the IsMonitoredDevice() predicate should only match monitored keyboards...
                        // ... but in case it does, we want to ignore this bit and pass the input through
                        if (isMonitoredKeyboard && _keyboardMappings.ContainsKey(i))
                        {
                            // Process Subscription Mode

                            #region KeyCode, State, Extended Flag translation

                            // Begin translation of incoming key code, state, extended flag etc...
                            var processMappings = true;
                            var processedState  = KeyboardStrokeToKeyboardState(stroke);

                            #endregion

                            if (processedState.Ignore)
                            {
                                // Set flag to stop Context Mode from firing
                                hasSubscription = true;
                                // Set flag to indicate disable mapping processing
                                processMappings = false;
                            }

                            var code  = processedState.Code;
                            var state = processedState.State;

                            // Code and state now normalized, proceed with checking for subscriptions...
                            if (processMappings && _keyboardMappings[i].ContainsKey(code))
                            {
                                hasSubscription = true;
                                var mapping = _keyboardMappings[i][code];
                                if (mapping.Block)
                                {
                                    block = true;
                                }
                                if (mapping.Concurrent)
                                {
                                    ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(state));
                                }
                                else if (_workerThreads.ContainsKey(i) && _workerThreads[i].ContainsKey(code))
                                {
                                    _workerThreads[i][code]?.Actions.Add(() => mapping.Callback(state));
                                }
                            }
                        }

                        // If the key was blocked by Subscription Mode, then move on to next key...
                        if (block)
                        {
                            continue;
                        }

                        // If this key had no subscriptions, but Context Mode is set for this keyboard...
                        // ... then set the Context before sending the key
                        if (!hasSubscription && hasContext)
                        {
                            _contextCallbacks[i](1);
                        }

                        // Pass the key through to the OS.
                        ManagedWrapper.Send(_deviceContext, i, ref stroke, 1);

                        // If we are processing Context Mode, then Unset the context variable after sending the key
                        if (!hasSubscription && hasContext)
                        {
                            _contextCallbacks[i](0);
                        }
                    }
                }

                // Process Mice
                for (var i = 11; i < 21; i++)
                {
                    var isMonitoredMouse = IsMonitoredDevice(i) == 1;
                    var hasSubscription  = false;
                    var hasContext       = _contextCallbacks.ContainsKey(i);

                    while (ManagedWrapper.Receive(_deviceContext, i, ref stroke, 1) > 0)
                    {
                        //Debug.WriteLine($"AHK| Mouse {i} seen - flags: {stroke.mouse.flags}, raw state: {stroke.mouse.state}");
                        var block = false;
                        if (isMonitoredMouse)
                        {
                            if (stroke.mouse.state != 0 && _mouseButtonMappings.ContainsKey(i))
                            {
                                // Mouse Button
                                //Debug.WriteLine($"AHK| Mouse {i} seen - flags: {stroke.mouse.flags}, raw state: {stroke.mouse.state}");
                                var btnStates = MouseStrokeToButtonStates(stroke);
                                foreach (var btnState in btnStates)
                                {
                                    if (_mouseButtonMappings[i].ContainsKey(btnState.Button))
                                    {
                                        hasSubscription = true;
                                        var mapping = _mouseButtonMappings[i][btnState.Button];
                                        if (mapping.Block)
                                        {
                                            block = true;
                                        }

                                        var state = btnState;

                                        if (mapping.Concurrent)
                                        {
                                            ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(state.State));
                                        }
                                        else if (_workerThreads.ContainsKey(i) &&
                                                 _workerThreads[i].ContainsKey(btnState.Button))
                                        {
                                            _workerThreads[i][btnState.Button]?.Actions
                                            .Add(() => mapping.Callback(state.State));
                                        }
                                    }
                                }

                                //Console.WriteLine($"AHK| Mouse {i} seen - button {btnState.Button}, state: {stroke.mouse.state}, rolling: {stroke.mouse.rolling}");
                            }
                            else if ((stroke.mouse.flags & (ushort)ManagedWrapper.MouseFlag.MouseMoveAbsolute) ==
                                     (ushort)ManagedWrapper.MouseFlag.MouseMoveAbsolute &&
                                     _mouseMoveAbsoluteMappings.ContainsKey(i))
                            {
                                // Absolute Mouse Move
                                hasSubscription = true;
                                var mapping = _mouseMoveAbsoluteMappings[i];
                                if (mapping.Block)
                                {
                                    block = true;
                                }

                                var x = stroke.mouse.x;
                                var y = stroke.mouse.y;
                                if (mapping.Concurrent)
                                {
                                    ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(x, y));
                                }
                                else if (_workerThreads.ContainsKey(i) && _workerThreads[i].ContainsKey(7))
                                {
                                    _workerThreads[i][7]?.Actions.Add(() => mapping.Callback(x, y));
                                }
                            }
                            else if ((stroke.mouse.flags & (ushort)ManagedWrapper.MouseFlag.MouseMoveRelative) ==
                                     (ushort)ManagedWrapper.MouseFlag.MouseMoveRelative &&
                                     _mouseMoveRelativeMappings.ContainsKey(i))
                            {
                                // Relative Mouse Move
                                hasSubscription = true;
                                var mapping = _mouseMoveRelativeMappings[i];
                                if (mapping.Block)
                                {
                                    block = true;
                                }

                                var x = stroke.mouse.x;
                                var y = stroke.mouse.y;
                                if (mapping.Concurrent)
                                {
                                    ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(x, y));
                                }
                                else if (_workerThreads.ContainsKey(i) && _workerThreads[i].ContainsKey(8))
                                {
                                    _workerThreads[i][8]?.Actions.Add(() => mapping.Callback(x, y));
                                }
                            }
                        }

                        // If this key had no subscriptions, but Context Mode is set for this mouse...
                        // ... then set the Context before sending the button
                        if (!hasSubscription && hasContext)
                        {
                            _contextCallbacks[i](1);                                 // Set Context
                        }
                        if (!block)
                        {
                            ManagedWrapper.Send(_deviceContext, i, ref stroke, 1);
                        }
                        // If we are processing Context Mode, then Unset the context variable after sending the button
                        if (!hasSubscription && hasContext)
                        {
                            _contextCallbacks[i](0);
                        }
                    }
                }

                Thread.Sleep(10);
            }
        }
Пример #18
0
 public Monitor()
 {
     _deviceContext = ManagedWrapper.CreateContext();
     SetThreadState(true);
 }
Пример #19
0
        private void PollThread()
        {
            var stroke = new ManagedWrapper.Stroke();

            while (_pollThreadRunning)
            {
                for (var i = 1; i < 11; i++)
                {
                    while (ManagedWrapper.Receive(_deviceContext, i, ref stroke, 1) > 0)
                    {
                        ManagedWrapper.Send(_deviceContext, i, ref stroke, 1);
                        var processedState = KeyboardStrokeToKeyboardState(stroke);
                        if (processedState.Ignore)
                        {
                            FireKeyboardCallback(i, new KeyboardCallback
                            {
                                Id    = i,
                                Code  = stroke.key.code,
                                State = stroke.key.state,
                                Info  = "Ignored - showing raw values"
                            });
                        }
                        else
                        {
                            FireKeyboardCallback(i, new KeyboardCallback
                            {
                                Id    = i,
                                Code  = processedState.Code,
                                State = processedState.State,
                                Info  = stroke.key.code > 255 ? "Extended" : ""
                            });
                        }
                    }
                }

                for (var i = 11; i < 21; i++)
                {
                    while (ManagedWrapper.Receive(_deviceContext, i, ref stroke, 1) > 0)
                    {
                        ManagedWrapper.Send(_deviceContext, i, ref stroke, 1);
                        if (stroke.mouse.state != 0)
                        {
                            // Mouse Button
                            var btnState = MouseStrokeToButtonState(stroke);
                            FireMouseCallback(new MouseCallback
                            {
                                Id    = i,
                                Code  = btnState.Button,
                                State = btnState.State,
                                Info  = "Mouse Button"
                            });
                        }
                        else if ((stroke.mouse.flags & (ushort)ManagedWrapper.MouseFlag.MouseMoveAbsolute) ==
                                 (ushort)ManagedWrapper.MouseFlag.MouseMoveAbsolute)
                        {
                            // Absolute Mouse Move
                            FireMouseCallback(new MouseCallback
                            {
                                Id   = i,
                                X    = stroke.mouse.x,
                                Y    = stroke.mouse.y,
                                Info = "Absolute Move"
                            });
                        }
                        else if ((stroke.mouse.flags & (ushort)ManagedWrapper.MouseFlag.MouseMoveRelative) ==
                                 (ushort)ManagedWrapper.MouseFlag.MouseMoveRelative)

                        {
                            // Relative Mouse Move
                            FireMouseCallback(new MouseCallback
                            {
                                Id   = i,
                                X    = stroke.mouse.x,
                                Y    = stroke.mouse.y,
                                Info = "Relative Move"
                            });
                        }

                        //FireMouseCallback(i, stroke);
                    }
                }

                Thread.Sleep(10);
            }
        }
Пример #20
0
        // ScanCode notes: https://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html
        private void PollThread()
        {
            ManagedWrapper.Stroke stroke = new ManagedWrapper.Stroke();

            while (true)
            {
                // Iterate through all Keyboards
                for (var i = 1; i < 11; i++)
                {
                    var isMonitoredKeyboard = IsMonitoredDevice(i) == 1;
                    var hasSubscription     = false;
                    var hasContext          = _contextCallbacks.ContainsKey(i);

                    // Process any waiting input for this keyboard
                    while (ManagedWrapper.Receive(_deviceContext, i, ref stroke, 1) > 0)
                    {
                        var block = false;
                        // If this is not a monitored keyboard, skip.
                        // This check should not really be needed as the IsMonitoredDevice() predicate should only match monitored keyboards...
                        // ... but in case it does, we want to ignore this bit and pass the input through
                        if (isMonitoredKeyboard && _keyboardMappings.ContainsKey(i))
                        {
                            // Process Subscription Mode
                            var code  = stroke.key.code;
                            var state = stroke.key.state;

                            #region KeyCode, State, Extended Flag translation
                            // Begin translation of incoming key code, state, extended flag etc...
                            var processMappings = true;
                            if (code == 54)
                            {
                                // Interception seems to report Right Shift as 54 / 0x36 with state 0/1...
                                // ... this code is normally unused (Alt-SysRq according to linked page) ...
                                // ... and AHK uses 54 + 256 = 310 (0x36 + 0x100 = 0x136)...
                                // ... so change the code, but leave the state as 0/1
                                code = 310;
                            }

                            // If state is shifted up by 2 (1 or 2 instead of 0 or 1), then this is an "Extended" key code
                            if (state > 1)
                            {
                                if (code == 42)
                                {
                                    // Shift (42/0x2a) with extended flag = the key after this one is extended.
                                    // Example case is Delete (The one above the arrow keys, not on numpad)...
                                    // ... this generates a stroke of 0x2a (Shift) with *extended flag set* (Normal shift does not do this)...
                                    // ... followed by 0x53 with extended flag set.
                                    // We do not want to fire subsriptions for the extended shift, but *do* want to let the key flow through...
                                    // ... so that is handled here.
                                    // When the extended key (Delete in the above example) subsequently comes through...
                                    // ... it will have code 0x53, which we shift to 0x153 (Adding 256 Dec) to signify extended version...
                                    // ... as this is how AHK behaves with GetKeySC()

                                    // Set flag to stop Context Mode from firing
                                    hasSubscription = true;
                                    // Set flag to indicate disable mapping processing
                                    processMappings = false;
                                }
                                else
                                {
                                    // Extended flag set
                                    // Shift code up by 256 (0x100) to signify extended code
                                    code  += 256;
                                    state -= 2;
                                }
                            }
                            #endregion

                            // Code and state now normalized, proceed with checking for subscriptions...
                            if (processMappings && _keyboardMappings[i].ContainsKey(code))
                            {
                                hasSubscription = true;
                                var mapping = _keyboardMappings[i][code];
                                if (mapping.Block)
                                {
                                    block = true;
                                }

                                ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(1 - state));
                            }
                        }

                        // If the key was blocked by Subscription Mode, then move on to next key...
                        if (block)
                        {
                            continue;
                        }

                        // If this key had no subscriptions, but Context Mode is set for this keyboard...
                        // ... then set the Context before sending the key
                        if (!hasSubscription && hasContext)
                        {
                            _contextCallbacks[i](1);
                        }

                        // Pass the key through to the OS.
                        ManagedWrapper.Send(_deviceContext, i, ref stroke, 1);

                        // If we are processing Context Mode, then Unset the context variable after sending the key
                        if (!hasSubscription && hasContext)
                        {
                            _contextCallbacks[i](0);
                        }
                    }
                }

                // Process Mice
                for (var i = 11; i < 21; i++)
                {
                    var isMonitoredMouse = IsMonitoredDevice(i) == 1;
                    var hasSubscription  = false;
                    var hasContext       = _contextCallbacks.ContainsKey(i);

                    while (ManagedWrapper.Receive(_deviceContext, i, ref stroke, 1) > 0)
                    {
                        //Debug.WriteLine($"AHK| Mouse {i} seen - flags: {stroke.mouse.flags}, raw state: {stroke.mouse.state}");
                        var block = false;
                        if (isMonitoredMouse)
                        {
                            if (stroke.mouse.state != 0 && _mouseButtonMappings.ContainsKey(i))
                            {
                                // Mouse Button
                                //Debug.WriteLine($"AHK| Mouse {i} seen - flags: {stroke.mouse.flags}, raw state: {stroke.mouse.state}");
                                var btnState = StrokeStateToButtonState(stroke);
                                if (_mouseButtonMappings[i].ContainsKey(btnState.Button))
                                {
                                    hasSubscription = true;
                                    var mapping = _mouseButtonMappings[i][btnState.Button];
                                    if (mapping.Block)
                                    {
                                        block = true;
                                    }

                                    var state = btnState;
                                    ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(state.State));
                                }
                                //Console.WriteLine($"AHK| Mouse {i} seen - button {btnState.Button}, state: {stroke.mouse.state}, rolling: {stroke.mouse.rolling}");
                            }
                            else if ((stroke.mouse.flags & (ushort)ManagedWrapper.MouseFlag.MouseMoveAbsolute) ==
                                     (ushort)ManagedWrapper.MouseFlag.MouseMoveAbsolute &&
                                     _mouseMoveAbsoluteMappings.ContainsKey(i))
                            {
                                // Absolute Mouse Move
                                hasSubscription = true;
                                var mapping = _mouseMoveAbsoluteMappings[i];
                                if (mapping.Block)
                                {
                                    block = true;
                                }

                                var x = stroke.mouse.x;
                                var y = stroke.mouse.y;
                                ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(x, y));
                            }
                            else if ((stroke.mouse.flags & (ushort)ManagedWrapper.MouseFlag.MouseMoveRelative) ==
                                     (ushort)ManagedWrapper.MouseFlag.MouseMoveRelative &&
                                     _mouseMoveRelativeMappings.ContainsKey(i))
                            {
                                // Relative Mouse Move
                                hasSubscription = true;
                                var mapping = _mouseMoveRelativeMappings[i];
                                if (mapping.Block)
                                {
                                    block = true;
                                }

                                var x = stroke.mouse.x;
                                var y = stroke.mouse.y;
                                ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(x, y));
                            }
                        }
                        // If this key had no subscriptions, but Context Mode is set for this mouse...
                        // ... then set the Context before sending the button
                        if (!hasSubscription && hasContext)
                        {
                            // Set Context
                            _contextCallbacks[i](1);
                        }
                        if (!(block))
                        {
                            ManagedWrapper.Send(_deviceContext, i, ref stroke, 1);
                        }
                        // If we are processing Context Mode, then Unset the context variable after sending the button
                        if (!hasSubscription && hasContext)
                        {
                            // Unset Context
                            _contextCallbacks[i](0);
                        }
                    }
                }
                Thread.Sleep(10);
            }
        }
Пример #21
0
        // ScanCode notes: https://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html
        private void DoPoll(object sender, EventArgs e)
        {
            _pollThreadRunning = true;
            var stroke = new ManagedWrapper.Stroke();

            // Iterate through all Keyboards
            for (var i = 1; i < 11; i++)
            {
                var isMonitoredKeyboard = IsMonitoredDevice(i) == 1;
                var hasSubscription     = false;
                var hasContext          = _contextCallbacks.ContainsKey(i);

                // Process any waiting input for this keyboard
                while (ManagedWrapper.Receive(_deviceContext, i, ref stroke, 1) > 0)
                {
                    var block = false;
                    // If this is not a monitored keyboard, skip.
                    // This check should not really be needed as the IsMonitoredDevice() predicate should only match monitored keyboards...
                    // ... but in case it does, we want to ignore this bit and pass the input through
                    if (isMonitoredKeyboard)
                    {
                        var            isKeyMapping   = false; // True if this is a mapping to a single key, else it would be a mapping to a whole device
                        var            processedState = HelperFunctions.KeyboardStrokeToKeyboardState(stroke);
                        var            code           = processedState.Code;
                        var            state          = processedState.State;
                        MappingOptions mapping        = null;

                        if (_keyboardMappings.ContainsKey(i))
                        {
                            mapping = _keyboardMappings[i];
                        }
                        else if (_keyboardKeyMappings.ContainsKey(i) && _keyboardKeyMappings[i].ContainsKey(code))
                        {
                            isKeyMapping = true;
                            mapping      = _keyboardKeyMappings[i][code];
                        }
                        if (mapping != null)
                        {
                            // Process Subscription Mode

                            #region KeyCode, State, Extended Flag translation

                            // Begin translation of incoming key code, state, extended flag etc...
                            var processMappings = true;

                            #endregion

                            if (processedState.Ignore)
                            {
                                // Set flag to stop Context Mode from firing
                                hasSubscription = true;
                                // Set flag to indicate disable mapping processing
                                processMappings = false;
                            }

                            // Code and state now normalized, proceed with checking for subscriptions...
                            if (processMappings)
                            {
                                hasSubscription = true;

                                if (mapping.Block)
                                {
                                    block = true;
                                }
                                if (mapping.Concurrent)
                                {
                                    if (isKeyMapping)
                                    {
                                        ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(state));
                                    }
                                    else
                                    {
                                        ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(code, state));
                                    }
                                }
                                else
                                {
                                    if (isKeyMapping)
                                    {
                                        _workerThreads[i][code]?.Actions.Add(() => mapping.Callback(state));
                                    }
                                    else
                                    {
                                        _deviceWorkerThreads[i]?.Actions.Add(() => mapping.Callback(code, state));
                                    }
                                }
                            }
                        }
                    }

                    // If the key was blocked by Subscription Mode, then move on to next key...
                    if (block)
                    {
                        continue;
                    }

                    // If this key had no subscriptions, but Context Mode is set for this keyboard...
                    // ... then set the Context before sending the key
                    if (!hasSubscription && hasContext)
                    {
                        _contextCallbacks[i](1);
                    }

                    // Pass the key through to the OS.
                    ManagedWrapper.Send(_deviceContext, i, ref stroke, 1);

                    // If we are processing Context Mode, then Unset the context variable after sending the key
                    if (!hasSubscription && hasContext)
                    {
                        _contextCallbacks[i](0);
                    }
                }
            }

            // Process Mice
            for (var i = 11; i < 21; i++)
            {
                var isMonitoredMouse = IsMonitoredDevice(i) == 1;
                var hasSubscription  = false;
                var hasContext       = _contextCallbacks.ContainsKey(i);

                while (ManagedWrapper.Receive(_deviceContext, i, ref stroke, 1) > 0)
                {
                    if (!isMonitoredMouse)
                    {
                        continue;
                    }

                    var moveRemoved = false;
                    var hasMove     = false;
                    var x           = stroke.mouse.x;
                    var y           = stroke.mouse.y;
                    //Debug.WriteLine($"AHK| Stroke Seen. State = {stroke.mouse.state}, Flags = {stroke.mouse.flags}, x={x}, y={y}");

                    // Process mouse movement
                    if (x != 0 || y != 0)
                    {
                        hasMove = true;
                        // Process Absolute Mouse Move
                        if ((stroke.mouse.flags & (ushort)ManagedWrapper.MouseFlag.MouseMoveAbsolute) == (ushort)ManagedWrapper.MouseFlag.MouseMoveAbsolute)
                        {
                            if (_mouseMoveAbsoluteMappings.ContainsKey(i))
                            {
                                var mapping = _mouseMoveAbsoluteMappings[i];
                                hasSubscription = true;
                                //var debugStr = $"AHK| Mouse stroke has absolute move of {x}, {y}...";

                                if (mapping.Concurrent)
                                {
                                    ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(x, y));
                                }
                                else if (_workerThreads.ContainsKey(i) && _workerThreads[i].ContainsKey(7))
                                {
                                    _workerThreads[i][7]?.Actions.Add(() => mapping.Callback(x, y));
                                }
                                if (mapping.Block)
                                {
                                    moveRemoved    = true;
                                    stroke.mouse.x = 0;
                                    stroke.mouse.y = 0;
                                    //debugStr += "Blocking";
                                }
                                else
                                {
                                    //debugStr += "Not Blocking";
                                }
                                //Debug.WriteLine(debugStr);
                            }
                        }

                        // Process Relative Mouse Move
                        //else if ((stroke.mouse.flags & (ushort) ManagedWrapper.MouseFlag.MouseMoveRelative) == (ushort) ManagedWrapper.MouseFlag.MouseMoveRelative) / flag is 0, so always true!
                        else
                        {
                            if (_mouseMoveRelativeMappings.ContainsKey(i))
                            {
                                var mapping = _mouseMoveRelativeMappings[i];
                                hasSubscription = true;
                                //var debugStr = $"AHK| Mouse stroke has relative move of {x}, {y}...";

                                if (mapping.Concurrent)
                                {
                                    ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(x, y));
                                }
                                else if (_workerThreads.ContainsKey(i) && _workerThreads[i].ContainsKey(8))
                                {
                                    _workerThreads[i][8]?.Actions.Add(() => mapping.Callback(x, y));
                                }
                                if (mapping.Block)
                                {
                                    moveRemoved    = true;
                                    stroke.mouse.x = 0;
                                    stroke.mouse.y = 0;
                                    //debugStr += "Blocking";
                                }
                                else
                                {
                                    //debugStr += "Not Blocking";
                                }
                                //Debug.WriteLine(debugStr);
                            }
                        }
                    }


                    var isMouseButtonsMapping = _mouseButtonsMappings.ContainsKey(i);

                    // Process Mouse Buttons - do this AFTER mouse movement, so that absolute mode has coordinates available at the point that the button callback is fired
                    if (stroke.mouse.state != 0 && _mouseButtonMappings.ContainsKey(i) || isMouseButtonsMapping)
                    {
                        var btnStates = HelperFunctions.MouseStrokeToButtonStates(stroke);
                        foreach (var btnState in btnStates)
                        {
                            if (!isMouseButtonsMapping && !_mouseButtonMappings[i].ContainsKey(btnState.Button))
                            {
                                continue;
                            }

                            hasSubscription = true;
                            MappingOptions mapping = null;
                            if (isMouseButtonsMapping)
                            {
                                mapping = _mouseButtonsMappings[i];
                            }
                            else
                            {
                                mapping = _mouseButtonMappings[i][btnState.Button];
                            }

                            var state = btnState;

                            if (mapping.Concurrent)
                            {
                                if (isMouseButtonsMapping)
                                {
                                    ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(btnState.Button, state.State));
                                }
                                else
                                {
                                    ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(state.State));
                                }
                            }
                            else
                            {
                                if (isMouseButtonsMapping)
                                {
                                    _deviceWorkerThreads[i]?.Actions
                                    .Add(() => mapping.Callback(btnState.Button, state.State));
                                }
                                else
                                {
                                    _workerThreads[i][btnState.Button]?.Actions
                                    .Add(() => mapping.Callback(state.State));
                                }
                            }


                            if (mapping.Block)
                            {
                                // Remove the event for this button from the stroke, leaving other button events intact
                                stroke.mouse.state -= btnState.Flag;
                                // If we are removing a mouse wheel event, then set rolling to 0 if no mouse wheel event left
                                if (btnState.Flag == 0x400 || btnState.Flag == 0x800)
                                {
                                    if ((stroke.mouse.state & 0x400) != 0x400 && (stroke.mouse.state & 0x800) != 0x800)
                                    {
                                        //Debug.WriteLine("AHK| Removing rolling flag from stroke");
                                        stroke.mouse.rolling = 0;
                                    }
                                }
                                //Debug.WriteLine($"AHK| Removing flag {btnState.Flag} from stoke, leaving state {stroke.mouse.state}");
                            }
                            else
                            {
                                //Debug.WriteLine($"AHK| Leaving flag {btnState.Flag} in stroke");
                            }
                        }
                    }


                    // Forward on the stroke if required
                    if (hasSubscription)
                    {
                        // Subscription mode
                        // If the stroke has a move that was not removed, OR it has remaining button events, then forward on the stroke
                        if ((hasMove && !moveRemoved) || stroke.mouse.state != 0)
                        {
                            //Debug.WriteLine($"AHK| Sending stroke. State = {stroke.mouse.state}. hasMove={hasMove}, moveRemoved={moveRemoved}");
                            ManagedWrapper.Send(_deviceContext, i, ref stroke, 1);
                        }
                        else
                        {
                            // Everything removed from stroke, do not forward
                            //Debug.WriteLine("AHK| Mouse stroke now empty, not forwarding");
                        }
                    }
                    else if (hasContext)
                    {
                        // Context Mode - forward stroke with context wrapping
                        _contextCallbacks[i](1);
                        ManagedWrapper.Send(_deviceContext, i, ref stroke, 1);
                        _contextCallbacks[i](0);
                    }
                    else
                    {
                        // No subscription or context mode - forward on
                        //Debug.WriteLine($"AHK| Sending stroke. State = {stroke.mouse.state}. hasMove={hasMove}, moveRemoved={moveRemoved}");
                        ManagedWrapper.Send(_deviceContext, i, ref stroke, 1);
                    }
                    //Debug.WriteLine($"AHK| ");
                }
            }

            _pollThreadRunning = false;
        }
Пример #22
0
        private static void PollThread(object obj)
        {
            var token = (CancellationToken)obj;

            //Debug.WriteLine($"AHK| Poll Thread Started");
            _pollThreadRunning = true;
            int stroke1DeviceId;
            int stroke2DeviceId;

            while (!token.IsCancellationRequested)
            {
                var stroke = new ManagedWrapper.Stroke();
                // While no input happens, this loop will exit every 10ms to allow us to check if cancellation has been requested
                // WaitWithTimeout is used with a timeout of 10ms instead of Wait, so that when we eg use SetState to turn the thread off...
                // ... any input which was filtered and is waiting to be processed can be processed (eg lots of mouse moves buffered)
                if (ManagedWrapper.Receive(DeviceContext, stroke1DeviceId = ManagedWrapper.WaitWithTimeout(DeviceContext, 10), ref stroke, 1) > 0)
                {
                    var strokes = new List <ManagedWrapper.Stroke>();
                    strokes.Add(stroke);
                    if (stroke1DeviceId < 11)
                    {
                        //Debug.WriteLine($"Stroke 1: {RenderStroke(stroke)}");
                        // If this is a keyboard stroke, then keep performing more Receives immediately with a timeout of 0...
                        // ... this is to check whether an extended stroke is waiting.
                        // Unfortunately, at this point, it's entirely possible that two single-stroke keys end up in strokes...
                        // ... or even 3 strokes or more (eg one single-stroke key followed by a two-stroke key)
                        //while ((stroke2DeviceId = ManagedWrapper.WaitWithTimeout(DeviceContext, 0)) == stroke1DeviceId)
                        while ((stroke2DeviceId = ManagedWrapper.WaitWithTimeout(DeviceContext, 0)) != 0)
                        {
                            ManagedWrapper.Receive(DeviceContext, stroke2DeviceId, ref stroke, 1);
                            strokes.Add(stroke);
                            //Debug.WriteLine($"Stroke {strokes.Count}: {RenderStroke(stroke)}");
                        }

                        // Loop through the list checking the first 2 indexes for valid "two-code" key combinations.
                        //   If no combo is found, send index 0 on its way, remove it off the top of the list, repeat
                        while (strokes.Count > 0)
                        {
                            if (strokes.Count >= 2 && ScanCodeHelper.IsDoubleScanCode(new List <ManagedWrapper.Stroke> {
                                strokes[0], strokes[1]
                            }))
                            {
                                DeviceHandlers[stroke1DeviceId].ProcessStroke(new List <ManagedWrapper.Stroke> {
                                    strokes[0], strokes[1]
                                });
                                strokes.RemoveRange(0, 2);
                            }
                            else
                            {
                                DeviceHandlers[stroke1DeviceId].ProcessStroke(new List <ManagedWrapper.Stroke> {
                                    strokes[0]
                                });
                                strokes.RemoveAt(0);
                            }
                        }
                    }
                    else
                    {
                        DeviceHandlers[stroke1DeviceId].ProcessStroke(strokes);
                    }
                }
            }
            _pollThreadRunning = false;
            //Debug.WriteLine($"AHK| Poll Thread Ended");
        }