갤럭시북 및 기타 와콤 EMR기기 커스터마이징 관련 자료가 많이 공유되던 Tabletpcreview 사이트의 포럼이 폐쇄되면서 해당 포럼의 "갤럭시 북" 페이지에서 공유되던 스크립트들도 모두 소실되었습니다. ( http://forum.tabletpcreview.com/threads/samsung-galaxy-book-discussion-thread.71795/ 등 , 현재는 접속 불가.)

 

Wayback machine 사용시 접근 가능하기는 하나 (https://web.archive.org/web/20220125221312/http://forum.tabletpcreview.com/threads/samsung-galaxy-book-discussion-thread.71795/) 깨진 페이지도 많고 로딩도 오래 걸리고 검색도 되지 않아 원하는 자료를 찾는 데 불편함이 많습니다. 

 

기존 해당 사이트에서 받아서 백업해두었던 자료들을 공유합니다. 

 

1. 해당 스크립트들은 모두 내용을 복사하여 ".ahk" 확장자로 저장한 후 Autohotkey V1 으로 실행해야 합니다. 2.0 이상 버전에선 작동하지 않습니다. https://www.autohotkey.com/download/ahk-install.exe

2. 해당 스크립트들은 "AHKHID" 추가 파일이 필요하며, "AHKHID.ahk" 파일과 같은 폴더에 있어야 합니다. 다운로드 링크: https://github.com/jleb/AHKHID/archive/refs/heads/master.zip

3. 해당 스크립트들은 제목에 표기한 닉네임(Forum handle)을 쓰는 분들이 만들었으며, 저는 단순히 백업 목적으로만 재게시합니다. 

 

 

모든 스크립트들의 기본적인 동작법은 다음과 같습니다.

 

1) AHKHID로 HID기기의 모든 신호를 읽어 옴. 위치, 사용자 입력...

2) HEX data 형태로 주어지는 값을 처음에 누군가 해석하여 "펜버튼 클릭", "펜 인식" 동작을 분석

3) "펜 인식" 상태에서 "신규 입력 data" 값이 "기존 입력 data"값과 달라지고, 그 값이 "펜버튼 클릭" 동작과 일치하면 user가 지정한 스크립트를 수행함 (A 스크립트)

4) 추후 다른 사용자들이 HEX data를 추가적으로 분석하여 "펜 클릭", "펜 호버", "펜 버튼 누른 상태로 드래그" 등의 신호 를 발견하여 해당 신호를 기반으로 스크립트 작성 (B 스크립트)

 

해당 스크립트들은 와콤 EMR 기기, 즉 갤럭시 북이나 일부 레노버 제품 등 와콤 제품이 아닌 제품에서만 동작합니다. 와콤 원 등 와콤이 드라이버를 제공하는 기기의 경우 해당 스크립트가 작동하지 않습니다.

 

B 스크립트 내부에도 있으나, 사용하는 HEX 신호는 다음과 같습니다. 

0: 펜이 인식되었으며 호버링 중
1: 펜이 화면을 터치함
8: 펜이 화면을 터치하지 않은 상태에서 펜 버튼을 누름 <- 리맵핑에 사용
12: 펜이 화면을 터치한 상태에서 펜 버튼을 누름

 

A) 가장 단순한 버전 -  펜버튼 리매핑 지원 (Fotd 제작)

 

SendMode Input
SetWorkingDir %A_ScriptDir%

global PEN_NOT_HOVERING := 0x0 ; Pen is moved away from screen.

#include AHKHID.ahk

WM_INPUT := 0xFF
USAGE_PAGE := 13
USAGE := 2

AHKHID_UseConstants()

AHKHID_AddRegister(1)
AHKHID_AddRegister(USAGE_PAGE, USAGE, A_ScriptHwnd, RIDEV_INPUTSINK)
AHKHID_Register()

OnMessage(WM_INPUT, "Work")

Work(wParam, lParam) {

    Local type, inputInfo, inputData, raw, proc
    static lastInput := PEN_NOT_HOVERING

    Critical

    type := AHKHID_GetInputInfo(lParam, II_DEVTYPE)

    if (type = RIM_TYPEHID) {
        inputData := AHKHID_GetInputData(lParam, uData)

    raw := NumGet(uData, 0, "UInt")
        proc := (raw >> 8) & 0x1F

    if (proc <> lastInput) {
        if (proc == 8)
        {
			Click right
            ;Click left
			;Click left
        }
        lastInput := proc
    }
    }
}

 

