scroll_helper.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. // +build windows
  2. package winterm
  3. // effectiveSr gets the current effective scroll region in buffer coordinates
  4. func (h *windowsAnsiEventHandler) effectiveSr(window SMALL_RECT) scrollRegion {
  5. top := addInRange(window.Top, h.sr.top, window.Top, window.Bottom)
  6. bottom := addInRange(window.Top, h.sr.bottom, window.Top, window.Bottom)
  7. if top >= bottom {
  8. top = window.Top
  9. bottom = window.Bottom
  10. }
  11. return scrollRegion{top: top, bottom: bottom}
  12. }
  13. func (h *windowsAnsiEventHandler) scrollUp(param int) error {
  14. info, err := GetConsoleScreenBufferInfo(h.fd)
  15. if err != nil {
  16. return err
  17. }
  18. sr := h.effectiveSr(info.Window)
  19. return h.scroll(param, sr, info)
  20. }
  21. func (h *windowsAnsiEventHandler) scrollDown(param int) error {
  22. return h.scrollUp(-param)
  23. }
  24. func (h *windowsAnsiEventHandler) deleteLines(param int) error {
  25. info, err := GetConsoleScreenBufferInfo(h.fd)
  26. if err != nil {
  27. return err
  28. }
  29. start := info.CursorPosition.Y
  30. sr := h.effectiveSr(info.Window)
  31. // Lines cannot be inserted or deleted outside the scrolling region.
  32. if start >= sr.top && start <= sr.bottom {
  33. sr.top = start
  34. return h.scroll(param, sr, info)
  35. } else {
  36. return nil
  37. }
  38. }
  39. func (h *windowsAnsiEventHandler) insertLines(param int) error {
  40. return h.deleteLines(-param)
  41. }
  42. // scroll scrolls the provided scroll region by param lines. The scroll region is in buffer coordinates.
  43. func (h *windowsAnsiEventHandler) scroll(param int, sr scrollRegion, info *CONSOLE_SCREEN_BUFFER_INFO) error {
  44. h.logf("scroll: scrollTop: %d, scrollBottom: %d", sr.top, sr.bottom)
  45. h.logf("scroll: windowTop: %d, windowBottom: %d", info.Window.Top, info.Window.Bottom)
  46. // Copy from and clip to the scroll region (full buffer width)
  47. scrollRect := SMALL_RECT{
  48. Top: sr.top,
  49. Bottom: sr.bottom,
  50. Left: 0,
  51. Right: info.Size.X - 1,
  52. }
  53. // Origin to which area should be copied
  54. destOrigin := COORD{
  55. X: 0,
  56. Y: sr.top - int16(param),
  57. }
  58. char := CHAR_INFO{
  59. UnicodeChar: ' ',
  60. Attributes: h.attributes,
  61. }
  62. if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil {
  63. return err
  64. }
  65. return nil
  66. }
  67. func (h *windowsAnsiEventHandler) deleteCharacters(param int) error {
  68. info, err := GetConsoleScreenBufferInfo(h.fd)
  69. if err != nil {
  70. return err
  71. }
  72. return h.scrollLine(param, info.CursorPosition, info)
  73. }
  74. func (h *windowsAnsiEventHandler) insertCharacters(param int) error {
  75. return h.deleteCharacters(-param)
  76. }
  77. // scrollLine scrolls a line horizontally starting at the provided position by a number of columns.
  78. func (h *windowsAnsiEventHandler) scrollLine(columns int, position COORD, info *CONSOLE_SCREEN_BUFFER_INFO) error {
  79. // Copy from and clip to the scroll region (full buffer width)
  80. scrollRect := SMALL_RECT{
  81. Top: position.Y,
  82. Bottom: position.Y,
  83. Left: position.X,
  84. Right: info.Size.X - 1,
  85. }
  86. // Origin to which area should be copied
  87. destOrigin := COORD{
  88. X: position.X - int16(columns),
  89. Y: position.Y,
  90. }
  91. char := CHAR_INFO{
  92. UnicodeChar: ' ',
  93. Attributes: h.attributes,
  94. }
  95. if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil {
  96. return err
  97. }
  98. return nil
  99. }