'자바'에 해당되는 글 11건

  1. 2009.01.09 Click on Touch Screen
  2. 2009.01.04 Java AWT Mouse Click Event의 기원 (4)
  3. 2007.09.02 Java Enum Type, Obfuscation Problem (2)
  4. 2007.04.02 ThinkFree Office with Nimbus Look and Feel (2)
  5. 2007.03.12 Swing Application Framework
자바2009.01.09 22:19

Sun이 작년(?)부터 Java SE for Embedded를 배포하고 있다. 점점 커지는 모바일 시장에서 한 몫 해보려는 모양이다. 지난달에는 심지어 ARM Linux 플랫폼을 위한 Java SE for Embedded 6u10 (early access)도 나왔다. 우연찮은 기회(업무 ^^)로 Java SE for Embedded 6u10 기반 ThinkFree Mobile 개발에 참여하게 되었는데, 몇 가지 주목할 만한 내용들이 있어 기록해둔다. 오늘은 일단 Click on Touch Screen에 대해서만.

일전에 기록해둔 것처럼 AWT의 mouse click event는 AWT native 구현체에서 발생이 되는데, 일반 desktop edition의 구현체는 pressed point와 released point가 동일한 경우에만 click event가 발생된다. 우리가 흔히 사용하는 마우스는, 클릭을 할 때 일부러 흔들지 않는 이상 pressed, released point가 다를 가능성이 희박하다. 따라서 의도대로 적절히 click을 행할 수 있다.

하지만 터치 스크린의 경우, 손가락 끝으로 스크린을 두드려야 되는데, 손가락 끝은 다른 도구(스타일러스 등)에 비해 면적이 넓은데다가 굴곡도 있고, 말랑말랑해서 자칫 pressed point와 released point에 차이가 생기게 마련이다(손톱은 그나마 좀 낫다). 그 차이는, 개인적인 측정에 의하면, 작게는 2~3 pixel부터 많게는 20~30 pixel까지 차이가 난다. 간혹 device driver나 OS가 똑똑하게 보정해 주는 경우도 있는 것 같지만, 그렇지 않은 경우라면 문제가 생길 수 있다.

테스트 결과 EJRE(JRE from Java SE for Embedded 6u10)에서는 x, y 좌표 중 하나라도 4 pixel 이상 차이나면 click event가 발생하지 않는 것으로 확인이 되었다. 4 pixel이라는 threshold는 외부 설정으로 변경이 가능한 것인지 아니면 단순 하드코딩된 값인지는 모르겠으나, 일단 불편한 default 값이긴 하다. 이 때문에 EJRE에서 사용자가 원하는 대로 click을 할 수 있도록 구현하려면 약간의 work-around가 필요하다. 내가 사용했던 방법은 대략 아래와 같이 AWT event를 꼬아버리는 방법이다.

Toolkit.getDefaultToolkit().getSystemEventQueue().push(new EventQuene() {
    @Override
    protected void dispatchEvent(AWTEvent event) {
        boolean dispatch = true;
        if(event instanceof MouseEvent) {
            // create and submit a mouse click event by
            // adjusted threshold about 16 ~ 32 pixels
            // between pressed and released point, and
            // execute some customizations by event id,
            // blah blah blah...
            ...
        }
        
        if(dispatch) {
            super.dispatchEvent(event);
        }
    }
});

물론 이런 식의 work-around는 몸에 해롭다. EJRE가 좀 더 유연해지면 얼렁 지워버리어야지. 그리고 위 코드가 동작했을 때의 결과는 아래 동영상으로 확인.


Easy Clicker from Yonghwan Cho on Vimeo.
신고
Posted by roguebean
자바2009.01.04 17:53

보통 AWT/Swing에서 발생되는 input event는 JVM을 호스팅하고 있는 OS의 native input event를 AWT native 구현체가 Java 객체로 변환하여 전달한 것이다. 그런데 Windows(win32)나 Linux(gtk) API에는 mouse click event가 따로 존재하지 않는다(고 알고 있다). 그러면 Java에서 사용되는 mouse click event는 어디서 생성된 것일까? 아마도 아래 OpenJDK 소스에서 답을 찾을 수 있을 것 같다.

