Subversion Repositories AndroidProjects

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
538 chris 1
/***********************************************************************
2
 * mt4j Copyright (c) 2008 - 2010 Christopher Ruff, Fraunhofer-Gesellschaft All rights reserved.
3
 *  
4
 *   This program is free software: you can redistribute it and/or modify
5
 *   it under the terms of the GNU General Public License as published by
6
 *   the Free Software Foundation, either version 3 of the License, or
7
 *   (at your option) any later version.
8
 *
9
 *   This program is distributed in the hope that it will be useful,
10
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 *   GNU General Public License for more details.
13
 *
14
 *   You should have received a copy of the GNU General Public License
15
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
 *
17
 ***********************************************************************/
18
package org.mt4j.input.inputSources;
19
 
20
import java.util.HashMap;
21
 
22
import javax.swing.SwingUtilities;
23
 
24
import org.mt4j.AbstractMTApplication;
25
import org.mt4j.input.inputData.ActiveCursorPool;
26
import org.mt4j.input.inputData.InputCursor;
27
import org.mt4j.input.inputData.MTFingerInputEvt;
28
import org.mt4j.input.inputData.MTWin7TouchInputEvt;
29
import org.mt4j.util.MT4jSettings;
30
import org.mt4j.util.logging.ILogger;
31
import org.mt4j.util.logging.MTLoggerFactory;
32
 
33
/**
34
 * Input source for native Windows 7 WM_TOUCH messages for single/multi-touch.
35
 * <br>Be careful to instantiate this class only ONCE!
36
 *
37
 * @author C.Ruff
38
 *
39
 */
40
public class Win7NativeTouchSource extends AbstractInputSource {
41
        /** The Constant logger. */
42
        private static final ILogger logger = MTLoggerFactory.getLogger(Win7NativeTouchSource.class.getName());
43
        static{
44
//              logger.setLevel(ILogger.ERROR);
45
//              logger.setLevel(ILogger.DEBUG);
46
                logger.setLevel(ILogger.INFO);
47
        }
48
 
49
        static boolean loaded = false;
50
 
51
        private AbstractMTApplication app;
52
 
53
        private int sunAwtCanvasHandle;
54
 
55
        private int awtFrameHandle;
56
 
57
        private Native_WM_TOUCH_Event wmTouchEvent;
58
 
59
        private boolean initialized;
60
 
61
        private boolean success;
62
 
63
        private HashMap<Integer, Long> touchToCursorID;
64
 
65
        private static final String dllName32 = "Win7Touch";
66
 
67
        private static final String dllName64 = "Win7Touch64";
68
 
69
        private static final String canvasClassName = "SunAwtCanvas";
70
 
71
 
72
        // NATIVE METHODS //
73
        private native int findWindow(String tmpTitle, String subWindowTitle);
74
 
75
        private native boolean init(long HWND);
76
 
77
        private native boolean getSystemMetrics();
78
 
79
        private native boolean quit();
80
 
81
        private native boolean pollEvent(Native_WM_TOUCH_Event myEvent);
82
        // NATIVE METHODS //
83
 
84
 
85
        //TODO remove points[] array? -> if digitizer has more than 255 touchpoints we could get out of bounds in points[]
86
        //TODO did we "delete [] ti;" in wndProc?
87
        //TODO- check dpi, if higher than 96 - if the screen is set to High DPI (more than 96 DPI),
88
        // you may also need to divide the values by 96 and multiply by the current DPI. (or already handled by ScreenToClient()?)
89
        //TODO try again getWindow() in windows -> no success in all thread (we probably need to do it in the awt-windows thread?)
90
 
91
        //TODO make singleton to avoid multiple instances
92
 
93
        /**
94
         * Instantiates a new win7 native touch source.
95
         *
96
         * @param mtApp the mt app
97
         */
98
        public Win7NativeTouchSource(AbstractMTApplication mtApp) {
99
                super(mtApp);
100
                this.app = mtApp;
101
                this.success = false;
102
 
103
                String platform = System.getProperty("os.name").toLowerCase();
104
                logger.debug("Platform: \"" + platform + "\"");
105
 
106
//              /*
107
                if (!platform.contains("windows 7")) {
108
                        logger.error("Win7NativeTouchSource input source can only be used on platforms running windows 7!");
109
                        return;
110
                }
111
 
112
                if (!loaded){
113
                        loaded = true;
114
                        String dllName = (MT4jSettings.getInstance().getArchitecture() == MT4jSettings.ARCHITECTURE_32_BIT)? dllName32 : dllName64;
115
                        System.loadLibrary(dllName);
116
//                      System.load(System.getProperty("user.dir") + File.separator + dllName + ".dll");
117
                }else{
118
                        logger.error("Win7NativeTouchSource may only be instantiated once.");
119
                        return;
120
                }
121
 
122
                boolean touchAvailable = this.getSystemMetrics();
123
                if (!touchAvailable){
124
                        logger.error("Windows 7 Touch Input currently not available!");
125
                        return;
126
                }else{
127
                        logger.info("Windows 7 Touch Input available.");
128
                }
129
//              */
130
 
131
                wmTouchEvent = new Native_WM_TOUCH_Event();
132
                wmTouchEvent.id = -1;
133
                wmTouchEvent.type = -1;
134
                wmTouchEvent.x = -1;
135
                wmTouchEvent.y = -1;
136
 
137
                initialized = false;
138
 
139
                touchToCursorID = new HashMap<Integer, Long>();
140
 
141
                this.getNativeWindowHandles();
142
                success = true;
143
 
144
                Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
145
                        public void run() {
146
                                if (isSuccessfullySetup()){
147
                                        logger.debug("Cleaning up Win7 touch source..");
148
                                        quit();
149
                                }
150
                        }
151
                }));
