package org.geogebra.web.html5.euclidian; import org.geogebra.common.euclidian.EuclidianConstants; import org.geogebra.common.euclidian.event.PointerEventType; import org.geogebra.common.util.debug.Log; import org.geogebra.web.html5.event.HasOffsets; import org.geogebra.web.html5.event.PointerEvent; import org.geogebra.web.html5.event.ZeroOffset; import com.google.gwt.dom.client.Element; /** * Handles pointer events in Euclidian view(or MSPointer events in case of IE10) * * @author Zbynek * */ public class PointerEventHandler { private final IsEuclidianController tc; private HasOffsets off; private static class MsOffset extends ZeroOffset { private IsEuclidianController ec; public MsOffset(IsEuclidianController ec) { this.ec = ec; } @Override public int mouseEventX(int clientX) { return clientX + (zoom() - 1); } private native int zoom() /*-{ return $wnd.screen.deviceXDPI ? $wnd.screen.deviceXDPI / $wnd.screen.logicalXDPI : 1; }-*/; @Override public int mouseEventY(int clientY) { return clientY + (zoom() - 1); } @Override public int touchEventX(int clientX) { return mouseEventX(clientX); } @Override public int touchEventY(int clientY) { return mouseEventY(clientY); } @Override public int getEvID() { return ec.getEvNo(); } } /** * @param tc * euclidian controller * @param off * offset provider */ public PointerEventHandler(IsEuclidianController tc, HasOffsets off) { this.tc = tc; Log.debug("Zoomer for" + off); // this.off = (HasOffsets)this.tc; this.off = off == null ? new MsOffset(tc) : off; } private void pointersUp() { this.tc.getLongTouchManager().cancelTimer(); this.tc.setExternalHandling(false); } private void twoPointersDown(double x1, double y1, double x2, double y2) { this.tc.setExternalHandling(true); this.tc.twoTouchStart(off.touchEventX((int) x1), off.touchEventY((int) y1), off.touchEventX((int) x2), off.touchEventY((int) y2)); } private void twoPointersMove(double x1, double y1, double x2, double y2) { this.tc.twoTouchMove(off.touchEventX((int) x1), off.touchEventY((int) y1), off.touchEventX((int) x2), off.touchEventY((int) y2)); } private void singleDown(double x, double y, int type, int modifiers) { tc.getOffsets().closePopups(); PointerEvent e = new PointerEvent(x, y, types[type], off, false); adjust(e, modifiers); this.tc.onPointerEventStart(e); } private static void adjust(PointerEvent e, int modifiers) { if ((modifiers & 8) > 0) { e.setAlt(true); } if ((modifiers & 4) > 0) { e.setShift(true); } if ((modifiers & 2) > 0) { e.setControl(true); } if ((modifiers & 1) > 0) { e.setIsRightClick(true); } } private void singleMove(double x, double y, int type, int modifiers) { PointerEvent e = new PointerEvent(x, y, types[type], off, false); adjust(e, modifiers); this.tc.onPointerEventMove(e); } private void singleUp(double x, double y, int type, int modifiers) { this.tc.getLongTouchManager().cancelTimer(); PointerEvent e = new PointerEvent(x, y, types[type], off, false); adjust(e, modifiers); this.tc.onPointerEventEnd(e); } private final PointerEventType[] types = new PointerEventType[] { PointerEventType.MOUSE, PointerEventType.TOUCH, PointerEventType.PEN }; private void setPointerType(int i, boolean pointerDown) { this.tc.setDefaultEventType(types[i], pointerDown); } private void startLongTouch(int x, int y) { if (this.tc.getMode() == EuclidianConstants.MODE_MOVE) { this.tc.getLongTouchManager().scheduleTimer(tc, off.touchEventX(x), off.touchEventY(y)); } } private void checkMoveLongTouch() { if (!tc.isDraggingBeyondThreshold()) { /* * this.tc.getLongTouchManager().rescheduleTimerIfRunning(tc, x, y, * false); */ } else { this.tc.getLongTouchManager().cancelTimer(); } } /** * Reset the pointers */ public native void reset()/*-{ $wnd.first = { id : -1 }; $wnd.second = { id : -1 }; }-*/; /** * @param element * listening element (EV) * @param zoomer * event handler * @param override * whether to use the full pointer implementation that does not * require further event handling */ public static native void attachTo(Element element, PointerEventHandler zoomer, boolean override) /*-{ $wnd.first = { id : -1 }; $wnd.second = { id : -1 }; var fix = function(name) { return $wnd.PointerEvent ? name.toLowerCase() : "MS" + name; }; var getType = function(e){ if(e.pointerType == 2 || e.pointerType == "touch"){ return 1; } if(e.pointerType == "pen" && override){ return 2; } return 0; }; var getModifiers = function(e){ var mod = 0; if(e.altKey){ mod+=8; } if(e.shiftKey){ mod+=4; } if(e.ctrlKey){ mod+=2; } if(e.button == 2){ mod+=1; } return mod; }; element .addEventListener( fix("PointerMove"), function(e) { // zoomer.@org.geogebra.web.html5.euclidian.PointerEventHandler::setPointerType(I)(getType(e)); if ($wnd.first.id >= 0 && $wnd.second.id >= 0) { if ($wnd.second.id === e.pointerId) { $wnd.second.x = e.x; $wnd.second.y = e.y; zoomer.@org.geogebra.web.html5.euclidian.PointerEventHandler::twoPointersMove(DDDD)($wnd.first.x, $wnd.first.y, $wnd.second.x, $wnd.second.y); } else { $wnd.first.x = e.x; $wnd.first.y = e.y; } }else{ if(override){ e.preventDefault(); zoomer.@org.geogebra.web.html5.euclidian.PointerEventHandler::singleMove(DDII)(e.x, e.y, getType(e), getModifiers(e)); } } if(override){ e.preventDefault(); } zoomer.@org.geogebra.web.html5.euclidian.PointerEventHandler::checkMoveLongTouch()(); }); element .addEventListener( fix("PointerDown"), function(e) { $wnd.pointerCapture = element; if ($wnd.first.id >= 0 && $wnd.second.id >= 0) { return; } if ($wnd.first.id >= 0) { $wnd.second.id = e.pointerId; $wnd.second.x = e.x; $wnd.second.y = e.y; } else { $wnd.first.id = e.pointerId; $wnd.first.x = e.x; $wnd.first.y = e.y; } //prevent touch but not mouse: make sure focus is moved if(override && getType(e) != 0){ e.preventDefault(); } zoomer.@org.geogebra.web.html5.euclidian.PointerEventHandler::setPointerType(IZ)(getType(e), true); if ($wnd.first.id >= 0 && $wnd.second.id >= 0) { zoomer .@org.geogebra.web.html5.euclidian.PointerEventHandler::twoPointersDown(DDDD)($wnd.first.x, $wnd.first.y, $wnd.second.x, $wnd.second.y); } else if(override){ zoomer.@org.geogebra.web.html5.euclidian.PointerEventHandler::singleDown(DDII)(e.x, e.y, getType(e), getModifiers(e)); } if (e.pointerType == 2 || e.pointerType == "touch") { zoomer.@org.geogebra.web.html5.euclidian.PointerEventHandler::startLongTouch(II)($wnd.first.x, $wnd.first.y); } }); function removePointer(out, stopPropagation){ return function(e) { if($wnd.pointerCapture != element && !out){ $wnd.console.log("pointer up no capture"); return; } if ($wnd.first.id == e.pointerId) { $wnd.first.id = -1; } else { $wnd.second.id = -1; } if(!out && $wnd.second.id < 0 && $wnd.first.id < 0){ $wnd.pointerCapture = null; } if(override){ if(stopPropagation){ e.stopPropagation(); } if(!out){ zoomer.@org.geogebra.web.html5.euclidian.PointerEventHandler::singleUp(DDII)(e.x, e.y, getType(e), getModifiers(e)); } } else { zoomer.@org.geogebra.web.html5.euclidian.PointerEventHandler::pointersUp()(); } zoomer.@org.geogebra.web.html5.euclidian.PointerEventHandler::setPointerType(IZ)(getType(e), false); }; } element.addEventListener(fix("PointerOut"), removePointer(true)); if(override){ $wnd.addEventListener(fix("PointerUp"), removePointer(false)); }else{ element.addEventListener(fix("PointerUp"), removePointer(false)); } }-*/; }