사실 대부분 용도에는 이 정도 기능만으로도 충분합니다. 

현재 상태는 펜버튼 클릭시 우클릭으로 동작합니다. "Click right" 코멘트하고 (;)  "Click left" 두개를 코멘트 해제하면 더블클릭으로 동작합니다.

해당 부분을 

        if (proc == 8)
        {
			Send {A}
        }

이와 같이 바꾸면 펜버튼 클릭이 "A" 입력으로 바뀝니다. 

 

B) 분석 코멘트 및 기능 추가 버전 (Serega, Poton812, LeoZappa)

/*
Original script and all the hard work by Serega and Piton812
posted in http://forum.tabletpcreview.com/threads/samsung-galaxy-book-discussion-thread.71795/page-370#post-528013

http://forum.tabletpcreview.com/threads/samsung-galaxy-book-discussion-thread.71795/page-375#post-528538

Modifications and gesture support by LeoZappa, posted in same thread
*/

SendMode Input
SetWorkingDir %A_ScriptDir%

; mouse coordinates are absolute and relative to screen rather than active window:
Coordmode, Mouse, Screen


;--------------------------------------------------------------
; ACTIONS ON BUTTON RELEASE
;--------------------------------------------------------------
; Treshold in milliseconds for single-click
; This is also the delay between release and triggering of the mouse right-click(pr other actions)
global RELEASE_TRESHOLD := 300 ;in milliseconds

; KEEP THESE FUNCTIONS SIMPLE AND AVOID SLEEP/WAIT
ReleaseActions(pressX,pressY,releaseX,releaseY,releaseCount) {
    if ( releaseCount > 1){
        ;double press-and-release of button while hovering, or more (triple etc.)
        MouseClick, middle, pressX, pressY, 1, 0
    }else{
        ;single press-and-release of button while hovering triggers right mouse click
        MouseClick, right, pressX, pressY, 1, 0
    }
}
;--------------------------------------------------------------




;--------------------------------------------------------------
; LONG PRESS WHILE HOVERING
;--------------------------------------------------------------
; Write the duration of a LONG HOVER PRESS, in milliseconds
; Set it to something like 100000 (100 secs) to effectively disable long press functionality

global LONG_HOVER_PRESS := 1000 ;in milliseconds

LongPressActions(pressX,pressY,releaseCount) {
    if (releaseCount > 0) {
        Send #v
    }else{
    Send +#s
    }
}

;--------------------------------------------------------------



;--------------------------------------------------------------
; FLICK ACTIONS
; Triggered by moving left/right/up/dows while pressing button (and hovering).
; Flick gesture is completed by either releasing the button or lifting pen away from screen.
; Also supports release count (e.g. press and release, press again and flick)
;--------------------------------------------------------------

global FLICK_DIST := 30 ; in px of the screen

FlickActions(pressX,pressY,deltaX,deltaY,releaseCount) {
    if (Abs(deltaX) > Abs(deltaY) ) {
        if (deltaX > 0) {
        ; flick right action
            if (releaseCount > 1){
            ; workaround to use alternate Redo shortcut
            ; when doing "press and release"+"flick right"
            ; in case some programs don't understand Ctrl+y
                Send +^z
            }else{
                Send ^y
            }
        }else{
        ; flick left action
            Send ^z
        }
    }else{
        if (deltaY > 0) {
        ; flick up action
            Send !{Esc}
            WinGet isMin, MinMax, A
            if ( isMin < 0 ) {
                WinRestore A
            }
        }else{
        ; flick down action
            Send +!{Esc}
            WinGet isMin, MinMax, A
            if ( isMin < 0 ) {
                WinRestore A
            }
        }  
    }
}



; write the coordinates you get from "example2_with_min_max_XY.ahk"
global Xmin := 0
global Xmax := 25272
global Ymin := 0
global Ymax := 16848
; write the resolution of your display
global screenXmax := 2160
global screenYmax := 1440


; calculation the ratio to convert pen coordinates to mouse coordinates
global kX := (Xmax - Xmin) / screenXmax
global kY := (Ymax - Ymin) / screenYmax

