Class: ScreenTracker

Inherits:
Object
  • Object
show all
Defined in:
lib/screen_tracker.rb

Constant Summary collapse

DIGIT_TYPES =
[:hours, :minute_tens, :minute_ones, :second_tens, :second_ones]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name_or_regex, x, y, width, height, digits = nil, callback = nil) ⇒ ScreenTracker

digits are like => [100,5], :minute_tens, :minute_ones, :second_tens, :second_ones digits share the height start point, have their own x and width…



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/screen_tracker.rb', line 20

def initialize name_or_regex,x,y,width,height,digits=nil,callback=nil
  # cache to save us 0.00445136 per time LOL
  @name_or_regex = name_or_regex
  get_hwnd
  pps 'height', height, 'width', width if $VERBOSE
  raise 'poor dimentia' if width <= 0 || height <= 0
  max_x, max_y = Win32::Screenshot::Util.dimensions_for(@hwnd)
  if(x < 0 || y < 0)
    if x < 0
      x = max_x + x
    end
    if y < 0
      y = max_y + y
    end
  end
  @height = height
  @x = x; @y = y; @x2 = x+width; @y2 = y+height; @callback = callback    
  @max_x = max_x
  raise 'poor width or wrong window' if @x2 > max_x  || @x2 == x
  raise 'poor height or wrong window' if @y2 > max_y || @y2 == y
  @digits = digits
  @displayed_warning = false
  pps 'using x',@x, 'from x', x, 'y', @y, 'from y', y,'x2',@x2,'y2',@y2,'digits', @digits if $VERBOSE
end

Instance Attribute Details

#hwndObject

Returns the value of attribute hwnd.



16
17
18
# File 'lib/screen_tracker.rb', line 16

def hwnd
  @hwnd
end

Class Method Details

.new_from_yaml(yaml, callback) ⇒ Object



8
9
10
11
12
13
14
# File 'lib/screen_tracker.rb', line 8

def self.new_from_yaml yaml, callback
  settings = YAML.load yaml
  # heigth is shared...
  height = settings["height"]
  digits = settings["digits"]
  return new(settings["name"], settings["x"], settings["y"], settings["width"], settings["height"], digits, callback)
end

Instance Method Details

#attempt_to_get_time_from_screenObject



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/screen_tracker.rb', line 151

def attempt_to_get_time_from_screen
  out = {}
  dump_digits if $DEBUG            
  digits = get_digits_as_bitmaps # 0.08s [!] not too accurate...ltodo
  start = Time.now
  DIGIT_TYPES.each{|type|
    if digits[type]
      digit = identify_digit(digits[type])
      unless digit
        if $DEBUG || $VERBOSE
          @a ||= 1
          @a += 1
          @already_wrote ||= {}
          unless @already_wrote[digits[type]]
            p 'unable to identify capture!' + type.to_s + @a.to_s
            File.binwrite("bad_digit#{@a}#{type}.bmp", digits[type]) unless type == :hours
            @already_wrote[digits[type]] = true
          end
        end
        if type == :hours
          digit = 0 # this one can fail in VLC
        else
          # early return
          p 'identity failure ' + type.to_s if $VERBOSE
          return
        end
      end
      out[type] = digit
    else
      # there isn't one specified as being on screen, so assume it is always zero (like youtube hour)...
      out[type] = 0
    end
  }
  out = "%d:%d%d:%d%d" % DIGIT_TYPES.map{ |type| out[type] }
  puts '', 'got new screen time ' + out + " tracking delta:" + (Time.now - start).to_s if $VERBOSE
  return out, Time.now-start
end

#dump_bmp(filename = 'dump.bmp') ⇒ Object

writes out all screen tracking info to various files in the current pwd



77
78
79
80
81
# File 'lib/screen_tracker.rb', line 77

def dump_bmp filename = 'dump.bmp'
  File.binwrite filename, get_bmp
  File.binwrite 'all.' + filename, get_full_bmp
  dump_digits
