Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

start on ime #24

Merged
merged 3 commits into from
Oct 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/windy/common.nim
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ type
MouseLeft
MouseRight
MouseMiddle
MouseBackward
MouseForward
MouseButton4
MouseButton5
DoubleClick
TripleClick
QuadrupleClick
Expand Down
94 changes: 90 additions & 4 deletions src/windy/platforms/win32/platform.nim
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ const

type
Window* = ref object
closeRequested*: bool
onCloseRequest*: Callback
onMove*: Callback
onResize*: Callback
Expand All @@ -43,7 +42,7 @@ type
onRune*: RuneCallback

title: string
closed: bool
closeRequested, closed: bool
perFrame: PerFrame
trackMouseEventRegistered: bool
mousePos: IVec2
Expand All @@ -54,6 +53,10 @@ type
quadrupleClickTimes: array[3, float64]
multiClickPositions: array[3, IVec2]

imePos*: IVec2
imeCursorIndex: int
imeCompositionString: string

hWnd: HWND
hdc: HDC
hglrc: HGLRC
Expand Down Expand Up @@ -286,6 +289,15 @@ proc mouseDelta*(window: Window): IVec2 =
proc scrollDelta*(window: Window): Vec2 =
window.perFrame.scrollDelta

proc closeRequested*(window: Window): bool =
window.closeRequested

proc imeCursorIndex*(window: Window): int =
window.imeCursorIndex

proc imeCompositionString*(window: Window): string =
window.imeCompositionString

proc `title=`*(window: Window, title: string) =
window.title = title
var wideTitle = title.wstr()
Expand Down Expand Up @@ -450,6 +462,12 @@ proc `maximized=`*(window: Window, maximized: bool) =
cmd = SW_RESTORE
discard ShowWindow(window.hWnd, cmd)

proc `closeRequested=`*(window: Window, closeRequested: bool) =
window.closeRequested = closeRequested
if closeRequested:
if window.onCloseRequest != nil:
window.onCloseRequest()