; Set up our pen constants
global PEN_HOVERING := 0 ; Pen is inside the area where screen see the pen and pen and don't touch the screen.
global PEN_TOUCHING := 1 ; Pen is touching screen.
global PEN_BTN_HOVERING := 8 ; Button is pressed with pen is inside the area where screen see the pen and pen and don't touch the screen.
global PEN_BTN_TOUCHING := 12 ; Button is pressed with pen is touching screen.

/*
The package from pen data flow
Package consist of 26 blocks
00 0 0 0000 0011 1111 11 1122 2222 ; Blocks address with size 4 bits
01 2 3 4567 8901 2345 67 8901 2345 ;

02 2 0 0000 0000 0000 20 0000 0000 ; Left Up of the screen
02 0 0 0000 0000 0000 20 0000 0000 ; Out of screen

02 2 0 B662 CC41 0000 20 0000 0000 ; Right Down of the screen
02 0 0 B662 CC41 0000 20 0000 0000 ; Out of screen

02 2 0 0000 0000 0000 58 0000 0000 ; Almost out of the screen (but screen still see the pen)
02 2 0 0000 0000 0000 00 0000 0000 ; Almost touching the screen (but not touching)
02 2 1 0000 0000 0100 00 6400 8403 ; Touching the screen

Resume:
xx x x xxxx xxxx xxxx xx #### #### ; ????
xx x x xxxx xxxx xxxx ## xxxx xxxx ; Z position
xx x x xxxx xxxx #### xx xxxx xxxx ; ????
xx x x xxxx #### xxxx xx xxxx xxxx ; Y position
xx x x #### xxxx xxxx xx xxxx xxxx ; X position
xx x # xxxx xxxx xxxx xx xxxx xxxx ; Using mode
xx # x xxxx xxxx xxxx xx xxxx xxxx ; Connection mode
## x x xxxx xxxx xxxx xx xxxx xxxx ; ????

Connection mode:
2 - Connection with pen exists
0 - Lose connection with pen

Using mode:
0x00 ( 0) - Hovering
0x01 ( 1) - Touching (after touching button will not be active)
0x08 ( 8) - Button is pressed when hovering
0x0C (12) - Touching with button pressed (after touching button will not be active)

X position pen:
0000 - minimum =     0
(B862) 0x62B8 - about maximum = 25272 (2160 points) 12 pen points in 1 screen point
Cursor X position = X position pen / 12

Y position pen:
0000 - minimum =     0
(D041) 0x41D0 - about maximum = 16848 (1440 points) 12 pen points in 1 screen point
Cursor Y position = Y position pen / 12
*/
/*
Convert blocks of package to date structure from variables

Package consist of 26 blocks
00 0 0 0000 0011 1111 11 1122 2222 ; Blocks address with size 4 bits
01 2 3 4567 8901 2345 67 8901 2345 ;

Data structure from variables:
UInt (32 bits) (variables 1)
00000000 ; Blocks address with size 4 bits
67452301 ;

UInt (32 bits) (variables 2)
11111100 ; Blocks address with size 4 bits
45230189 ;

UInt (32 bits) (variables 3)
22221111 ; Blocks address with size 4 bits
23018967 ;

UInt (32 bits) (variables 4)
33222222 ; Blocks address with size 4 bits
01896745 ;

*/


#include AHKHID.ahk

WM_INPUT := 0xFF
USAGE_PAGE := 13
USAGE := 2

AHKHID_UseConstants()

AHKHID_AddRegister(1)
AHKHID_AddRegister(USAGE_PAGE, USAGE, A_ScriptHwnd, RIDEV_INPUTSINK)
AHKHID_Register()

OnMessage(WM_INPUT, "Work")