end

#dump_digitsObject



83
84
85
86
87
88
89
90
91
92
# File 'lib/screen_tracker.rb', line 83

def dump_digits
  if @digits
    @digit_count ||= 1
    @digit_count += 1
    for type, bitmap in get_digits_as_bitmaps
      File.binwrite type.to_s + '.' + @digit_count.to_s + '.bmp', bitmap
    end
    print 'wrote digits:', @digit_count, "\n"
  end
end

#get_bmpObject

gets the snapshot of “all the digits together”



66
67
68
69
# File 'lib/screen_tracker.rb', line 66

def get_bmp
  # Note: we no longer bring the window to the front tho...which it needs to be in both XP and Vista to work...sigh.
  Win32::Screenshot::BitmapMaker.capture_area(@hwnd,@x,@y,@x2,@y2) {|h,w,bmp| return bmp}
end

#get_digits_as_bitmapsObject

returns like {:hours => nil, :minutes_tens => raw_bmp, …



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/screen_tracker.rb', line 96

def get_digits_as_bitmaps
  # @digits are like {:hours => [100,5], :minute_tens => [x, width], :minute_ones, :second_tens, :second_ones}
  out = {}
  for type in DIGIT_TYPES
    assert @digits.key?(type)
    if @digits[type]
      x,w = @digits[type]
      if(x < 0)
        x = @max_x + x
      end
      out[type] = Win32::Screenshot::BitmapMaker.capture_area(@hwnd, x, @y, x+w, @y2) {|h,w,bmp| bmp}
    end
  end
  out
end

#get_full_bmpObject

gets snapshot of the full window



72
73
74
# File 'lib/screen_tracker.rb', line 72

def get_full_bmp
   Win32::Screenshot::BitmapMaker.capture_all(@hwnd) {|h,w,bmp| return bmp}
end

#get_hwndObject



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/screen_tracker.rb', line 45

def get_hwnd
  if @name_or_regex.to_s.downcase == 'desktop'
    # full screen option
    @hwnd = hwnd = Win32::Screenshot::BitmapMaker.desktop_window
  else
    @hwnd = Win32::Screenshot::BitmapMaker.hwnd(@name_or_regex)
  end

  unless @hwnd
    until @hwnd
      print 'perhaps not running yet? [%s]' % @name_or_regex
      sleep 1
      STDOUT.flush
      @hwnd = Win32::Screenshot::BitmapMaker.hwnd(@name_or_regex)
    end
    puts 'found window'
  end

end

#get_relative_coordsObject



112
113
114
# File 'lib/screen_tracker.rb', line 112

def get_relative_coords
  [@x,@y,@x2,@y2]
end

#identify_digit(bitmap) ⇒ Object

split out for unit testing purposes



117
118
119
# File 'lib/screen_tracker.rb', line 117

def identify_digit bitmap
  OCR.identify_digit(bitmap, @digits)
end

#process_forever_in_threadObject



189
190
191
192
193
194
195
196
# File 'lib/screen_tracker.rb', line 189

def process_forever_in_thread
  Thread.new {
    loop {
      out_time, delta = wait_till_next_change
      @callback.timestamp_changed out_time, delta
    }
  }
end

#wait_till_next_changeObject



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/screen_tracker.rb', line 121

def wait_till_next_change
  original = get_bmp
  time_since_last = Time.now
  loop {
    current = get_bmp
    if current != original
      if @digits
        got = attempt_to_get_time_from_screen
        if @displayed_warning && got
          # reassure user :)
          p 'tracking it successfully again' 
          @displayed_warning = false
        end
        return got
      else
        puts 'screen time change only detected...'
        return
      end
    end
    sleep 0.02
    if(Time.now - time_since_last > 5)
      p 'warning--unable to track screen time for some reason' unless @displayed_warning
      time_since_last = Time.now
      @displayed_warning = true
      # reget window, just in case that's the problem...
      get_hwnd
    end
  }
end