proc loadOpenGL() =
let opengl = LoadLibraryA("opengl32.dll")
if opengl == 0:
Expand Down Expand Up @@ -734,14 +752,19 @@ proc wndProc(
if window.onScroll != nil:
window.onScroll()
return 0
of WM_LBUTTONDOWN, WM_RBUTTONDOWN, WM_MBUTTONDOWN,
WM_LBUTTONUP, WM_RBUTTONUP, WM_MBUTTONUP:
of WM_LBUTTONDOWN, WM_RBUTTONDOWN, WM_MBUTTONDOWN, WM_XBUTTONDOWN,
WM_LBUTTONUP, WM_RBUTTONUP, WM_MBUTTONUP, WM_XBUTTONUP:
let button =
case uMsg:
of WM_LBUTTONDOWN, WM_LBUTTONUP:
MouseLeft
of WM_RBUTTONDOWN, WM_RBUTTONUP:
MouseRight
of WM_XBUTTONDOWN, WM_XBUTTONUP:
if HIWORD(wParam) == XBUTTON1:
MouseButton4
else:
MouseButton5
else:
MouseMiddle
if uMsg in {WM_LBUTTONDOWN, WM_RBUTTONDOWN, WM_MBUTTONDOWN}:
Expand Down Expand Up @@ -776,6 +799,62 @@ proc wndProc(
let codepoint = wParam.uint32
window.handleRune(Rune(codepoint))
return 0
of WM_IME_STARTCOMPOSITION:
let hIMC = ImmGetContext(window.hWnd)

var compositionPos: COMPOSITIONFORM
compositionPos.dwStyle = CFS_POINT
compositionPos.ptCurrentPos = POINT(x: window.imePos.x, y: window.imePos.y)
discard ImmSetCompositionWindow(hIMC, compositionPos.addr)

var candidatePos: CANDIDATEFORM
candidatePos.dwIndex = 0
candidatePos.dwStyle = CFS_CANDIDATEPOS
candidatePos.ptCurrentPos = POINT(x: window.imePos.x, y: window.imePos.y)
discard ImmSetCandidateWindow(hIMC, candidatePos.addr)

var exclude: CANDIDATEFORM
exclude.dwIndex = 0
exclude.dwStyle = CFS_EXCLUDE
exclude.ptCurrentPos = POINT(x: window.imePos.x, y: window.imePos.y)
exclude.rcArea = RECT(
left: window.imePos.x,
top: window.imePos.y,
right: window.imePos.x + 1,
bottom: window.imePos.x + 1
)
discard ImmSetCandidateWindow(hIMC, exclude.addr)

discard ImmReleaseContext(window.hWnd, hIMC)
return 0
of WM_IME_COMPOSITION:
let hIMC = ImmGetContext(window.hWnd)

if (lParam and GCS_CURSORPOS) != 0:
window.imeCursorIndex = ImmGetCompositionStringW(
hIMC, GCS_CURSORPOS, nil, 0
)

if (lParam and GCS_COMPSTR) != 0:
let len = ImmGetCompositionStringW(
hIMC, GCS_COMPSTR, nil, 0
)
if len > 0:
var buf = newString(len + 1) # Include 1 extra byte for WCHAR null terminator
discard ImmGetCompositionStringW(
hIMC, GCS_COMPSTR, buf[0].addr, len
)
window.imeCompositionString = $cast[ptr WCHAR](buf[0].addr)
else:
window.imeCompositionString = ""

if (lParam and GCS_RESULTSTR) != 0:
# The input runes will come in through WM_CHAR events
window.imeCursorIndex = 0
window.imeCompositionString = ""

discard ImmReleaseContext(window.hWnd, hIMC)
# Do not return 0 here
else:
discard

Expand Down Expand Up @@ -830,6 +909,13 @@ proc close*(window: Window) =
destroy window
window.closed = true

proc closeIme*(window: Window) =
let hIMC = ImmGetContext(window.hWnd)
discard ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_CANCEL, 0)
discard ImmReleaseContext(window.hWnd, hIMC)
window.imeCursorIndex = 0
window.imeCompositionString = ""

proc newWindow*(
title: string,
size: IVec2,
Expand Down
35 changes: 23 additions & 12 deletions src/windy/platforms/win32/utils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,19 @@ proc `$`*(p: ptr WCHAR): string =
nil,
nil
)
result.setLen(len)
discard WideCharToMultiByte(
CP_UTF8,
0,
p,
-1,
result[0].addr,
len,
nil,
nil
)
result.setLen(len - 1)
if len > 0:
result.setLen(len)
discard WideCharToMultiByte(
CP_UTF8,
0,
p,
-1,
result[0].addr,
len,
nil,
nil
)
result.setLen(len - 1)

proc checkHRESULT*(hresult: HRESULT) =
if hresult != S_OK:
Expand Down Expand Up @@ -267,5 +268,15 @@ proc wmEventName*(wm: int | UINT): string =
"WM_UNICHAR"
of WM_SYSCOMMAND:
"WM_SYSCOMMAND"
of WM_XBUTTONDOWN:
"WM_XBUTTONDOWN"
of WM_XBUTTONUP:
"WM_XBUTTONUP"
of WM_IME_STARTCOMPOSITION:
"WM_IME_STARTCOMPOSITION"
of WM_IME_ENDCOMPOSITION:
"WM_IME_ENDCOMPOSITION"
of WM_IME_COMPOSITION:
"WM_IME_COMPOSITION"
else:
"WM " & $wm & " " & $toHex(wm)
88 changes: 87 additions & 1 deletion src/windy/platforms/win32/windefs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ type
BOOL* = int32
LPBOOL* = ptr BOOL
LONG* = int32
USHORT* = uint16
LANGID* = USHORT
WORD* = uint16
ATOM* = WORD
DWORD* = int32
Expand All @@ -35,6 +37,8 @@ type
HBRUSH* = HANDLE
HMODULE* = HINSTANCE
HGLOBAL* = HANDLE
HIMC* = HANDLE
HBITMAP* = HANDLE
LPVOID* = pointer
UINT* = uint32
WPARAM* = UINT_PTR
Expand Down Expand Up @@ -126,6 +130,17 @@ type
rcWork*: RECT
dwFlags*: DWORD
LPMONITORINFO* = ptr MONITORINFO
COMPOSITIONFORM* {.pure.} = object
dwStyle*: DWORD
ptCurrentPos*: POINT
rcArea*: RECT
LPCOMPOSITIONFORM* = ptr COMPOSITIONFORM
CANDIDATEFORM* {.pure.} = object
dwIndex*: DWORD
dwStyle*: DWORD
ptCurrentPos*: POINT
rcArea*: RECT
LPCANDIDATEFORM* = ptr CANDIDATEFORM

type
wglCreateContext* = proc(hdc: HDC): HGLRC {.stdcall, raises: [].}
Expand Down Expand Up @@ -236,6 +251,10 @@ const
WM_SYSKEYUP* = 0x0105
WM_SYSCHAR* = 0x0106
WM_UNICHAR* = 0x0109
WM_IME_STARTCOMPOSITION* = 0x010D
WM_IME_ENDCOMPOSITION* = 0x010E
WM_IME_COMPOSITION* = 0x010F
WM_QUERYUISTATE* = 0x0129
WM_SYSCOMMAND* = 0x0112
WM_MOUSEMOVE* = 0x0200
WM_LBUTTONDOWN* = 0x0201
Expand All @@ -248,6 +267,8 @@ const
WM_MBUTTONUP* = 0x0208
WM_MBUTTONDBLCLK* = 0x0209
WM_MOUSEWHEEL* = 0x020A
WM_XBUTTONDOWN* = 0x020B
WM_XBUTTONUP* = 0x020C
WM_MOUSEHWHEEL* = 0x020E
WM_IME_SETCONTEXT* = 0x0281
WM_IME_NOTIFY* = 0x0282
Expand Down Expand Up @@ -338,6 +359,31 @@ const
VK_PROCESSKEY* = 0xE5
CF_UNICODETEXT* = 13
GMEM_MOVEABLE* = 0x2
XBUTTON1* = 0x0001
XBUTTON2* = 0x0002
CFS_DEFAULT* = 0x0000
CFS_RECT* = 0x0001
CFS_POINT* = 0x0002
CFS_FORCE_POSITION* = 0x0020
CFS_CANDIDATEPOS* = 0x0040
CFS_EXCLUDE* = 0x0080
GCS_COMPREADSTR* = 0x0001
GCS_COMPREADATTR* = 0x0002
GCS_COMPREADCLAUSE* = 0x0004
GCS_COMPSTR* = 0x0008
GCS_COMPATTR* = 0x0010
GCS_COMPCLAUSE* = 0x0020
GCS_CURSORPOS* = 0x0080
GCS_DELTASTART* = 0x0100
GCS_RESULTREADSTR* = 0x0200
GCS_RESULTREADCLAUSE* = 0x0400
GCS_RESULTSTR* = 0x0800
GCS_RESULTCLAUSE* = 0x1000
CPS_COMPLETE* = 0x0001
CPS_CONVERT* = 0x0002
CPS_REVERT* = 0x0003
CPS_CANCEL* = 0x0004
NI_COMPOSITIONSTR* = 0x0015

proc GetLastError*(): DWORD {.importc, stdcall, dynlib: "Kernel32".}

Expand Down Expand Up @@ -399,7 +445,9 @@ proc GlobalAlloc*(

proc GlobalFree*(
hMem: HGLOBAL
): HGLOBAL{.importc, stdcall, dynlib: "Kernel32".}
): HGLOBAL {.importc, stdcall, dynlib: "Kernel32".}

proc GetUserDefaultUILanguage*(): LANGID {.importc, stdcall, dynlib: "Kernel32".}

proc LoadCursorW*(
hInstance: HINSTANCE,
Expand Down Expand Up @@ -611,6 +659,20 @@ proc IsClipboardFormatAvailable*(
format: UINT
): BOOL {.importc, stdcall, dynlib: "User32".}

proc CreateCaret*(
hWnd: HWND,
hBitamp: HBITMAP,
nWidth: int32,
nHeight: int32
): BOOL {.importc, stdcall, dynlib: "User32".}

proc DestroyCaret*(): BOOL {.importc, stdcall, dynlib: "User32".}

proc SetCaretPos*(
x: int32,
y: int32
): BOOL {.importc, stdcall, dynlib: "User32".}

proc ChoosePixelFormat*(
hdc: HDC,
ppfd: ptr PIXELFORMATDESCRIPTOR
Expand All @@ -632,3 +694,27 @@ proc DescribePixelFormat*(
): int32 {.importc, stdcall, dynlib: "Gdi32".}

proc SwapBuffers*(hdc: HDC): BOOL {.importc, stdcall, dynlib: "Gdi32".}

proc ImmGetContext*(
hWnd: HWND
): HIMC {.importc, stdcall, dynlib: "imm32".}

proc ImmReleaseContext*(
hWnd: HWND, hIMC: HIMC
): BOOL {.importc, stdcall, dynlib: "imm32".}

proc ImmSetCompositionWindow*(
hIMC: HIMC, lpCompForm: LPCOMPOSITIONFORM
): BOOL {.importc, stdcall, dynlib: "imm32".}

proc ImmSetCandidateWindow*(
hIMC: HIMC, lpCandidate: LPCANDIDATEFORM
): BOOL {.importc, stdcall, dynlib: "imm32".}

proc ImmGetCompositionStringW*(
hIMC: HIMC, gcsValue: DWORD, lpBuf: LPVOID, dwBufLen: DWORD
): LONG {.importc, stdcall, dynlib: "imm32".}

proc ImmNotifyIME*(
hIMC: HIMC, dwAction: DWORD, dwIndex: DWORD, dwValue: DWORD
): BOOL {.importc, stdcall, dynlib: "imm32".}