152
        }
153
 
154
 
155
//      private boolean addedArtificalTouchDown = false; //FIXME REMOVE
156
 
157
        public boolean isSuccessfullySetup() {
158
                return success;
159
        }
160
 
161
 
162
        @Override
163
        public void pre(){ //we dont have to call registerPre() again (already in superclass and called there)
164
                if (initialized){ //Only poll events if native c++ core was initialized successfully
165
                        while (pollEvent(wmTouchEvent)) {
166
                                /*
167
                                 //FIXME TEST, make a artifical TOUCH_DOWN event REMOVE LATER!
168
                                if (!addedArtificalTouchDown){
169
                                        addedArtificalTouchDown = true;
170
                                        wmTouchEvent.type = Native_WM_TOUCH_Event.TOUCH_DOWN;
171
                                }
172
                                 */
173
 
174
                                switch (wmTouchEvent.type) {
175
                                case Native_WM_TOUCH_Event.TOUCH_DOWN:{
176
//                                      logger.debug("TOUCH_DOWN ==> ID:" + wmTouchEvent.id + " x:" +  wmTouchEvent.x + " y:" +  wmTouchEvent.y);
177
 
178
                                        InputCursor c = new InputCursor();
179
                                        long cursorID = c.getId();
180
                                        MTWin7TouchInputEvt touchEvt = new MTWin7TouchInputEvt(this, wmTouchEvent.x, wmTouchEvent.y, wmTouchEvent.contactSizeX, wmTouchEvent.contactSizeY, MTFingerInputEvt.INPUT_STARTED, c);
181
                                        int touchID = wmTouchEvent.id;
182
                                        ActiveCursorPool.getInstance().putActiveCursor(cursorID, c);
183
                                        touchToCursorID.put(touchID, cursorID);
184
                                        this.enqueueInputEvent(touchEvt);
185
 
186
                                        break;
187
                                }case Native_WM_TOUCH_Event.TOUCH_MOVE:{
188
//                                      logger.debug("TOUCH_MOVE ==> ID:" + wmTouchEvent.id + " x:" +  wmTouchEvent.x + " y:" +  wmTouchEvent.y);
189
//                                      System.out.println("Contact area X:" + wmTouchEvent.contactSizeX + " Y:" + wmTouchEvent.contactSizeY);
190
 
191
                                        Long cursorID = touchToCursorID.get(wmTouchEvent.id);
192
                                        if (cursorID != null){
193
                                                InputCursor c = ActiveCursorPool.getInstance().getActiveCursorByID(cursorID);
194
                                                if (c != null){
195
                                                        MTWin7TouchInputEvt te = new MTWin7TouchInputEvt(this, wmTouchEvent.x, wmTouchEvent.y, wmTouchEvent.contactSizeX, wmTouchEvent.contactSizeY, MTFingerInputEvt.INPUT_UPDATED, c);
196
                                                        this.enqueueInputEvent(te);    
197
                                                }
198
                                        }
199
 
200
                                        break;
201
                                }case Native_WM_TOUCH_Event.TOUCH_UP:{
202
//                                      logger.debug("TOUCH_UP ==> ID:" + wmTouchEvent.id + " x:" +  wmTouchEvent.x + " y:" +  wmTouchEvent.y);
203
 
204
                                        Long cursorID = touchToCursorID.get(wmTouchEvent.id);
205
                                        if (cursorID != null){
206
                                                InputCursor c = ActiveCursorPool.getInstance().getActiveCursorByID(cursorID);
207
                                                if (c != null){
208
                                                        MTWin7TouchInputEvt te = new MTWin7TouchInputEvt(this, wmTouchEvent.x, wmTouchEvent.y, wmTouchEvent.contactSizeX, wmTouchEvent.contactSizeY, MTFingerInputEvt.INPUT_ENDED, c);
209
                                                        this.enqueueInputEvent(te);
210
                                                }
211
                                                ActiveCursorPool.getInstance().removeCursor(cursorID);
212
                                                touchToCursorID.remove(wmTouchEvent.id);
213
                                        }
214
 
215
                                        break;
216
                                }default:
217
                                        break;
218
                                }
219
                        }
220
                }
221
 
222
                super.pre();
223
        }
