001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Michael Danilov
019: * @version $Revision$
020: */package org.apache.harmony.awt.wtk.windows;
021:
022: import java.awt.Frame;
023: import java.awt.Insets;
024: import java.awt.Point;
025: import java.awt.Rectangle;
026: import java.awt.event.ComponentEvent;
027: import java.awt.event.FocusEvent;
028: import java.awt.event.InputEvent;
029: import java.awt.event.KeyEvent;
030: import java.awt.event.MouseEvent;
031: import java.awt.event.PaintEvent;
032: import java.awt.event.WindowEvent;
033: import org.apache.harmony.awt.gl.MultiRectArea;
034: import org.apache.harmony.awt.nativebridge.Int8Pointer;
035: import org.apache.harmony.awt.nativebridge.NativeBridge;
036: import org.apache.harmony.awt.nativebridge.windows.Win32;
037: import org.apache.harmony.awt.nativebridge.windows.WindowsDefs;
038: import org.apache.harmony.awt.wtk.NativeEvent;
039:
040: final class WinEvent extends NativeEvent implements WindowsDefs {
041: static final int WM_AWAKE = WM_USER;
042:
043: static final Win32 win32 = Win32.getInstance();
044: static final NativeBridge bridge = NativeBridge.getInstance();
045:
046: private static final long sizeofRECT = win32.createRECT(0).size();
047:
048: // missing const from header "tmschema.h"
049: private static final int WM_THEMECHANGED = 0x031A;
050:
051: private Rectangle clipRect;
052: private MultiRectArea clipRgn;
053: private int msg;
054:
055: private long wParam;
056: private long lParam;
057:
058: private char lastChar;
059:
060: private final WinWindowFactory factory;
061:
062: @Override
063: public boolean getTrigger() {
064: return ((eventId == MouseEvent.MOUSE_RELEASED) && (mouseButton == MouseEvent.BUTTON3));
065: }
066:
067: @Override
068: public MultiRectArea getClipRects() {
069: if (clipRgn == null) {
070: Insets insets = factory.getInsets(windowId);
071: int dx = insets.left;
072: int dy = insets.top;
073:
074: long hRgn = win32.CreateRectRgn(0, 0, 0, 0);
075: int type = win32.GetUpdateRgn(windowId, hRgn, 0);
076: long rgnToValidate = type != NULLREGION ? hRgn : 0;
077: win32.ValidateRgn(windowId, rgnToValidate);
078:
079: Win32.RECT nativeRect = win32.createRECT(false);
080: win32.GetRgnBox(hRgn, nativeRect);
081: clipRect = factory.getRectBounds(nativeRect);
082: clipRect.translate(dx, dy);
083:
084: switch (type) {
085: case COMPLEXREGION: {
086: clipRgn = decodeComplexRgn(hRgn, dx, dy);
087: break;
088: }
089: case SIMPLEREGION:
090: clipRgn = new MultiRectArea(clipRect);
091: break;
092: case NULLREGION:
093: clipRgn = new MultiRectArea();
094: break;
095: }
096: win32.DeleteObject(hRgn);
097: }
098: return clipRgn;
099: }
100:
101: @Override
102: public Rectangle getClipBounds() {
103: if (clipRect == null) {
104: getClipRects();
105: }
106: return clipRect;
107: }
108:
109: @Override
110: public Rectangle getWindowRect() {
111: if (windowRect == null) {
112: windowRect = factory.getWindowBounds(windowId);
113: }
114: return windowRect;
115: }
116:
117: @Override
118: public Insets getInsets() {
119: return factory.getInsets(windowId);
120: }
121:
122: @Override
123: public char getLastChar() {
124: return lastChar;
125: }
126:
127: WinEvent(long hwnd, int msg, long wParam, long lParam,
128: long lastTime, StringBuffer lastTranslation, char lastChar,
129: WinWindowFactory factory) {
130: this .factory = factory;
131: this .windowId = hwnd;
132: this .msg = msg;
133: this .wParam = wParam;
134: this .lParam = lParam;
135: this .time = lastTime;
136: keyInfo.setKeyChars(lastTranslation);
137: if (keyInfo.keyChars.length() == 0) {
138: keyInfo.keyChars.append(KeyEvent.CHAR_UNDEFINED);
139: }
140: this .lastChar = lastChar;
141: eventId = ID_PLATFORM;
142:
143: if (hwnd == factory.eventQueue.getJavaWindow()) {
144: if ((msg == WM_THEMECHANGED) || (msg == WM_SYSCOLORCHANGE)
145: || (msg == WM_SETTINGCHANGE)) {
146: // TODO: handle this
147:
148: if (msg == WM_THEMECHANGED) {
149: factory.eventQueue.getThemeMap().refresh();
150: factory.eventQueue.systemProperties
151: .getXPTheme(null);
152: }
153: eventId = ID_THEME_CHANGED;
154: }
155: } else if (((msg >= WM_MOUSEFIRST) && (msg <= WM_MOUSELAST))
156: || (msg == WM_MOUSELEAVE)) {
157: processMouse(msg);
158: } else if (msg == WM_CHAR) {
159: processChar();
160: } else if (msg == WM_IME_KEYDOWN) {
161: processKey(msg);
162: } else if ((msg >= WM_KEYFIRST) && (msg <= WM_KEYLAST)) {
163: processKey(msg);
164: } else if ((msg == WM_KILLFOCUS) || (msg == WM_SETFOCUS)) {
165: processFocus(msg);
166: } else if (msg == WM_PAINT) {
167: eventId = PaintEvent.PAINT;
168: processPaint();
169: } else if (msg == WM_SIZE) {
170: processSize();
171: } else if (msg == WM_MOVE) {
172: processMove();
173: } else if (msg == WM_CLOSE) {
174: eventId = WindowEvent.WINDOW_CLOSING;
175: } else if (msg == WM_MOUSEACTIVATE) {
176: processActivation();
177: } else if (msg == WM_CAPTURECHANGED) {
178: if (lParam == 0) {
179: eventId = ID_MOUSE_GRAB_CANCELED;
180: }
181: } else if (msg == WM_CREATE) {
182: eventId = ID_CREATED;
183: } else if (msg == WM_SHOWWINDOW) {
184: processShowWindow();
185: } else if (msg == WM_STYLECHANGED) {
186: processStyleChanged();
187: } else if (msg == WM_THEMECHANGED) {
188: processThemeChanged();
189: } else if (msg == WM_INPUTLANGCHANGEREQUEST) {
190: WinIM.onInputLangChange(lParam);
191: }
192: }
193:
194: @Override
195: public String toString() {
196: return "hwnd=0x" + Long.toHexString(windowId) + ", msg=0x" + Integer.toHexString(msg); //$NON-NLS-1$ //$NON-NLS-2$
197: }
198:
199: private void processChar() {
200: keyInfo.keyChars.setLength(0);
201: keyInfo.keyChars.append((char) wParam);
202: eventId = KeyEvent.KEY_PRESSED;
203: }
204:
205: private void processThemeChanged() {
206: eventId = ID_THEME_CHANGED;
207: }
208:
209: private void processStyleChanged() {
210: if ((wParam & GWL_STYLE) != 0) {
211: Win32.STYLESTRUCT ss = win32.createSTYLESTRUCT(lParam);
212: int oldStyle = ss.get_styleOld();
213: int newStyle = ss.get_styleNew();
214:
215: if ((oldStyle & WS_SIZEBOX) != (newStyle & WS_SIZEBOX)) {
216: eventId = ID_INSETS_CHANGED;
217: // Update native decorations
218: int flags = SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE
219: | SWP_NOZORDER | SWP_NOACTIVATE;
220: win32.SetWindowPos(windowId, 0, 0, 0, 0, 0, flags);
221: }
222: }
223: }
224:
225: private void processShowWindow() {
226: WinWindow win = factory.getWinWindowById(windowId);
227: if (wParam != 0 && !win.child) {
228: eventId = ID_INSETS_CHANGED;
229: }
230: }
231:
232: private void processSize() {
233: WinWindow win = factory.getWinWindowById(windowId);
234:
235: if (wParam == SIZE_RESTORED) {
236: if (!factory.isWindowBeingCreated()) {
237: if (win.isIconified()) {
238: win.setIconified(false);
239: windowState = Frame.NORMAL;
240: }
241: if (win.isMaximized()) {
242: win.setMaximized(false);
243: windowState = Frame.NORMAL;
244: }
245: }
246: eventId = ID_BOUNDS_CHANGED;
247: } else if (wParam == SIZE_MAXIMIZED) {
248: win.setIconified(false);
249: win.setMaximized(true);
250: windowState = Frame.MAXIMIZED_BOTH;
251: eventId = ID_BOUNDS_CHANGED;
252: } else if (wParam == SIZE_MINIMIZED) {
253: win.setIconified(true);
254: windowState = Frame.ICONIFIED;
255: if (win.isMaximized()) {
256: windowState |= Frame.MAXIMIZED_BOTH;
257: }
258: eventId = WindowEvent.WINDOW_STATE_CHANGED;
259: }
260: }
261:
262: private void processMove() {
263: WinWindow win = factory.getWinWindowById(windowId);
264:
265: if (win32.IsIconic(windowId) == 0) {
266: if (!win.isIconified()) {
267: eventId = ComponentEvent.COMPONENT_MOVED;
268: } else {
269: eventId = ID_INSETS_CHANGED;
270: }
271: }
272: }
273:
274: private void processFocus(int msg) {
275: eventId = (msg == WM_SETFOCUS) ? FocusEvent.FOCUS_GAINED
276: : FocusEvent.FOCUS_LOST;
277: otherWindowId = wParam;
278: }
279:
280: private void processActivation() {
281: //translate activation events into focus events only for top-levels
282: WinWindow wnd = factory.getWinWindowById(windowId);
283: if (wnd.isFocusable()) {
284: if (!wnd.child) {
285: //set focus on top-level
286: win32.SetFocus(windowId);
287: } else {
288: //activate top-level ancestor
289: long ancestorHwnd = win32
290: .GetAncestor(windowId, GA_ROOT);
291: if (win32.GetActiveWindow() != ancestorHwnd) {
292: win32.SetActiveWindow(ancestorHwnd);
293: }
294:
295: // check for embedded window, pass focus into it
296: if (factory.getWinWindowById(ancestorHwnd) == null) {
297: for (long curHwnd = windowId; curHwnd != 0;) {
298: long parentHwnd = win32.GetParent(curHwnd);
299: if (factory.getWinWindowById(parentHwnd) == null) {
300: win32.SetFocus(curHwnd);
301: break;
302: }
303: curHwnd = parentHwnd;
304: }
305: }
306:
307: }
308: }
309:
310: }
311:
312: private void processPaint() {
313: getClipRects();
314: }
315:
316: private MultiRectArea decodeComplexRgn(long hRgn, int dx, int dy) {
317: int nBytes = win32.GetRegionData(hRgn, 0, 0);
318: Int8Pointer rgnDataPtr = bridge
319: .createInt8Pointer(nBytes, false);
320:
321: win32.GetRegionData(hRgn, nBytes, rgnDataPtr.lock());
322: rgnDataPtr.unlock();
323: Win32.RGNDATA rgnData = win32.createRGNDATA(rgnDataPtr);
324: Win32.RGNDATAHEADER rdh = rgnData.get_rdh();
325: Int8Pointer bufferPtr = rgnData.get_Buffer();
326:
327: int nCount = rdh.get_nCount();
328: Rectangle rgn[] = new Rectangle[nCount];
329:
330: long rawBufferPtr = bufferPtr.lock();
331: for (int i = 0; i < nCount; i++) {
332: Win32.RECT nr = win32.createRECT(rawBufferPtr + i
333: * sizeofRECT);
334: Rectangle rect = factory.getRectBounds(nr);
335: rect.translate(dx, dy);
336: rgn[i] = rect;
337: }
338: bufferPtr.unlock();
339:
340: return new MultiRectArea(rgn);
341: }
342:
343: private void processKey(int msg) {
344: if ((msg == WM_KEYDOWN) || (msg == WM_SYSKEYDOWN)
345: || (msg == WM_IME_KEYDOWN)) {
346: eventId = KeyEvent.KEY_PRESSED;
347: } else if ((msg == WM_KEYUP) || (msg == WM_SYSKEYUP)) {
348: eventId = KeyEvent.KEY_RELEASED;
349: }
350:
351: modifiers |= translateKeyModifiers();
352: keyInfo.keyLocation = computeKeyLocation();
353: keyInfo.vKey = translateVKey();
354: }
355:
356: private int translateVKey() {
357: int vKey = (int) wParam;
358:
359: switch (vKey) {
360: case VK_RETURN:
361: vKey = KeyEvent.VK_ENTER;
362: break;
363: case VK_LWIN:
364: case VK_RWIN:
365: case VK_APPS:
366: vKey = KeyEvent.VK_UNDEFINED;
367: break;
368: case VK_INSERT:
369: vKey = KeyEvent.VK_INSERT;
370: break;
371: case VK_DELETE:
372: vKey = KeyEvent.VK_DELETE;
373: break;
374: case VK_OEM_1:
375: vKey = KeyEvent.VK_SEMICOLON;
376: break;
377: case VK_OEM_2:
378: vKey = KeyEvent.VK_SLASH;
379: break;
380: case VK_OEM_4:
381: vKey = KeyEvent.VK_OPEN_BRACKET;
382: break;
383: case VK_OEM_5:
384: vKey = KeyEvent.VK_BACK_SLASH;
385: break;
386: case VK_OEM_6:
387: vKey = KeyEvent.VK_CLOSE_BRACKET;
388: break;
389: case VK_OEM_COMMA:
390: vKey = KeyEvent.VK_COMMA;
391: break;
392: case VK_OEM_PERIOD:
393: vKey = KeyEvent.VK_PERIOD;
394: break;
395: case VK_OEM_MINUS:
396: vKey = KeyEvent.VK_MINUS;
397: break;
398: case VK_OEM_PLUS:
399: vKey = KeyEvent.VK_EQUALS;
400: break;
401: }
402: return vKey;
403: }
404:
405: private int translateKeyModifiers() {
406: int modifiers = 0;
407: modifiers |= ((win32.GetKeyState(VK_SHIFT) & 0x80) != 0) ? InputEvent.SHIFT_DOWN_MASK
408: : 0;
409: modifiers |= ((win32.GetKeyState(VK_CONTROL) & 0x80) != 0) ? InputEvent.CTRL_DOWN_MASK
410: : 0;
411: modifiers |= ((win32.GetKeyState(VK_MENU) & 0x80) != 0) ? InputEvent.ALT_DOWN_MASK
412: : 0;
413: modifiers |= ((win32.GetKeyState(VK_LBUTTON) & 0x80) != 0) ? InputEvent.BUTTON1_DOWN_MASK
414: : 0;
415: modifiers |= ((win32.GetKeyState(VK_MBUTTON) & 0x80) != 0) ? InputEvent.BUTTON2_DOWN_MASK
416: : 0;
417: modifiers |= ((win32.GetKeyState(VK_RBUTTON) & 0x80) != 0) ? InputEvent.BUTTON3_DOWN_MASK
418: : 0;
419: return modifiers;
420: }
421:
422: private int computeKeyLocation() {
423: int winVKey = (int) wParam;
424:
425: if ((winVKey == VK_MENU) || (winVKey == VK_CONTROL)) {
426: return ((lParam & 0x1000000) > 0) ? KeyEvent.KEY_LOCATION_RIGHT
427: : KeyEvent.KEY_LOCATION_LEFT;
428: }
429: if (winVKey == VK_SHIFT) {
430: if (((((int) lParam) >> 16) & 0xff) == win32
431: .MapVirtualKeyW(VK_SHIFT, 0)) {
432: return KeyEvent.KEY_LOCATION_LEFT;
433: }
434: return KeyEvent.KEY_LOCATION_RIGHT;
435: }
436: if (((winVKey >= VK_NUMPAD0) && (winVKey <= VK_NUMPAD9))
437: || (winVKey == VK_NUMLOCK) || (winVKey == VK_DECIMAL)
438: || (winVKey == VK_DIVIDE) || (winVKey == VK_MULTIPLY)
439: || (winVKey == VK_SUBTRACT) || (winVKey == VK_ADD)
440: || (winVKey == VK_CLEAR)) {
441: return KeyEvent.KEY_LOCATION_NUMPAD;
442: }
443: if ((winVKey == VK_HOME) || (winVKey == VK_END)
444: || (winVKey == VK_UP) || (winVKey == VK_DOWN)
445: || (winVKey == VK_LEFT) || (winVKey == VK_RIGHT)
446: || (winVKey == VK_PRIOR) || (winVKey == VK_NEXT)
447: || (winVKey == VK_INSERT) || (winVKey == VK_DELETE)) {
448: return ((lParam & 0x1000000) > 0) ? KeyEvent.KEY_LOCATION_STANDARD
449: : KeyEvent.KEY_LOCATION_NUMPAD;
450: }
451: if (winVKey == VK_RETURN) {
452: return ((lParam & 0x1000000) > 0) ? KeyEvent.KEY_LOCATION_NUMPAD
453: : KeyEvent.KEY_LOCATION_STANDARD;
454: }
455: return KeyEvent.KEY_LOCATION_STANDARD;
456: }
457:
458: private void processMouse(int msg) {
459: if (msg == WM_MOUSELEAVE) {
460: Win32.POINT nativePoint = win32.createPOINT(false);
461: win32.GetCursorPos(nativePoint);
462: screenPos = new Point(nativePoint.get_x(), nativePoint
463: .get_y());
464: eventId = MouseEvent.MOUSE_EXITED;
465: modifiers |= translateKeyModifiers();
466: factory.lastHwndUnderPointer = 0;
467: } else {
468: setMouseEventIDAndButton();
469: if (eventId == MouseEvent.MOUSE_WHEEL) {
470: wheelRotation = computeMouseWheelRotation();
471: screenPos = computeMouseWheelScreenPosition();
472: } else {
473: screenPos = computeMouseScreenPosition();
474: }
475: modifiers |= translateMouseModifiers();
476:
477: if (factory.lastHwndUnderPointer != windowId) {
478: WinWindow win = factory.getWinWindowById(windowId);
479:
480: if (win.contains(screenPos)) {
481: win.trackMouseEvent();
482: factory.lastHwndUnderPointer = windowId;
483: }
484: }
485: if (factory.mouseGrab.isMouseGrabbed()) {
486: Win32.POINT nativePoint = win32.createPOINT(false);
487: nativePoint.set_x(screenPos.x);
488: nativePoint.set_y(screenPos.y);
489: long newHwnd = win32.WindowFromPoint(nativePoint);
490: if (factory.getWinWindowById(newHwnd) != null) {
491: windowId = newHwnd;
492: }
493: }
494: }
495: localPos = computeMouseLocalPosition();
496: }
497:
498: private int computeMouseWheelRotation() {
499: return -((short) ((wParam >> 16) & 0xffff)) / 120;
500: }
501:
502: private Point computeMouseLocalPosition() {
503: Win32.RECT nativeRect = win32.createRECT(false);
504: win32.GetWindowRect(windowId, nativeRect);
505: int x = screenPos.x - nativeRect.get_left();
506: int y = screenPos.y - nativeRect.get_top();
507: return new Point(x, y);
508: }
509:
510: private Point computeMouseScreenPosition() {
511: if (msg == WM_MOUSEMOVE) {
512: Win32.MSG tempMsg = win32.createMSG(false);
513: while (win32.PeekMessageW(tempMsg, 0, WM_MOUSEMOVE,
514: WM_MOUSEMOVE, PM_NOREMOVE) != 0) {
515: if (tempMsg.get_hwnd() == windowId) {
516: win32.PeekMessageW(tempMsg, windowId, WM_MOUSEMOVE,
517: WM_MOUSEMOVE, PM_REMOVE);
518: lParam = tempMsg.get_lParam();
519: } else {
520: break;
521: }
522: }
523: }
524:
525: int x = (short) (lParam & 0xffff);
526: int y = (short) ((lParam >> 16) & 0xffff);
527:
528: Insets insets = factory.getInsets(windowId);
529: x += insets.left;
530: y += insets.top;
531:
532: Win32.RECT nativeRect = win32.createRECT(false);
533: win32.GetWindowRect(windowId, nativeRect);
534: x += nativeRect.get_left();
535: y += nativeRect.get_top();
536: return new Point(x, y);
537: }
538:
539: private Point computeMouseWheelScreenPosition() {
540: int x = (short) (lParam & 0xffff);
541: int y = (short) ((lParam >> 16) & 0xffff);
542: return new Point(x, y);
543: }
544:
545: private void setMouseEventIDAndButton() {
546: switch (msg) {
547: case WM_LBUTTONDOWN:
548: eventId = MouseEvent.MOUSE_PRESSED;
549: mouseButton = MouseEvent.BUTTON1;
550: break;
551: case WM_LBUTTONUP:
552: eventId = MouseEvent.MOUSE_RELEASED;
553: mouseButton = MouseEvent.BUTTON1;
554: break;
555: case WM_RBUTTONDOWN:
556: eventId = MouseEvent.MOUSE_PRESSED;
557: mouseButton = MouseEvent.BUTTON3;
558: break;
559: case WM_RBUTTONUP:
560: eventId = MouseEvent.MOUSE_RELEASED;
561: mouseButton = MouseEvent.BUTTON3;
562: break;
563: case WM_MBUTTONDOWN:
564: eventId = MouseEvent.MOUSE_PRESSED;
565: mouseButton = MouseEvent.BUTTON2;
566: break;
567: case WM_MBUTTONUP:
568: eventId = MouseEvent.MOUSE_RELEASED;
569: mouseButton = MouseEvent.BUTTON2;
570: break;
571: case WM_MOUSEMOVE:
572: eventId = ((wParam & (MK_LBUTTON | MK_RBUTTON | MK_MBUTTON)) != 0) ? MouseEvent.MOUSE_DRAGGED
573: : MouseEvent.MOUSE_MOVED;
574: break;
575: case WM_MOUSEWHEEL:
576: eventId = MouseEvent.MOUSE_WHEEL;
577: break;
578: }
579: }
580:
581: private int translateMouseModifiers() {
582: int modifiers = 0;
583: modifiers |= (wParam & MK_SHIFT) != 0 ? InputEvent.SHIFT_DOWN_MASK
584: : 0;
585: modifiers |= (wParam & MK_CONTROL) != 0 ? InputEvent.CTRL_DOWN_MASK
586: : 0;
587: modifiers |= ((win32.GetKeyState(VK_MENU) & 0x80) != 0) ? InputEvent.ALT_DOWN_MASK
588: : 0;
589:
590: modifiers |= (wParam & MK_LBUTTON) != 0 ? InputEvent.BUTTON1_DOWN_MASK
591: : 0;
592: modifiers |= (wParam & MK_MBUTTON) != 0 ? InputEvent.BUTTON2_DOWN_MASK
593: : 0;
594: modifiers |= (wParam & MK_RBUTTON) != 0 ? InputEvent.BUTTON3_DOWN_MASK
595: : 0;
596: return modifiers;
597: }
598: }
|