Work(wParam, lParam) {
    Local type, inputInfo, inputData, raw, UsingMode, ConnectionMode
 
    static lastInput := -1 ; Last code for compare with constants

    static releaseCount := 0 ; count single/double/etc.-releases of pen button
    static valid_press := 0 ;Last state of pen

    Local sPen_Xpos ;X position cursor of pen
    Local sPen_Ypos ;Y position cursor of pen

    Local mouseXpos ;X position cursor of mouse
    Local mouseYpos ;Y position cursor of mouse

    static press_Time := 0 ; when was the button last pressed
    static release_Time :=  0 ; when was the button last released

    static pressX ;coordinates at time of button press
    static pressY
    static deltaX ;displacement at time of release of button/lift away from screen
    static deltaY

    sPen_Xpos := NumGet(uData, 2, "WORD") ;Read X position cursor of pen (offset on 2 bytes in package, size in 16 bits (2 bytes))
    sPen_Ypos := NumGet(uData, 4, "WORD") ;Read Y position cursor of pen (offset on 4 bytes in package, size in 16 bits (2 bytes))
    sPen_Xpos := (sPen_Xpos & 0xFFFF)
    sPen_Ypos := (sPen_Ypos & 0xFFFF)
    mouseXpos := sPen_Xpos / kX ; Convert to X position cursor for mouse
    mouseYpos := sPen_Ypos / kY ; Convert to Y position cursor for mouse

   
    Critical

    ;Get device type
    type := AHKHID_GetInputInfo(lParam, II_DEVTYPE) ;Connect to device
    if (type = RIM_TYPEHID) { ;if type device is "pen"
        inputData := AHKHID_GetInputData(lParam, uData) ;Connect to commands flow of pen
       
        raw := NumGet(uData, 1, "UChar") ;Read Z position cursor of pen (offset on 8 bytes in package, size in 8 bits (1 byte))
        UsingMode := raw & 0x1F ;Decode command to code using mode for compare with constants
        ConnectionMode := raw & 0x20 ; Decode command to code connection mode for tracking the information flow from pen till screen see the pen

        if (ConnectionMode <> 0){ ; Connection with pen exists

            BlockInput on ; seems to help with hiding the mouse cursor while pen is hovering. Not sure why.
               
            if (UsingMode <> lastInput) { ;Changed button state
                if (UsingMode == PEN_BTN_HOVERING) and (lastInput <> PEN_BTN_TOUCHING){
                ; just pressed button while hovering, didn't just lift pen from touching the screen
                        valid_press := 1 ;Mark pressed button state
                        press_Time := A_TickCount ; start measuring press time
                        release_Time := A_TickCount ; set release timer to something certainly larger than last value
                        pressX := mouseXpos
                        pressY := mouseYpos
                }else{
                    if (valid_press <> 0) and (lastInput == PEN_BTN_HOVERING){
                        if (UsingMode <> PEN_BTN_TOUCHING){
                            ; just released button while hovering
                            releaseCount++
                            release_Time := A_TickCount ; start measuring time from release
                            deltaX := mouseXpos - pressX
                            deltaY := mouseYpos - pressY
                        }else{ ;touched the screen again
                            valid_press := 0
                            releaseCount := 0
                        }  
                        valid_press := 0 ;Mark button released state
                    }
                }
                lastInput := UsingMode ;Save new code for new loop
            }
            if (valid_press <> 0) and (A_TickCount - press_Time > LONG_HOVER_PRESS) {
                    LongPressActions(pressX,pressY,releaseCount)
                    valid_press := 0
                    releaseCount := 0
            }else{
                ; Single-release action is right click
                if (valid_press == 0) and (releaseCount > 0 ) {
                    if (Abs(deltaX) > FLICK_DIST) or (Abs(deltaY) > FLICK_DIST) {
                        FlickActions(pressX,pressY,deltaX,deltaY,releaseCount)
                        releaseCount := 0
                    }else{
                    if (A_TickCount - release_Time > RELEASE_TRESHOLD) {
                        ReleaseActions(pressX,pressY,mouseXpos,mouseYpos,releaseCount)
                        valid_press := 0
                        releaseCount := 0
                    }
                    }
                }
            }
        }else{ ; Lost connection with pen

            BlockInput off
       
            lastInput := 0 ; set it to button released regardless of actual state
           
            if (valid_press <>0) {
                ; these are the last positions before disconnection
                deltaX := mouseXpos - pressX
                deltaY := mouseYpos - pressY
                if (Abs(deltaX) > FLICK_DIST) or (Abs(deltaY) > FLICK_DIST) {
                    FlickActions(pressX,pressY,deltaX,deltaY,releaseCount+1)
                }
            }
            releaseCount := 0
            release_Time := 0
            press_Time := 0
            valid_press := 0
        }
    }
}

 

Flick 액션 및 long press 기능을 추가한 버전입니다. 포럼에서 여러 사람이 공동 작업한 결과물로 알고 있습니다.

저는 해당 스크립트를 직접 써보지는 않아 구체적인 동작은 알지 못하나, 구현상 "FlickActions" 함수와 "ReleaseActions", "LongPressActions" 함수 내부를 변경하여 키 할당이 가능할 것으로 보입니다. 

 

 

 

+ Recent posts