clipboard.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. // Copyright 2013 The Walk Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // +build windows
  5. package walk
  6. import (
  7. "syscall"
  8. "unsafe"
  9. )
  10. import (
  11. "github.com/lxn/win"
  12. )
  13. const clipboardWindowClass = `\o/ Walk_Clipboard_Class \o/`
  14. func init() {
  15. MustRegisterWindowClass(clipboardWindowClass)
  16. hwnd := win.CreateWindowEx(
  17. 0,
  18. syscall.StringToUTF16Ptr(clipboardWindowClass),
  19. nil,
  20. 0,
  21. 0,
  22. 0,
  23. 0,
  24. 0,
  25. win.HWND_MESSAGE,
  26. 0,
  27. 0,
  28. nil)
  29. if hwnd == 0 {
  30. panic("failed to create clipboard window")
  31. }
  32. if !win.AddClipboardFormatListener(hwnd) {
  33. lastError("AddClipboardFormatListener")
  34. }
  35. clipboard.hwnd = hwnd
  36. }
  37. func clipboardWndProc(hwnd win.HWND, msg uint32, wp, lp uintptr) uintptr {
  38. switch msg {
  39. case win.WM_CLIPBOARDUPDATE:
  40. clipboard.contentsChangedPublisher.Publish()
  41. return 0
  42. }
  43. return win.DefWindowProc(hwnd, msg, wp, lp)
  44. }
  45. var clipboard ClipboardService
  46. // Clipboard returns an object that provides access to the system clipboard.
  47. func Clipboard() *ClipboardService {
  48. return &clipboard
  49. }
  50. // ClipboardService provides access to the system clipboard.
  51. type ClipboardService struct {
  52. hwnd win.HWND
  53. contentsChangedPublisher EventPublisher
  54. }
  55. // ContentsChanged returns an Event that you can attach to for handling
  56. // clipboard content changes.
  57. func (c *ClipboardService) ContentsChanged() *Event {
  58. return c.contentsChangedPublisher.Event()
  59. }
  60. // Clear clears the contents of the clipboard.
  61. func (c *ClipboardService) Clear() error {
  62. return c.withOpenClipboard(func() error {
  63. if !win.EmptyClipboard() {
  64. return lastError("EmptyClipboard")
  65. }
  66. return nil
  67. })
  68. }
  69. // ContainsText returns whether the clipboard currently contains text data.
  70. func (c *ClipboardService) ContainsText() (available bool, err error) {
  71. err = c.withOpenClipboard(func() error {
  72. available = win.IsClipboardFormatAvailable(win.CF_UNICODETEXT)
  73. return nil
  74. })
  75. return
  76. }
  77. // Text returns the current text data of the clipboard.
  78. func (c *ClipboardService) Text() (text string, err error) {
  79. err = c.withOpenClipboard(func() error {
  80. hMem := win.HGLOBAL(win.GetClipboardData(win.CF_UNICODETEXT))
  81. if hMem == 0 {
  82. return lastError("GetClipboardData")
  83. }
  84. p := win.GlobalLock(hMem)
  85. if p == nil {
  86. return lastError("GlobalLock()")
  87. }
  88. defer win.GlobalUnlock(hMem)
  89. text = win.UTF16PtrToString((*uint16)(p))
  90. return nil
  91. })
  92. return
  93. }
  94. // SetText sets the current text data of the clipboard.
  95. func (c *ClipboardService) SetText(s string) error {
  96. return c.withOpenClipboard(func() error {
  97. utf16, err := syscall.UTF16FromString(s)
  98. if err != nil {
  99. return err
  100. }
  101. hMem := win.GlobalAlloc(win.GMEM_MOVEABLE, uintptr(len(utf16)*2))
  102. if hMem == 0 {
  103. return lastError("GlobalAlloc")
  104. }
  105. p := win.GlobalLock(hMem)
  106. if p == nil {
  107. return lastError("GlobalLock()")
  108. }
  109. win.MoveMemory(p, unsafe.Pointer(&utf16[0]), uintptr(len(utf16)*2))
  110. win.GlobalUnlock(hMem)
  111. if 0 == win.SetClipboardData(win.CF_UNICODETEXT, win.HANDLE(hMem)) {
  112. // We need to free hMem.
  113. defer win.GlobalFree(hMem)
  114. return lastError("SetClipboardData")
  115. }
  116. // The system now owns the memory referred to by hMem.
  117. return nil
  118. })
  119. }
  120. func (c *ClipboardService) withOpenClipboard(f func() error) error {
  121. if !win.OpenClipboard(c.hwnd) {
  122. return lastError("OpenClipboard")
  123. }
  124. defer win.CloseClipboard()
  125. return f()
  126. }