MsgRouting AwtComponent::WmMouseUp(UINT flags, int x, int y, int button)
{
    MSG msg;
    InitMessage(&msg, lastMessage, flags, MAKELPARAM(x, y), x, y);

    SendMouseEvent(java_awt_event_MouseEvent_MOUSE_RELEASED, TimeHelper::getMessageTimeUTC(),
                   x, y, GetJavaModifiers(), clickCount,
                   (GetButton(button) == java_awt_event_MouseEvent_BUTTON3 ?
                    TRUE : FALSE), GetButton(button), &msg);
    ...
    if (!(m_mouseDragState & GetButtonMK(button))) { // No up-button in the drag-state
        SendMouseEvent(java_awt_event_MouseEvent_MOUSE_CLICKED,
                       TimeHelper::getMessageTimeUTC(), x, y, GetJavaModifiers(),
                       clickCount, JNI_FALSE, GetButton(button));
    }
    ...
}

Source:
https://openjdk.dev.java.net/svn/openjdk/jdk/trunk/jdk/src/windows/native/sun/windows/awt_Component.cpp

void
awt_canvas_handleEvent(Widget w, XtPointer client_data,
                       XEvent * event, struct WidgetInfo *winfo,
                       Boolean * cont, Boolean passEvent)
{
    ...

    switch (event->type) {
        ...
        case ButtonRelease:
            ...
            awt_post_java_mouse_event(client_data,
                                      java_awt_event_MouseEvent_MOUSE_RELEASED,
                                      (passEvent == TRUE) ? event : NULL,
                                      event->xbutton.time,
                                      modifiers,
                                      x, y,
                                      (jint) (event->xbutton.x_root),
                                      (jint) (event->xbutton.y_root),
                                      clickCount,
                                      FALSE, 0,
                                      button);

            if (lastPeer == client_data) {
                awt_post_java_mouse_event(client_data,
                                          java_awt_event_MouseEvent_MOUSE_CLICKED,
                                          NULL,
                                          event->xbutton.time,
                                          modifiers,
                                          x, y,
                                          (jint) (event->xbutton.x_root),
                                          (jint) (event->xbutton.y_root),
                                          clickCount,
                                          FALSE, 0,
                                          button);
            }
            ...
    }
}

Source:
https://openjdk.dev.java.net/svn/openjdk/jdk/trunk/jdk/src/solaris/native/sun/awt/canvas.c

그렇다. Release event 발생시에 몇 가지 조건만 맞으면 click event도 발생된다. AWT native 구현이 크게 다르지 않다면 다른 JRE도 대략 이러한 과정으로 click event를 생성하지 않을까 생각된다.

신고
Posted by roguebean
자바2007.09.02 16:00

Java enum type은 obfuscate할 때 주의가 필요하다. java.lang.Class.getEnumConstants()에서 reflection으로 해당 enum type의 'values'라는 메서드를 참조하기 때문이다.

예를 들어 net.rb.lab.TestEnum이라는 java enum type이 다음과 같은 소스코드를 가진다고 하자.

package net.rb.lab;

public enum TestEnum {

    ITEM_A,
    ITEM_B;
    
}

이 소스코드를 compile하면 다음과 같은 byte code outline을 확인할 수 있다.

net.rb.lab.TestEnum
Fields:
    ITEM_A
    ITEM_B
    ENUM$VALUES
Methods:
    <clinit>
    <init>
    values
    valueOf

실제 byte code를 decompile해보면 대략 아래와 같은 코드를 유추해낼 수 있다.
(아래 소스코드는 byte code의 구조파악을 위해 기술된 내용이고, Enum 상속 문제때문에 실제 complie은 안된다.)

package net.rb.lab;

public final class TestEnum extends Enum {

    public static final TestEnum ITEM_A;
    public static final TestEnum ITEM_B;
    private static final TestEnum[] ENUM$VALUES;

