Menu

newt support

2015-09-01
2015-10-22
  • Andres Colubri

    Andres Colubri - 2015-09-01

    Hi there,

    First of all, many thanks to the authors of jpen-2, I have been using it
    for many years as the basis for the Tablet library in Processing (
    http://interfaze.info/libraries/tablet/).

    It appears that AWT is starting to fall out of favor as the default
    windowing toolkit. Oracle's efforts go mostly behind JavaFX, while JOGL (an
    OpenGL-Java binding) introduced its own toolkit (NEWT,
    http://jogamp.org/jogl/doc/NEWT-Overview.html).

    NEWT defines its own base class (GLWindow) but has some API reminiscent of
    AWT (listeners, etc.) This makes me wonder how difficult would be to
    implement a NewtPenOwner, etc.

    Best,
    Andres

     
    • Nicolas Carranza

      hi Andres, I will take a look at newt next weekend and let you know.
      thank you,
      Nicolas

       

      Last edit: Nicolas Carranza 2015-09-02
  • Nicolas Carranza

    hi Andres,

    jogl and newt are fun. Here is an implementation of a newt WindowPenOwner:

    import com.jogamp.newt.event.MouseAdapter;
    import com.jogamp.newt.event.MouseEvent;
    import com.jogamp.newt.Window;
    import java.util.Arrays;
    import java.util.Collection;
    import jpen.owner.PenClip;
    import jpen.owner.PenOwner;
    import jpen.PenEvent;
    import jpen.PenProvider;
    import jpen.provider.osx.CocoaProvider;
    import jpen.provider.wintab.WintabProvider;
    import jpen.provider.xinput.XinputProvider;
    
    public class WindowPenOwner
        implements PenOwner {
    
        private PenManagerHandle penManagerHandle;
        private final WindowPenClip WindowPenClip=new WindowPenClip(this);
        private final Window window;
        private volatile boolean mayBeDraggingOut;
    
        public WindowPenOwner(Window window) {
            this.window=window;
        }
    
        public Window getWindow() {
            return window;
        }
    
        @Override
        public void setPenManagerHandle(PenManagerHandle penManagerHandle) {
            this.penManagerHandle=penManagerHandle;
            window.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseEntered(MouseEvent ev) {
                    mayBeDraggingOut=true;
                    // escape from the EDT to avoid thead-safety issues...
                    new Thread(()->penManagerHandle.setPenManagerPaused(false)).start();
                }
    
                @Override
                public void mouseExited(MouseEvent ev) {
                    mayBeDraggingOut=false;
                    // escape from the EDT to avoid thead-safety issues...
                    // Note: this has a side effect: some level events continue to be fired for a "very short time" after the mouse has exited, we would have to modify jpen internals to filter them out if necessary... let me know if this needs to be done for your use case.
                    new Thread(()->penManagerHandle.setPenManagerPaused(true)).start();
                }
            });
        }
    
        @Override
        public Collection<PenProvider.Constructor> getPenProviderConstructors() {
            return Arrays.asList(
                       new PenProvider.Constructor[] {
                           //Note: do you need a newt mouse/keyboard provider (so that regular newt mouse events/keyboard are fired as jpen events too)?
                           new XinputProvider.Constructor(),
                           new WintabProvider.Constructor(),
                           new CocoaProvider.Constructor(),
                       }
                   );
        }
    
        @Override
        public PenClip getPenClip() {
            return WindowPenClip;
        }
    
        @Override
        public boolean isDraggingOut() {
            return mayBeDraggingOut;
        }
    
        @Override
        public Object evalPenEventTag(PenEvent ev) {
            return null;
        }
    
        @Override
        public boolean enforceSinglePenManager() {
            return true;
        }
    }
    

    and its WindowPenClip:

    import com.jogamp.newt.Window;
    import java.awt.geom.Point2D;
    import java.awt.Point;
    import java.awt.Rectangle;
    import jpen.owner.PenClip;
    
    final class WindowPenClip
        implements PenClip {
    
        final WindowPenOwner windowPenOwner;
    
        public WindowPenClip(WindowPenOwner windowPenOwner) {
            this.windowPenOwner=windowPenOwner;
        }
    
        @Override
        public void evalLocationOnScreen(Point pointOnScreen) {
            //-> called holding the pen scheduler lock
            pointOnScreen.x=pointOnScreen.y=0;
            com.jogamp.nativewindow.util.Point joglPoint=windowPenOwner.getWindow().getLocationOnScreen(null);
            pointOnScreen.x=joglPoint.getX();
            pointOnScreen.y=joglPoint.getY();
        }
    
        @Override
        public boolean contains(Point2D.Float point) {
            //-> called holding the pen scheduler lock
            if(point.x<0 || point.y<0)
                return false;
            Window window=windowPenOwner.getWindow();
            return point.x<=window.getWidth() && point.y<=window.getHeight();
        }
    }
    

    A dummy application printing jpen events on std output is:

    import com.jogamp.newt.event.WindowAdapter;
    import com.jogamp.newt.event.WindowEvent;
    import com.jogamp.newt.opengl.GLWindow;
    import com.jogamp.newt.Window;
    import com.jogamp.opengl.GLCapabilities;
    import com.jogamp.opengl.GLProfile;
    import jpen.event.PenAdapter;
    import jpen.PenManager;
    import jpen.PKindEvent;
    import jpen.PLevelEvent;
    
    public class JPenOnWindow {
    
        public synchronized static void main(String... args) throws Throwable {
            Window window=GLWindow.create(new GLCapabilities(GLProfile.getDefault()));
            window.setTitle("Newt and JPen");
            window.addWindowListener(new WindowAdapter() {
                @Override
                public void windowDestroyNotify(WindowEvent ev) {
                    synchronized(JPenOnWindow.class) {
                        JPenOnWindow.class.notify();
                    }
                }
            });
    
            installJPen(window);
    
            window.setVisible(true);
    
            JPenOnWindow.class.wait();
        }
    
        static void installJPen(Window window) {
            PenManager penManager=new PenManager(new WindowPenOwner(window));
    
            penManager.pen.addListener(new PenAdapter() {
                @Override
                public void penLevelEvent(PLevelEvent ev) {
                    System.out.println("ev=" + ( ev ));
                }
                @Override
                public void penKindEvent(PKindEvent ev) {
                    System.out.println("ev=" + ( ev ));
                }
            });
        }
    }
    

    This code run as expected on my linux (wacom) box, I haven't tested on Windows or OS X. Let me know if you do, and what you think... would this be enough for your use case?

    que la pases bien!
    Nicolas

     
  • Andres Colubri

    Andres Colubri - 2015-10-11

    Hola Nicolas,

    Excellent, thanks so much! I will use your code to update the Processing Tablet library, and will test on Windows and OS X. I will post an update shortly!

    Saludos,
    Andres

     
  • Andres Colubri

    Andres Colubri - 2015-10-15

    Hi Nicolas,

    I incorporated the NEWT's WindowPenOwner into the Tablet library, and the good news is that it works (tested it on OS X)!

    However, one user reported that the library is queuing up all the intermediate pen values generated between each frame. However, when the user queries the pressure, position, etc., the oldest value in the queue is returned. This is in contrast with AWT, where the current pen state is returned.

    So two questions:

    1) How can we get the most recent pen state with NEWT's WindowPenOwner?

    2) Is it possible to access the entire queue?

    Thanks!
    Andres

     
  • Nicolas Carranza

    Hi Andres,

    you can try disabling jpen event buffering by inserting "pm.pen.setFrequencyLater(1001);" on line ~147 of Tablet.java, (javadoc, 60 by default, values greater than 1000 will disable buffering). Let me know what you think or if this change resolves the issue. **

    Cheers!
    Nicolas

    ** Note that changing the Pen frequency to 200 or higher will cause potentially 200/60=~3 times more event processing by the Processing applet penTock (a Wacom Intuos reaches 200pps maximum) which can lead to unnecessarily high CPU usage. An alternative is adding a new setFrequency(){pm.setFrequencyLater()} method on Tablet.java and let demanding clients call it if needed.

     

    Last edit: Nicolas Carranza 2015-10-17
  • Nicolas Carranza

    ** UPDATE to previous post: I just saw that Tablet.java does not do anything with the penTock method. You can ignore the previous note :-)

     
  • Andres Colubri

    Andres Colubri - 2015-10-22

    Hi Nicolas,

    Thanks for the help, I will try the setFrequencyLater(1001) call!

    Andres