api_windows.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. // Copyright 2024 The Ebitengine Authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package textinput
  15. import (
  16. "errors"
  17. "fmt"
  18. "runtime"
  19. "unsafe"
  20. "golang.org/x/sys/windows"
  21. )
  22. const (
  23. _ATTR_TARGET_CONVERTED = 0x01
  24. _ATTR_TARGET_NOTCONVERTED = 0x03
  25. _CFS_CANDIDATEPOS = 0x0040
  26. _GCS_COMPATTR = 0x0010
  27. _GCS_COMPCLAUSE = 0x0020
  28. _GCS_COMPSTR = 0x0008
  29. _GCS_RESULTSTR = 0x0800
  30. _GWL_WNDPROC = -4
  31. _ISC_SHOWUICOMPOSITIONWINDOW = 0x80000000
  32. _UNICODE_NOCHAR = 0xffff
  33. _WM_CHAR = 0x0102
  34. _WM_IME_COMPOSITION = 0x010F
  35. _WM_IME_SETCONTEXT = 0x0281
  36. _WM_SYSCHAR = 0x0106
  37. _WM_UNICHAR = 0x0109
  38. )
  39. type (
  40. _HIMC uintptr
  41. )
  42. type _CANDIDATEFORM struct {
  43. dwIndex uint32
  44. dwStyle uint32
  45. ptCurrentPos _POINT
  46. rcArea _RECT
  47. }
  48. type _POINT struct {
  49. x int32
  50. y int32
  51. }
  52. type _RECT struct {
  53. left int32
  54. top int32
  55. right int32
  56. bottom int32
  57. }
  58. var (
  59. imm32 = windows.NewLazySystemDLL("imm32.dll")
  60. user32 = windows.NewLazySystemDLL("user32.dll")
  61. procImmAssociateContext = imm32.NewProc("ImmAssociateContext")
  62. procImmGetCompositionStringW = imm32.NewProc("ImmGetCompositionStringW")
  63. procImmGetContext = imm32.NewProc("ImmGetContext")
  64. procImmReleaseContext = imm32.NewProc("ImmReleaseContext")
  65. procImmSetCandidateWindow = imm32.NewProc("ImmSetCandidateWindow")
  66. procCallWindowProcW = user32.NewProc("CallWindowProcW")
  67. procGetActiveWindow = user32.NewProc("GetActiveWindow")
  68. procSetWindowLongW = user32.NewProc("SetWindowLongW") // 32-Bit Windows version.
  69. procSetWindowLongPtrW = user32.NewProc("SetWindowLongPtrW") // 64-Bit Windows version.
  70. )
  71. func _CallWindowProcW(lpPrevWndFunc uintptr, hWnd uintptr, msg uint32, wParam, lParam uintptr) uintptr {
  72. r, _, _ := procCallWindowProcW.Call(lpPrevWndFunc, hWnd, uintptr(msg), wParam, lParam)
  73. return r
  74. }
  75. func _GetActiveWindow() windows.HWND {
  76. r, _, _ := procGetActiveWindow.Call()
  77. return windows.HWND(r)
  78. }
  79. func _ImmAssociateContext(hwnd windows.HWND, hIMC uintptr) (uintptr, error) {
  80. r, _, e := procImmAssociateContext.Call(uintptr(hwnd), hIMC)
  81. if e != nil && !errors.Is(e, windows.ERROR_SUCCESS) {
  82. return 0, fmt.Errorf("textinput: ImmAssociateContext failed: error code: %w", e)
  83. }
  84. return r, nil
  85. }
  86. func _ImmGetCompositionStringW(unnamedParam1 _HIMC, unnamedParam2 uint32, lpBuf unsafe.Pointer, dwBufLen uint32) (uint32, error) {
  87. r, _, e := procImmGetCompositionStringW.Call(uintptr(unnamedParam1), uintptr(unnamedParam2), uintptr(lpBuf), uintptr(dwBufLen))
  88. runtime.KeepAlive(lpBuf)
  89. if r < 0 {
  90. return 0, fmt.Errorf("textinput: ImmGetCompositionStringW failed: %d", r)
  91. }
  92. if e != nil && e != windows.ERROR_SUCCESS {
  93. return 0, fmt.Errorf("textinput: ImmGetCompositionStringW failed: %w", e)
  94. }
  95. return uint32(r), nil
  96. }
  97. func _ImmGetContext(unnamedParam1 windows.HWND) _HIMC {
  98. r, _, _ := procImmGetContext.Call(uintptr(unnamedParam1))
  99. return _HIMC(r)
  100. }
  101. func _ImmReleaseContext(unnamedParam1 windows.HWND, unnamedParam2 _HIMC) error {
  102. r, _, e := procImmReleaseContext.Call(uintptr(unnamedParam1), uintptr(unnamedParam2))
  103. if int32(r) == 0 {
  104. if e != nil && e != windows.ERROR_SUCCESS {
  105. return fmt.Errorf("textinput: ImmReleaseContext failed: %w", e)
  106. }
  107. return fmt.Errorf("textinput: ImmReleaseContext returned 0")
  108. }
  109. return nil
  110. }
  111. func _ImmSetCandidateWindow(unnamedParam1 _HIMC, lpCandidate *_CANDIDATEFORM) error {
  112. r, _, e := procImmSetCandidateWindow.Call(uintptr(unnamedParam1), uintptr(unsafe.Pointer(lpCandidate)))
  113. runtime.KeepAlive(lpCandidate)
  114. if int32(r) == 0 {
  115. if e != nil && e != windows.ERROR_SUCCESS {
  116. return fmt.Errorf("textinput: ImmSetCandidateWindow failed: %w", e)
  117. }
  118. return fmt.Errorf("textinput: ImmSetCandidateWindow returned 0")
  119. }
  120. return nil
  121. }
  122. func _SetWindowLongPtrW(hWnd windows.HWND, nIndex int32, dwNewLong uintptr) (uintptr, error) {
  123. var p *windows.LazyProc
  124. if procSetWindowLongPtrW.Find() == nil {
  125. // 64-Bit Windows.
  126. p = procSetWindowLongPtrW
  127. } else {
  128. // 32-Bit Windows.
  129. p = procSetWindowLongW
  130. }
  131. h, _, e := p.Call(uintptr(hWnd), uintptr(nIndex), dwNewLong)
  132. if h == 0 {
  133. if e != nil && e != windows.ERROR_SUCCESS {
  134. return 0, fmt.Errorf("textinput: SetWindowLongPtrW failed: %w", e)
  135. }
  136. return 0, fmt.Errorf("textinput: SetWindowLongPtrW returned 0")
  137. }
  138. return h, nil
  139. }