event.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. // Copyright 2018 visualfc. All rights reserved.
  2. package tk
  3. import (
  4. "fmt"
  5. "strconv"
  6. "strings"
  7. "unicode/utf8"
  8. )
  9. type Event struct {
  10. //The type field from the event. Valid for all event types.
  11. Type int
  12. //The send_event field from the event. Valid for all event types.
  13. //0 indicates that this is a “normal” event, 1 indicates that it is a “synthetic” event generated by SendEvent.
  14. Synthetic bool
  15. //The path name of the window to which the event was reported (the window field from the event). Valid for all event types.
  16. Widget Widget
  17. //The time field from the event. This is the X server timestamp (typically the time since the last server reset) in milliseconds,
  18. //when the event occurred. Valid for most events.
  19. Timestamp int64
  20. //The number of the button that was pressed or released.
  21. //Valid only for ButtonPress and ButtonRelease events.
  22. MouseButton int
  23. //The x and y fields from the event. For ButtonPress, ButtonRelease, Motion, KeyPress, KeyRelease, and MouseWheel events,
  24. //%x and %y indicate the position of the mouse pointer relative to the receiving window.
  25. //For Enter and Leave events, the position where the mouse pointer crossed the window, relative to the receiving window.
  26. //For Configure and Create requests, the x and y coordinates of the window relative to its parent window.
  27. PosX int
  28. PosY int
  29. GlobalPosX int
  30. GlobalPosY int
  31. //This reports the delta value of a MouseWheel event.
  32. //The delta value represents the rotation units the mouse wheel has been moved.
  33. //The sign of the value represents the direction the mouse wheel was scrolled.
  34. WheelDelta int
  35. //The keycode field from the event. Valid only for KeyPress and KeyRelease events.
  36. KeyCode int
  37. KeySym string
  38. KeyText string
  39. KeyRune rune
  40. //The detail or user_data field from the event. The %d is replaced by a string identifying the detail.
  41. //For Enter, Leave, FocusIn, and FocusOut events, the string will be one of the following:
  42. //NotifyAncestor NotifyNonlinearVirtual NotifyDetailNone
  43. //NotifyPointer NotifyInferior NotifyPointerRoot NotifyNonlinear NotifyVirtual
  44. //For ConfigureRequest events, the string will be one of:
  45. //Above Opposite Below None BottomIf TopIf
  46. //For virtual events, the string will be whatever value is stored in the user_data field when the event was created (typically with event generate),
  47. //or the empty string if the field is NULL. Virtual events corresponding to key sequence presses (see event add for details) set the user_data to NULL.
  48. //For events other than these, the substituted string is undefined.
  49. UserData string
  50. //The focus field from the event (0 or 1). Valid only for Enter and Leave events.
  51. //1 if the receiving window is the focus window or a descendant of the focus window, 0 otherwise.
  52. Focus bool
  53. //The width/height field from the event. Valid for the Configure, ConfigureRequest, Create, ResizeRequest, and Expose events.
  54. //Indicates the new or requested width/height of the window.
  55. Width int
  56. Height int
  57. //The mode field from the event. The substituted string is one of NotifyNormal, NotifyGrab, NotifyUngrab, or NotifyWhileGrabbed.
  58. //Valid only for Enter, FocusIn, FocusOut, and Leave events.
  59. Mode string
  60. //The override_redirect field from the event. Valid only for Map, Reparent, and Configure events.
  61. OverrideRedirect string
  62. //The place field from the event, substituted as one of the strings PlaceOnTop or PlaceOnBottom.
  63. //Valid only for Circulate and CirculateRequest events.
  64. Place string
  65. //The state field from the event. For ButtonPress, ButtonRelease, Enter, KeyPress, KeyRelease, Leave, and Motion events,
  66. //a decimal string is substituted. For Visibility, one of the strings VisibilityUnobscured, VisibilityPartiallyObscured, and VisibilityFullyObscured is substituted.
  67. //For Property events, substituted with either the string NewValue (indicating that the property has been created or modified) or Delete (indicating that the property has been removed).
  68. State string
  69. }
  70. func (e *Event) params() string {
  71. return "%T %E %W %t %b %x %y %D %k %K %A %d %f %w %h %m %o %p %s %X %Y"
  72. }
  73. func (e *Event) parser(args []string) {
  74. e.Type = e.toInt(args[0])
  75. e.Synthetic = e.toBool(args[1])
  76. e.Widget = FindWidget(args[2])
  77. e.Timestamp = e.toInt64(args[3])
  78. if e.Timestamp < 0 {
  79. e.Timestamp = 0
  80. }
  81. e.MouseButton = e.toInt(args[4])
  82. e.PosX = e.toInt(args[5])
  83. e.PosY = e.toInt(args[6])
  84. e.WheelDelta = e.toInt(args[7])
  85. e.KeyCode = e.toInt(args[8])
  86. e.KeySym = e.toString(args[9])
  87. e.KeyText = e.toString(args[10])
  88. if e.KeyText != "" {
  89. e.KeyRune, _ = utf8.DecodeRuneInString(e.KeyText)
  90. }
  91. e.UserData = e.toString(args[11])
  92. e.Focus = e.toBool(args[12])
  93. e.Width = e.toInt(args[13])
  94. e.Height = e.toInt(args[14])
  95. e.Mode = e.toString(args[15])
  96. e.OverrideRedirect = e.toString(args[16])
  97. e.Place = e.toString(args[17])
  98. e.State = e.toString(args[18])
  99. e.GlobalPosX = e.toInt(args[19])
  100. e.GlobalPosY = e.toInt(args[20])
  101. }
  102. func (e *Event) toInt(s string) int {
  103. v, _ := strconv.ParseInt(s, 10, 0)
  104. return int(v)
  105. }
  106. func (e *Event) toInt64(s string) int64 {
  107. v, _ := strconv.ParseInt(s, 10, 0)
  108. return v
  109. }
  110. func (e *Event) toBool(s string) bool {
  111. if s == "1" {
  112. return true
  113. }
  114. return false
  115. }
  116. func (e *Event) toString(s string) string {
  117. if s == "??" {
  118. return ""
  119. }
  120. return s
  121. }
  122. type KeyModifier int
  123. const (
  124. KeyModifierNone KeyModifier = 1 << iota
  125. KeyModifierShift
  126. KeyModifierControl
  127. KeyModifierAlt
  128. KeyModifierMeta
  129. KeyModifierFn
  130. )
  131. func (k KeyModifier) String() string {
  132. var ar []string
  133. if k&KeyModifierShift == KeyModifierShift {
  134. ar = append(ar, "Shift")
  135. }
  136. if k&KeyModifierControl == KeyModifierControl {
  137. ar = append(ar, "Control")
  138. }
  139. if k&KeyModifierAlt == KeyModifierAlt {
  140. ar = append(ar, "Alt")
  141. }
  142. if k&KeyModifierMeta == KeyModifierMeta {
  143. ar = append(ar, "Meta")
  144. }
  145. return strings.Join(ar, " ")
  146. }
  147. type KeyEvent struct {
  148. *Event
  149. KeyModifier KeyModifier
  150. }
  151. func (e *KeyEvent) addModifier(sym string, name string, mod KeyModifier) {
  152. if strings.HasPrefix(sym, name) {
  153. e.KeyModifier |= mod
  154. }
  155. }
  156. func (e *KeyEvent) removeModifier(sym string, name string, mod KeyModifier) {
  157. if strings.HasPrefix(sym, name) {
  158. if e.KeyModifier&mod == mod {
  159. e.KeyModifier ^= mod
  160. }
  161. }
  162. }
  163. //TODO: almost check key modifier
  164. func BindKeyEventEx(tag string, fnPress func(e *KeyEvent), fnRelease func(e *KeyEvent)) error {
  165. var ke KeyEvent
  166. var err error
  167. err = BindEvent(tag, "<KeyPress>", func(e *Event) {
  168. ke.addModifier(e.KeySym, "Shift_", KeyModifierShift)
  169. ke.addModifier(e.KeySym, "Control_", KeyModifierControl)
  170. ke.addModifier(e.KeySym, "Alt_", KeyModifierAlt)
  171. ke.addModifier(e.KeySym, "Meta_", KeyModifierMeta)
  172. ke.addModifier(e.KeySym, "Super_", KeyModifierFn)
  173. ke.Event = e
  174. if fnPress != nil {
  175. fnPress(&ke)
  176. }
  177. })
  178. if err != nil {
  179. return err
  180. }
  181. err = BindEvent(tag, "<KeyRelease>", func(e *Event) {
  182. ke.Event = e
  183. if fnRelease != nil {
  184. fnRelease(&ke)
  185. }
  186. ke.removeModifier(e.KeySym, "Shift_", KeyModifierShift)
  187. ke.removeModifier(e.KeySym, "Control_", KeyModifierControl)
  188. ke.removeModifier(e.KeySym, "Alt_", KeyModifierAlt)
  189. ke.removeModifier(e.KeySym, "Meta_", KeyModifierMeta)
  190. ke.removeModifier(e.KeySym, "Super_", KeyModifierFn)
  191. })
  192. return err
  193. }
  194. func bindEventHelper(tag string, event string, fnid string, ev *Event, fn func()) error {
  195. mainInterp.CreateAction(fnid, func(args []string) {
  196. ev.parser(args)
  197. fn()
  198. })
  199. return eval(fmt.Sprintf("bind %v %v {%v %v}", tag, event, fnid, ev.params()))
  200. }
  201. func addEventHelper(tag string, event string, fnid string, ev *Event, fn func()) error {
  202. mainInterp.CreateAction(fnid, func(args []string) {
  203. ev.parser(args)
  204. fn()
  205. })
  206. return eval(fmt.Sprintf("bind %v %v {+%v %v}", tag, event, fnid, ev.params()))
  207. }
  208. func IsEvent(event string) bool {
  209. return strings.HasPrefix(event, "<") && strings.HasSuffix(event, ">")
  210. }
  211. func IsVirtualEvent(event string) bool {
  212. return strings.HasPrefix(event, "<<") && strings.HasSuffix(event, ">>")
  213. }
  214. // add bind event
  215. func BindEvent(tag string, event string, fn func(e *Event)) error {
  216. if tag == "" || !IsEvent(event) {
  217. return ErrInvalid
  218. }
  219. fnid := makeBindEventId()
  220. var ev Event
  221. return addEventHelper(tag, event, fnid, &ev, func() {
  222. fn(&ev)
  223. })
  224. }
  225. // clear tag event
  226. func ClearBindEvent(tag string, event string) error {
  227. if tag == "" || !IsEvent(event) {
  228. return ErrInvalid
  229. }
  230. return eval(fmt.Sprintf("bind %v %v {}", tag, event))
  231. }
  232. func BindInfo(tag string) []string {
  233. if tag == "" {
  234. return nil
  235. }
  236. v, _ := evalAsStringList(fmt.Sprintf("bind %v", tag))
  237. return v
  238. }
  239. //Associates the virtual event virtual with the physical event sequence(s)
  240. //given by the sequence arguments, so that the virtual event will trigger
  241. //whenever any one of the sequences occurs. Virtual may be any string value
  242. //and sequence may have any of the values allowed for the sequence argument
  243. // to the bind command. If virtual is already defined, the new physical event
  244. // sequences add to the existing sequences for the event.
  245. func AddVirtualEventPhysicalEvent(virtual string, event string, events ...string) error {
  246. if !IsVirtualEvent(virtual) {
  247. return ErrInvalid
  248. }
  249. eventList := append([]string{event}, events...)
  250. return eval(fmt.Sprintf("event add %v %v", virtual, strings.Join(eventList, " ")))
  251. }
  252. //Deletes each of the sequences from those associated with the virtual event
  253. // given by virtual. Virtual may be any string value and sequence may have
  254. //any of the values allowed for the sequence argument to the bind command.
  255. //Any sequences not currently associated with virtual are ignored.
  256. //If no sequence argument is provided, all physical event sequences are removed
  257. // for virtual, so that the virtual event will not trigger anymore.
  258. func RemoveVirtualEventPhysicalEvent(virtual string, events ...string) error {
  259. if !IsVirtualEvent(virtual) {
  260. return ErrInvalid
  261. }
  262. return eval(fmt.Sprintf("event remove %v %v", virtual, strings.Join(events, " ")))
  263. }
  264. func VirtualEventInfo(virtual string) []string {
  265. if !IsVirtualEvent(virtual) {
  266. return nil
  267. }
  268. r, _ := evalAsStringList(fmt.Sprintf("event info %v", virtual))
  269. return r
  270. }
  271. //TODO: event attr
  272. type EventAttr struct {
  273. key string
  274. value string
  275. }
  276. func NativeEventAttr(key string, value string) *EventAttr {
  277. return &EventAttr{key, value}
  278. }
  279. func SendEvent(widget Widget, event string, attrs ...*EventAttr) error {
  280. if !IsValidWidget(widget) {
  281. return ErrInvalid
  282. }
  283. return sendEvent(widget.Id(), event, attrs...)
  284. }
  285. func SendEventToFocus(event string, attrs ...*EventAttr) error {
  286. return sendEvent("[focus]", event, attrs...)
  287. }
  288. func sendEvent(id string, event string, attrs ...*EventAttr) error {
  289. if !IsEvent(event) {
  290. return ErrInvalid
  291. }
  292. var list []string
  293. for _, attr := range attrs {
  294. if attr == nil {
  295. continue
  296. }
  297. list = append(list, fmt.Sprintf("-%v {%v}", attr.key, attr.value))
  298. }
  299. var script string
  300. script = fmt.Sprintf("event generate %v %v", id, event)
  301. if len(list) > 0 {
  302. script += " " + strings.Join(list, " ")
  303. }
  304. return eval(script)
  305. }