    static {
        ITEM_A = new TestEnum("ITEM_A", 0);
        ITEM_B = new TestEnum("ITEM_B", 1);
        ENUM$VALUES = new TestEnum[] { ITEM_A, ITEM_B };
    }
    
    private TestEnum(String name, int ordinal) {
        super(name, ordinal);
    }

    public static TestEnum[] values() {
        TestEnum[] newArray = new TestEnum[ENUM$VALUES.length];
        System.arraycopy(ENUM$VALUES, 0, newArray, 0, ENUM$VALUES.length);
        return newArray;
    }

    public static TestEnum valueOf(String name) {
        return (TestEnum) Enum.valueOf(TestEnum.class, name);
    }

}

보시다시피 enum type의 경우, Java compiler에 의해서 다음과 같이 두 메서드가 자동으로 생성된다.

  • public static TestEnum[] values()
  • public static TestEnum valueOf(String)

이 두 메서드가 바로 문제의 녀석들이다. TestEnum.valueOf(String) 호출은 결국 Class.getEnumConstants() 호출을 야기하는데, 만약 values() 메서드가 obfuscate되었다면 Class.getEnumConstants()는 reflection으로 해당 메서드를 찾을 수 없으므로 null을 return, 결국 JVM은 'TestEnum은 enum type이 아닐세'라며 exception을 던져버린다.

Obfuscation의 목적은 decompile시 의미파악을 어렵게 하기 위함인데, Java enum type의 'values'나 'valueOf'같은 메서드는 이미 공개된 내용이므로 obfuscation 목록에서 제외하는게 문제를 예방하는 데 도움이 될 것 같다.

신고
Posted by roguebean
자바2007.04.02 14:49
ThinkFree OfficeNimbus Look and Feel을 적용하면 어떤 모습일까?
아마도 그럴 일은 없겠지만, 호기심 충족용 스크린샷!!!


신고
Posted by roguebean
자바2007.03.12 01:56
Duke on Swing

Duke on Swing

요즘에 Swing Application Framework을 주의깊게 살펴보고 있다. Swing Application Framework은 수많은 개발자들이 Swing application을 작성하면서 고민했던 부분을 다루고 있는데, 대표적으로는 application life cycle, resources, actions (including background task), session 관리 등을 다루고 있다.

현재 버전은 0.2 수준이고 아직 프로토타이핑 중인데, 범용적으로 사용되는 부분만을 다루다보니 ThinkFree Office처럼 덩치큰 프로젝트에 적용하기 위해서는 확장이 필요해보인다. 그리고 ThinkFree Office처럼 content-centric application을 위한 기반은 전혀 제공되지 않는다. 메일링 리스트를 살펴보면 JHotDraw 7을 개발중인 Werner Randelshofer 역시 이러한 application에 대한 지원이 없음을 아쉬워하고 있다.

어쨌든 개인적으로 ThinkFree Office의 다소 빈약한 framework 때문에 많은 고민을 해왔었는데, 이러한 framework의 등장은 매우 기쁘다. 또한 많은 개발자들이 나와 비슷한 고민을 해왔다는 점과 비슷한 솔루션을 생각해왔다는 점도 흥미롭다. 아직 1.0이 나오려면 멀었지만 계속 지켜봐야겠다.

Swing Application Framework은 Sun사의 Desktop division CTO인 Hans Muller에 의해 주도되고 있으며 지난 JavaOne 2006에서 소개된 이후에 JavaPolis 2006 및 지난주에 열렸던 Desktop Matters 등의 컨퍼런스에서 계속 소개되고 있다. 작년에 이미 JSR 296으로 등록되었으며 큰 차질이 없다면 Java 7의 core library에 들어가지 않을까 생각된다.

관련 자료들의 URL:
 - java.net: Swing Application Framework
 - JSR 296: Swing Application Framework
 - JavaOne 2006 presentation
 - JavaPolis 2006 presentation
신고
Posted by roguebean

티스토리 툴바