locked
Capturing user's signature

    Question

  • Hello All.

    I've trying to implement a canvas control to capture user's signature. Its a windows 8.1 metro app.

    The problem is, the canvas accepts user's signature when input from a mouse (more like drawing your signature in MS Paint - same thing) but it fails when using a finger or a stylus.

    This is my code. 

    // register canvas handlers
    CnvGvlSign.PointerPressed += new PointerEventHandler(CnvGvlSign_PointerPressed);
                CnvGvlSign.PointerMoved += new PointerEventHandler(CnvGvlSign_PointerMoved);
                CnvGvlSign.PointerReleased += new PointerEventHandler(CnvGvlSign_PointerReleased);
                CnvGvlSign.PointerExited += new PointerEventHandler(CnvGvlSign_PointerReleased);
    
    
    //code to "save" the sign
    Point _previousgvlContactPt = new Point();
    InkManager _inkgvlManager = new InkManager();
    
    //code to draw the line... PROBLEM HERE
    private void CnvGvlSign_PointerMoved(object sender, PointerRoutedEventArgs e)
            {
                if (e.Pointer.PointerId == _penID)
                {
                    PointerPoint pt = e.GetCurrentPoint(CnvGvlSign);
    
                    // Render a red line on the canvas as the pointer moves. 
                    // Distance() is an application-defined function that tests
                    // whether the pointer has moved far enough to justify 
                    // drawing a new line.
                    Point currentContactPt = pt.Position;
                    if (Distance(currentContactPt, _previousgvlContactPt) > 1)
                    {
                        Line line = new Line()
                        {
                            X1 = _previousgvlContactPt.X,
                            Y1 = _previousgvlContactPt.Y,
                            X2 = currentContactPt.X,
                            Y2 = currentContactPt.Y,
                            StrokeThickness = STROKETHICKNESS,
                            Stroke = new SolidColorBrush(Colors.Black)
                        };
    
                        _previousgvlContactPt = currentContactPt;
    
                        // Draw the line on the canvas by adding the Line object as
                        // a child of the Canvas object.
                        CnvGvlSign.Children.Add(line);
    
                        // Pass the pointer information to the InkManager.
                        _inkgvlManager.ProcessPointerUpdate(pt);
                    }
                }
                else if (e.Pointer.PointerId == _touchID)
                {
                    // Process touch input ??? HOW TO HANDLE THIS INPUT ??! ??
                }
    
                e.Handled = true;
            }
    
    

    I've tried every possible link from codeproject but no use. Any one can help me to crack this? 

    Thank you.


    • Edited by Pirate11 Wednesday, May 21, 2014 2:10 PM updated code
    Wednesday, May 21, 2014 2:09 PM