224
 
225
 
226
 
227
        private void getNativeWindowHandles(){
228
                if (app.frame == null){
229
                        logger.error("applet.frame == null! -> cant set up windows 7 input!");
230
                        return;
231
                }
232
 
233
                //TODO kind of hacky way of getting the HWND..but there seems to be no real alternative(?)
234
                final String oldTitle = app.frame.getTitle();
235
                final String tmpTitle = "Initializing Native Windows 7 Touch Input " + Math.random();
236
                app.frame.setTitle(tmpTitle);
237
                logger.debug("Temp title: " + tmpTitle);
238
 
239
                //FIXME TEST REMOVE
240
                //Window window = SwingUtilities.getWindowAncestor(app);
241
//              AWTUtilities.setWindowOpacity(window, 0.5f); //works!
242
 
243
                //Invokelater because of some crash issue 
244
                //-> maybe we need to wait a frame until windows is informed of the window name change
245
                SwingUtilities.invokeLater(new Runnable() {
246
                        public void run() {
247
                                int awtCanvasHandle = 0;
248
                                try {
249
//                                      //TODO also search for window class?
250
                                        awtCanvasHandle = (int)findWindow(tmpTitle, canvasClassName);
251
                                        setSunAwtCanvasHandle(awtCanvasHandle);
252
                                } catch (Exception e) {
253
                                        System.err.println(e.getMessage());
254
                                }
255
                                app.frame.setTitle(oldTitle); //Reset title text
256
                        }
257
                });
258
        }
259
 
260
 
261
        private void setTopWindowHandle(int HWND){
262
                if (HWND > 0){
263
                        this.awtFrameHandle = HWND;
264
                        logger.debug("-> Found AWT HWND: " + this.awtFrameHandle);
265
                }else{
266
                        logger.error("-> Couldnt retrieve the top window handle!");
267
                }
268
        }
269
 
270
 
271
        private void setSunAwtCanvasHandle(int HWND){
272
                if (HWND > 0){
273
                        this.sunAwtCanvasHandle = HWND;
274
                        logger.debug("-> Found SunAwtCanvas HWND: " + this.sunAwtCanvasHandle);
275
                        //Initialize c++ core (subclass etc)
276
                        this.init(this.sunAwtCanvasHandle);
277
                        this.initialized = true;
278
                }else{
279
                        logger.error("-> Couldnt retrieve the SunAwtCanvas handle!");
280
                }
281
        }
282
 
283
        private class Native_WM_TOUCH_Event{
284
                //can be real enums in Java 5.0.
285
            /** The Constant TOUCH_DOWN. */
286
            public static final int TOUCH_DOWN = 0;
287
 
288
            /** The Constant TOUCH_MOVE. */
289
            public static final int TOUCH_MOVE = 1;
290
 
291
            /** The Constant TOUCH_UP. */
292
            public static final int TOUCH_UP = 2;
293
 
294
            /** The type. */
295
            public int type;
296
 
297
            /** The id. */
298
            public int id;
299
 
300
            /** The x value. */
301
            public int x;
302
 
303
            /** The y value. */
304
            public int y;
305
 
306
            /** The contact size area X dimension */
307
            public int contactSizeX;
308
 
309
            /** The contact size area Y dimension */
310
            public int contactSizeY;
311
        }
312
 
313
}