Пример #1
0
        /// <summary>
        /// Attempts to update the current stylus and tablet devices for the latest WM_POINTER message.
        /// Will attempt retries if the tablet collection is invalid or does not contain the proper ids.
        /// </summary>
        /// <param name="deviceId">The id of the TabletDevice</param>
        /// <param name="cursorId">The id of the StylusDevice</param>
        /// <returns>True if successfully updated, false otherwise.</returns>
        private bool UpdateCurrentTabletAndStylus(IntPtr deviceId, uint cursorId)
        {
            PointerTabletDeviceCollection tablets = Tablet.TabletDevices?.As <PointerTabletDeviceCollection>();

            // We have an invalid tablet collection, we should refresh to make sure
            // we have the latest.
            if (!tablets.IsValid)
            {
                tablets.Refresh();

                // If the refresh fails, we need to skip input here, nothing we can do.
                // We'll try to pick up the proper state on the next WM_POINTER message.
                if (!tablets.IsValid)
                {
                    return(false);
                }
            }

            _currentTabletDevice = tablets?.GetByDeviceId(deviceId);

            _currentStylusDevice = _currentTabletDevice?.GetStylusByCursorId(cursorId);

            // Something went wrong when querying the tablet or stylus, attempt a refresh
            if (_currentTabletDevice == null || _currentStylusDevice == null)
            {
                tablets.Refresh();

                _currentTabletDevice = tablets?.GetByDeviceId(deviceId);

                _currentStylusDevice = _currentTabletDevice?.GetStylusByCursorId(cursorId);

                // Still can't get the proper devices, just wait for the next message
                if (_currentTabletDevice == null || _currentStylusDevice == null)
                {
                    return(false);
                }
            }

            return(true);
        }
Пример #2
0
        /// <summary>
        /// Creates raw stylus data from the raw WM_POINTER properties
        /// </summary>
        /// <param name="pointerData">The current pointer info</param>
        /// <param name="tabletDevice">The current TabletDevice</param>
        /// <returns>An array of raw pointer data</returns>
        private int[] GenerateRawStylusData(PointerData pointerData, PointerTabletDevice tabletDevice)
        {
            // Since we are copying raw pointer data, we want to use every property supported by this pointer.
            // We may never access some of the unknown (unsupported by WPF) properties, but they should be there
            // for consumption by the developer.
            int pointerPropertyCount = tabletDevice.DeviceInfo.SupportedPointerProperties.Length;

            // The data is as wide as the pointer properties and is per history point
            int[] rawPointerData = new int[pointerPropertyCount * pointerData.Info.historyCount];

            int[] data = new int[0];

            // Get the raw data formatted to our supported properties
            if (UnsafeNativeMethods.GetRawPointerDeviceData(
                    pointerData.Info.pointerId,
                    pointerData.Info.historyCount,
                    (uint)pointerPropertyCount,
                    tabletDevice.DeviceInfo.SupportedPointerProperties,
                    rawPointerData))
            {
                // Get the X and Y offsets to translate device coords to the origin of the hwnd
                int originOffsetX, originOffsetY;
                GetOriginOffsetsLogical(out originOffsetX, out originOffsetY);

                int numButtons = tabletDevice.DeviceInfo.SupportedPointerProperties.Length - tabletDevice.DeviceInfo.SupportedButtonPropertyIndex;

                int rawDataPointSize = (numButtons > 0) ? pointerPropertyCount - numButtons + 1 : pointerPropertyCount;

                // Instead of a single entry for each button we use one entry for all buttons so reflect that in the raw data size
                data = new int[rawDataPointSize * pointerData.Info.historyCount];

                // Skip to the beginning of each stylus point in both the target WPF array and the pointer data array.
                // The pointer data is arranged from last point to first point in the history while WPF data is arranged
                // the reverse of this (in whole stylus points).  Therefore we need to fill backward from pointer data
                // via stylus point strides.
                for (int i = 0, j = rawPointerData.Length - pointerPropertyCount; i < data.Length; i += rawDataPointSize, j -= pointerPropertyCount)
                {
                    Array.Copy(rawPointerData, j, data, i, rawDataPointSize);

                    // Apply offsets from the origin to raw pointer data here
                    data[i + StylusPointDescription.RequiredXIndex] -= originOffsetX;
                    data[i + StylusPointDescription.RequiredYIndex] -= originOffsetY;

                    if (numButtons > 0)
                    {
                        int buttonIndex = i + rawDataPointSize - 1;

                        // The last data point probably has garbage in it, so clear it to store button info
                        data[buttonIndex] = 0;

                        // Condense any leftover button properties into a single entry
                        for (int k = tabletDevice.DeviceInfo.SupportedButtonPropertyIndex; k < pointerPropertyCount; k++)
                        {
                            int mask = rawPointerData[j + k] << (k - tabletDevice.DeviceInfo.SupportedButtonPropertyIndex);
                            data[buttonIndex] |= mask;
                        }
                    }
                }
            }

            return(data);
        }