Answers

  • Without knowing exactly what the code does I can't say for sure why you get that error, but one thing you'll need to handle for touch is multiple points at the same time. An easy way is to ignore any new touch points if you're already handling one.

    The Input: Simplified ink sample  may be a better starting point. If you change the EventIsInk function to allow Touch and disable the MainPage's ScrollViewer so it doesn't steal the touch input then it will draw fine by touch.

       public static bool EventIsInk(Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
        {
            var pointerProperties = e.GetCurrentPoint(null).Properties;
    
            bool rval = false
                || (e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Pen && !pointerProperties.IsBarrelButtonPressed && !pointerProperties.IsRightButtonPressed)
                || (e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Mouse && pointerProperties.IsLeftButtonPressed && e.KeyModifiers == Windows.System.VirtualKeyModifiers.None)
                || (e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Touch);
    
            return rval;
        }
    --Rob

      

    Friday, May 23, 2014 2:15 AM
    Owner

All replies

  • You should be able to use the same code for pen, touch, and mouse.

    Where does _penID come from in your code?

    The PointerId is the id for a specific touch point so you can tell multiple simultaneous pointers apart. It doesn't tell the type of the pointer and isn't constant except while that particular pointers down: you can track an ID from PointerPressed until that pointerId is PointerReleased. Then that ID may or may not be reused.

    The sample code at http://msdn.microsoft.com/en-us/library/windows/apps/xaml/Hh974457(v=win.10).aspx explicitly excludes touch and captures only mouse and pen input. If you want finger drawing you don't need to separate them.

    A common pattern is to handle them separately and to use the pen for ink and touch to manipulate the canvas, but you don't need to separate them for your use.


    Wednesday, May 21, 2014 2:20 PM
    Owner
  • Hi, thanks for replying.

    Here is the remaining code.

    uint _penID;
    
    private void CnvGvlSign_PointerReleased(object sender, PointerRoutedEventArgs e)
            {
                if (e.Pointer.PointerId == _penID)
                {
                    PointerPoint pt = e.GetCurrentPoint(CnvGvlSign);
    
                    // Pass the pointer information to the InkManager. 
                    _inkgvlManager.ProcessPointerUp(pt);
                }
    
                else if (e.Pointer.PointerId == _touchID)
                {
                    // Process touch input
                    //fails here as well...
                }
    
                _touchID = 0;
                _penID = 0;
    
                // Call an application-defined function to render the ink strokes.
                //RenderAllStrokes();
    
                e.Handled = true;
            }
    
    
    
    private void CnvGvlSign_PointerMoved(object sender, PointerRoutedEventArgs e)
            {
                if (e.Pointer.PointerId == _penID)
                {
                    PointerPoint pt = e.GetCurrentPoint(CnvGvlSign);
    
                    // Render a red line on the canvas as the pointer moves. 
                    // Distance() is an application-defined function that tests
                    // whether the pointer has moved far enough to justify 
                    // drawing a new line.
                    Point currentContactPt = pt.Position;
                    if (Distance(currentContactPt, _previousgvlContactPt) > 1)
                    {
                        Line line = new Line()
                        {
                            X1 = _previousgvlContactPt.X,
                            Y1 = _previousgvlContactPt.Y,
                            X2 = currentContactPt.X,
                            Y2 = currentContactPt.Y,
                            StrokeThickness = STROKETHICKNESS,
                            Stroke = new SolidColorBrush(Colors.Black)
                        };
    
                        _previousgvlContactPt = currentContactPt;
    
                        // Draw the line on the canvas by adding the Line object as
                        // a child of the Canvas object.
                        CnvGvlSign.Children.Add(line);
    
                        // Pass the pointer information to the InkManager.
                        _inkgvlManager.ProcessPointerUpdate(pt);
                    }
                }
                else if (e.Pointer.PointerId == _touchID)
                {
                    // Process touch input
                }
    
                e.Handled = true;
            }
    
    
    
    // THIS IS WHERE THE _penID IS GIVEN A VALUE
    
    Point _previousgvlContactPt = new Point();
            InkManager _inkgvlManager = new InkManager();
    
            private void CnvGvlSign_PointerPressed(object sender, PointerRoutedEventArgs e)
            {
                // Get information about the pointer location.
                PointerPoint pt = e.GetCurrentPoint(CnvGvlSign);
                _previousgvlContactPt = pt.Position;
    
                // Accept input only from a pen or mouse with the left button pressed. 
                PointerDeviceType pointerDevType = e.Pointer.PointerDeviceType;
                if (pointerDevType == PointerDeviceType.Pen ||
                        pointerDevType == PointerDeviceType.Mouse &&
                        pt.Properties.IsLeftButtonPressed)
                {
                    // Pass the pointer information to the InkManager.
                    _inkgvlManager.ProcessPointerDown(pt);
                    _penID = pt.PointerId;
    
                    e.Handled = true;
                }
    
                else if (pointerDevType == PointerDeviceType.Touch)
                {
                    // Process touch input
                    _inkgvlManager.ProcessPointerDown(pt);
                    _penID = pt.PointerId;
    
                    e.Handled = true;
                }
            }

    I tried to write the same code, as you said, but it fails.
    Hope that helps to solve my problem.

    • Edited by Pirate11 Wednesday, May 21, 2014 2:28 PM added code
    Wednesday, May 21, 2014 2:27 PM
  • This is the error that I get when I keep "same" code for all inputs.

    This error occurs in "private void CnvGvlSign_PointerMoved(object sender, PointerRoutedEventArgs e)" 

    Wednesday, May 21, 2014 3:17 PM
  • Without knowing exactly what the code does I can't say for sure why you get that error, but one thing you'll need to handle for touch is multiple points at the same time. An easy way is to ignore any new touch points if you're already handling one.

    The Input: Simplified ink sample  may be a better starting point. If you change the EventIsInk function to allow Touch and disable the MainPage's ScrollViewer so it doesn't steal the touch input then it will draw fine by touch.

       public static bool EventIsInk(Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
        {
            var pointerProperties = e.GetCurrentPoint(null).Properties;
    
            bool rval = false
                || (e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Pen && !pointerProperties.IsBarrelButtonPressed && !pointerProperties.IsRightButtonPressed)
                || (e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Mouse && pointerProperties.IsLeftButtonPressed && e.KeyModifiers == Windows.System.VirtualKeyModifiers.None)
                || (e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Touch);
    
            return rval;
        }
    --Rob

      

    Friday, May 23, 2014 2:15 AM
    Owner