/src/org/mt4j/input/inputSources/Win7NativeTouchSource.java
http://mt4j.googlecode.com/ · Java · 313 lines · 173 code · 67 blank · 73 comment · 20 complexity · ce13dd33f290ab83f1d07072b8d1d7c5 MD5 · raw file
- /***********************************************************************
- * mt4j Copyright (c) 2008 - 2010 Christopher Ruff, Fraunhofer-Gesellschaft All rights reserved.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- ***********************************************************************/
- package org.mt4j.input.inputSources;
-
- import java.util.HashMap;
-
- import javax.swing.SwingUtilities;
-
- import org.mt4j.MTApplication;
- import org.mt4j.input.inputData.ActiveCursorPool;
- import org.mt4j.input.inputData.InputCursor;
- import org.mt4j.input.inputData.MTFingerInputEvt;
- import org.mt4j.input.inputData.MTWin7TouchInputEvt;
- import org.mt4j.util.MT4jSettings;
- import org.mt4j.util.logging.ILogger;
- import org.mt4j.util.logging.MTLoggerFactory;
-
- /**
- * Input source for native Windows 7 WM_TOUCH messages for single/multi-touch.
- * <br>Be careful to instantiate this class only ONCE!
- *
- * @author C.Ruff
- *
- */
- public class Win7NativeTouchSource extends AbstractInputSource {
- /** The Constant logger. */
- private static final ILogger logger = MTLoggerFactory.getLogger(Win7NativeTouchSource.class.getName());
- static{
- // logger.setLevel(ILogger.ERROR);
- // logger.setLevel(ILogger.DEBUG);
- logger.setLevel(ILogger.INFO);
- }
-
- static boolean loaded = false;
-
- private MTApplication app;
-
- private int sunAwtCanvasHandle;
-
- private int awtFrameHandle;
-
- private Native_WM_TOUCH_Event wmTouchEvent;
-
- private boolean initialized;
-
- private boolean success;
-
- private HashMap<Integer, Long> touchToCursorID;
-
- private static final String dllName32 = "Win7Touch";
-
- private static final String dllName64 = "Win7Touch64";
-
- private static final String canvasClassName = "SunAwtCanvas";
-
-
- // NATIVE METHODS //
- private native int findWindow(String tmpTitle, String subWindowTitle);
-
- private native boolean init(long HWND);
-
- private native boolean getSystemMetrics();
-
- private native boolean quit();
-
- private native boolean pollEvent(Native_WM_TOUCH_Event myEvent);
- // NATIVE METHODS //
-
-
- //TODO remove points[] array? -> if digitizer has more than 255 touchpoints we could get out of bounds in points[]
- //TODO did we "delete [] ti;" in wndProc?
- //TODO- check dpi, if higher than 96 - if the screen is set to High DPI (more than 96 DPI),
- // you may also need to divide the values by 96 and multiply by the current DPI. (or already handled by ScreenToClient()?)
- //TODO try again getWindow() in windows -> no success in all thread (we probably need to do it in the awt-windows thread?)
-
- //TODO make singleton to avoid multiple instances
-
- /**
- * Instantiates a new win7 native touch source.
- *
- * @param mtApp the mt app
- */
- public Win7NativeTouchSource(MTApplication mtApp) {
- super(mtApp);
- this.app = mtApp;
- this.success = false;
-
- String platform = System.getProperty("os.name").toLowerCase();
- logger.debug("Platform: \"" + platform + "\"");
-
- // /*
- if (!platform.contains("windows 7")) {
- logger.error("Win7NativeTouchSource input source can only be used on platforms running windows 7!");
- return;
- }
-
- if (!loaded){
- loaded = true;
- String dllName = (MT4jSettings.getInstance().getArchitecture() == MT4jSettings.ARCHITECTURE_32_BIT)? dllName32 : dllName64;
- System.loadLibrary(dllName);
- // System.load(System.getProperty("user.dir") + File.separator + dllName + ".dll");
- }else{
- logger.error("Win7NativeTouchSource may only be instantiated once.");
- return;
- }
-
- boolean touchAvailable = this.getSystemMetrics();
- if (!touchAvailable){
- logger.error("Windows 7 Touch Input currently not available!");
- return;
- }else{
- logger.info("Windows 7 Touch Input available.");
- }
- // */
-
- wmTouchEvent = new Native_WM_TOUCH_Event();
- wmTouchEvent.id = -1;
- wmTouchEvent.type = -1;
- wmTouchEvent.x = -1;
- wmTouchEvent.y = -1;
-
- initialized = false;
-
- touchToCursorID = new HashMap<Integer, Long>();
-
- this.getNativeWindowHandles();
- success = true;
-
- Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
- public void run() {
- if (isSuccessfullySetup()){
- logger.debug("Cleaning up Win7 touch source..");
- quit();
- }
- }
- }));
- }
-
-
- // private boolean addedArtificalTouchDown = false; //FIXME REMOVE
-
- public boolean isSuccessfullySetup() {
- return success;
- }
-
-
- @Override
- public void pre(){ //we dont have to call registerPre() again (already in superclass and called there)
- if (initialized){ //Only poll events if native c++ core was initialized successfully
- while (pollEvent(wmTouchEvent)) {
- /*
- //FIXME TEST, make a artifical TOUCH_DOWN event REMOVE LATER!
- if (!addedArtificalTouchDown){
- addedArtificalTouchDown = true;
- wmTouchEvent.type = Native_WM_TOUCH_Event.TOUCH_DOWN;
- }
- */
-
- switch (wmTouchEvent.type) {
- case Native_WM_TOUCH_Event.TOUCH_DOWN:{
- // logger.debug("TOUCH_DOWN ==> ID:" + wmTouchEvent.id + " x:" + wmTouchEvent.x + " y:" + wmTouchEvent.y);
-
- InputCursor c = new InputCursor();
- long cursorID = c.getId();
- MTWin7TouchInputEvt touchEvt = new MTWin7TouchInputEvt(this, wmTouchEvent.x, wmTouchEvent.y, wmTouchEvent.contactSizeX, wmTouchEvent.contactSizeY, MTFingerInputEvt.INPUT_STARTED, c);
- int touchID = wmTouchEvent.id;
- ActiveCursorPool.getInstance().putActiveCursor(cursorID, c);
- touchToCursorID.put(touchID, cursorID);
- this.enqueueInputEvent(touchEvt);
-
- break;
- }case Native_WM_TOUCH_Event.TOUCH_MOVE:{
- // logger.debug("TOUCH_MOVE ==> ID:" + wmTouchEvent.id + " x:" + wmTouchEvent.x + " y:" + wmTouchEvent.y);
- // System.out.println("Contact area X:" + wmTouchEvent.contactSizeX + " Y:" + wmTouchEvent.contactSizeY);
-
- Long cursorID = touchToCursorID.get(wmTouchEvent.id);
- if (cursorID != null){
- InputCursor c = ActiveCursorPool.getInstance().getActiveCursorByID(cursorID);
- if (c != null){
- MTWin7TouchInputEvt te = new MTWin7TouchInputEvt(this, wmTouchEvent.x, wmTouchEvent.y, wmTouchEvent.contactSizeX, wmTouchEvent.contactSizeY, MTFingerInputEvt.INPUT_UPDATED, c);
- this.enqueueInputEvent(te);
- }
- }
-
- break;
- }case Native_WM_TOUCH_Event.TOUCH_UP:{
- // logger.debug("TOUCH_UP ==> ID:" + wmTouchEvent.id + " x:" + wmTouchEvent.x + " y:" + wmTouchEvent.y);
-
- Long cursorID = touchToCursorID.get(wmTouchEvent.id);
- if (cursorID != null){
- InputCursor c = ActiveCursorPool.getInstance().getActiveCursorByID(cursorID);
- if (c != null){
- MTWin7TouchInputEvt te = new MTWin7TouchInputEvt(this, wmTouchEvent.x, wmTouchEvent.y, wmTouchEvent.contactSizeX, wmTouchEvent.contactSizeY, MTFingerInputEvt.INPUT_ENDED, c);
- this.enqueueInputEvent(te);
- }
- ActiveCursorPool.getInstance().removeCursor(cursorID);
- touchToCursorID.remove(wmTouchEvent.id);
- }
-
- break;
- }default:
- break;
- }
- }
- }
-
- super.pre();
- }
-
-
-
- private void getNativeWindowHandles(){
- if (app.frame == null){
- logger.error("applet.frame == null! -> cant set up windows 7 input!");
- return;
- }
-
- //TODO kind of hacky way of getting the HWND..but there seems to be no real alternative(?)
- final String oldTitle = app.frame.getTitle();
- final String tmpTitle = "Initializing Native Windows 7 Touch Input " + Math.random();
- app.frame.setTitle(tmpTitle);
- logger.debug("Temp title: " + tmpTitle);
-
- //FIXME TEST REMOVE
- //Window window = SwingUtilities.getWindowAncestor(app);
- // AWTUtilities.setWindowOpacity(window, 0.5f); //works!
-
- //Invokelater because of some crash issue
- //-> maybe we need to wait a frame until windows is informed of the window name change
- SwingUtilities.invokeLater(new Runnable() {
- public void run() {
- int awtCanvasHandle = 0;
- try {
- // //TODO also search for window class?
- awtCanvasHandle = (int)findWindow(tmpTitle, canvasClassName);
- setSunAwtCanvasHandle(awtCanvasHandle);
- } catch (Exception e) {
- System.err.println(e.getMessage());
- }
- app.frame.setTitle(oldTitle); //Reset title text
- }
- });
- }
-
-
- private void setTopWindowHandle(int HWND){
- if (HWND > 0){
- this.awtFrameHandle = HWND;
- logger.debug("-> Found AWT HWND: " + this.awtFrameHandle);
- }else{
- logger.error("-> Couldnt retrieve the top window handle!");
- }
- }
-
-
- private void setSunAwtCanvasHandle(int HWND){
- if (HWND > 0){
- this.sunAwtCanvasHandle = HWND;
- logger.debug("-> Found SunAwtCanvas HWND: " + this.sunAwtCanvasHandle);
- //Initialize c++ core (subclass etc)
- this.init(this.sunAwtCanvasHandle);
- this.initialized = true;
- }else{
- logger.error("-> Couldnt retrieve the SunAwtCanvas handle!");
- }
- }
-
- private class Native_WM_TOUCH_Event{
- //can be real enums in Java 5.0.
- /** The Constant TOUCH_DOWN. */
- public static final int TOUCH_DOWN = 0;
-
- /** The Constant TOUCH_MOVE. */
- public static final int TOUCH_MOVE = 1;
-
- /** The Constant TOUCH_UP. */
- public static final int TOUCH_UP = 2;
-
- /** The type. */
- public int type;
-
- /** The id. */
- public int id;
-
- /** The x value. */
- public int x;
-
- /** The y value. */
- public int y;
-
- /** The contact size area X dimension */
- public int contactSizeX;
-
- /** The contact size area Y dimension */
- public int contactSizeY;
- }
-
- }