epitools 0.5.7 → 0.5.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/epitools/sys.rb CHANGED
@@ -65,6 +65,7 @@ module Sys
65
65
 
66
66
  PS_FIELD_TABLE = [
67
67
  [:pid, :to_i],
68
+ [:ppid, :to_i],
68
69
  [:pcpu, :to_f],
69
70
  [:pmem, :to_f],
70
71
  [:stat, :to_s],
@@ -147,6 +148,15 @@ module Sys
147
148
  super(*args)
148
149
  end
149
150
 
151
+ def parent
152
+ Sys.ps(ppid).first unless ppid < 1
153
+ end
154
+
155
+ def children
156
+ @@parents ||= Sys.ps.group_by(&:ppid)
157
+ @@parents[pid]
158
+ end
159
+
150
160
  #
151
161
  # Convert all the process information to a hash.
152
162
  #
@@ -217,11 +227,21 @@ module Sys
217
227
 
218
228
  #-----------------------------------------------------------------------------
219
229
 
230
+ def self.tree
231
+ tree = Sys.ps.group_by(&:ppid)
232
+ Hash[tree.map do |ppid, children|
233
+ kvs = children.map { |child| [child.pid, tree.delete(child.pid)] }
234
+ [ppid, Hash[kvs]]
235
+ end]
236
+ end
237
+
220
238
  #
221
239
  # List all (or specified) processes, and return ProcessInfo objects.
222
240
  # (Takes an optional list of pids as arguments.)
223
241
  #
224
242
  def self.ps(*pids)
243
+ #return @@cache if @@cache
244
+
225
245
  options = PS_FIELDS.join(',')
226
246
 
227
247
  pids = pids.map(&:to_i)
@@ -229,7 +249,7 @@ module Sys
229
249
  if pids.any?
230
250
  command = "ps -p #{pids.join(',')} -o #{options}"
231
251
  else
232
- command = "ps ax -o #{options}"
252
+ command = "ps awx -o #{options}"
233
253
  end
234
254
 
235
255
  lines = `#{command}`.lines.to_a
@@ -248,6 +268,10 @@ module Sys
248
268
 
249
269
  #-----------------------------------------------------------------------------
250
270
 
271
+ def self.refresh
272
+ @@cache = nil
273
+ end
274
+
251
275
  #
252
276
  # Trap signals!
253
277
  #
data/lib/epitools/term.rb CHANGED
@@ -9,9 +9,9 @@
9
9
  module Term
10
10
 
11
11
  extend self
12
-
12
+
13
13
  attr_accessor :wrap, :x, :y
14
-
14
+
15
15
  #
16
16
  # Return the [width,height] of the terminal.
17
17
  #
@@ -21,37 +21,43 @@ module Term
21
21
  Curses.close_screen
22
22
  result
23
23
  end
24
-
24
+
25
25
  def width; size[0]; end
26
26
  def height; size[1]; end
27
27
  def goto(x,y); @x, @y = x, y; end
28
28
  def pos; [@x, @y]; end
29
-
29
+
30
30
  def color(fore, back=nil)
31
31
  @fore = fore
32
- @back = back if back
32
+ @back = back if back
33
33
  end
34
-
34
+
35
35
  def puts(s)
36
- # some curses shit
36
+ # some curses shit
37
37
  end
38
-
38
+
39
39
  class Window
40
40
  def initialize
41
41
  end
42
-
42
+
43
43
  def scroll(dx, dy)
44
44
  end
45
45
  end
46
-
46
+
47
47
  class Table
48
48
 
49
+ # TODO:
50
+ #
51
+ # * make Table's configuration eaiser to remember by putting the formatting parameters in initialize
52
+ # eg: Table.new(elements, :sort=>:vertical).to_s
53
+ #
54
+
49
55
  attr_accessor :border, :columns, :padding, :strip_color, :indent
50
-
56
+
51
57
  def self.[](data)
52
58
  self.new(data)
53
59
  end
54
-
60
+
55
61
  def initialize(data, options={})
56
62
  @data = data.map(&:to_s)
57
63
  @strip_color = options[:ansi] || options[:colorized] || options[:colored] || options[:strip_color] || options[:strip_ansi]
@@ -61,24 +67,24 @@ module Term
61
67
  else
62
68
  @max_size = @data.map(&:size).max
63
69
  end
64
-
70
+
65
71
  @indent = options[:indent] || 0
66
72
  @border = options[:border]
67
73
  @columns = options[:columns]
68
74
  @padding = options[:padding] || 1
69
75
  end
70
-
76
+
71
77
  def num_columns
72
78
  return @columns if @columns
73
79
  width, height = Term.size
74
80
  width -= indent
75
81
  (width-2) / (@max_size + @padding)
76
82
  end
77
-
83
+
78
84
  def num_rows
79
85
  (@data.size / num_columns.to_f).ceil
80
86
  end
81
-
87
+
82
88
  def column_order
83
89
  cols = []
84
90
  @data.each_slice(num_rows) { |col| cols << col }
@@ -96,7 +102,7 @@ module Term
96
102
  end
97
103
  rows
98
104
  end
99
-
105
+
100
106
  def sliced_into(n)
101
107
  elems = []
102
108
  @data.each_slice(n) { |e| elems << e }
@@ -105,32 +111,32 @@ module Term
105
111
  end
106
112
  elems
107
113
  end
108
-
114
+
109
115
  def by_columns
110
116
  return '' if @data.empty?
111
117
  render sliced_into(num_rows).transpose
112
118
  end
113
-
119
+
114
120
  def by_rows
115
121
  return '' if @data.empty?
116
122
  render sliced_into(num_columns)
117
123
  end
118
-
124
+
119
125
  def to_s
120
126
  by_rows
121
127
  end
122
-
128
+
123
129
  def render(rows, options={})
124
130
  num_cols = rows.first.size
125
131
  result = []
126
-
132
+
127
133
  if @border
128
134
  separator = "+#{(["-" * @max_size] * num_cols).join('+')}+"
129
135
  result << separator
130
- end
131
-
136
+ end
137
+
132
138
  for row in rows
133
-
139
+
134
140
  justified = row.map do |e|
135
141
  if (diff = @max_size - e.strip_color.size) > 0
136
142
  e = e + (" " * diff)
@@ -142,16 +148,16 @@ module Term
142
148
  line = "|#{justified.join('|')}|"
143
149
  else
144
150
  line = justified.join(' '*@padding)
145
- end
146
-
151
+ end
152
+
147
153
  result << (" "*indent) + line
148
154
  end
149
-
155
+
150
156
  result << separator if @border
151
-
157
+
152
158
  result.join("\n")
153
159
  end
154
-
160
+
155
161
  end
156
-
162
+
157
163
  end
data/lib/epitools/wm.rb CHANGED
@@ -4,10 +4,22 @@ module WM
4
4
 
5
5
  def self.windows; @windows ||= Window.all; end
6
6
  def self.desktops; @desktops ||= Desktop.all; end
7
- def self.processes; @processes ||= Hash[ Sys.ps.map { |process| [process.pid, process] } ] ; end
7
+ def self.processes; @processes ||= Hash[ Sys.ps.map { |pr| [pr.pid, pr] } ] ; end
8
8
  def self.current_desktop; @current ||= desktops.find { |d| d.current? }; end
9
9
  def self.sticky; @sticky ||= windows.select { |w| w.sticky? }; end
10
10
 
11
+ def self.window(pid)
12
+ results = windows.select { |w| w.pid }
13
+
14
+ if results.empty?
15
+ # check the children
16
+ results = windows.select { |w| w.process.children.any? {|pr| pr.pid == pid } }
17
+ end
18
+
19
+ results
20
+ end
21
+
22
+
11
23
  class Desktop < TypedStruct["num:int current:bool resolution viewport desktop_geometry name"]
12
24
  def self.all
13
25
  # 0 - DG: 1680x1050 VP: N/A WA: 0,25 1680x974 Workspace 1
@@ -40,7 +52,7 @@ module WM
40
52
  end
41
53
 
42
54
 
43
- class Window < TypedStruct["addr desktop_id:int pid:int x:int y:int w:int h:int hostname title"]
55
+ class Window < TypedStruct["window_id desktop_id:int pid:int x:int y:int w:int h:int hostname title"]
44
56
 
45
57
  def self.all
46
58
  `wmctrl -lpG`.lines.map(&:strip).map { |line| Window.from_line(line) }
@@ -70,14 +82,293 @@ module WM
70
82
  end
71
83
 
72
84
  alias_method :name, :title
85
+ alias_method :addr, :window_id
73
86
 
74
87
  def process
75
88
  WM.processes[pid]
76
89
  end
77
90
 
91
+ def command
92
+ process.command
93
+ end
94
+
78
95
  def inspect
79
96
  "{ ::#{name}:: [#{desktop_id}]}"
80
97
  end
98
+
99
+ def activate!
100
+ system "wmctrl", "-i", "-a", window_id
101
+ end
102
+
103
+ #
104
+ # string is made up of regular text, plus <>'d keypresses
105
+ # eg: "Hello<Ctrl-T><Ctrl-L><Ctrl-Shift-K><Return>!!!"
106
+ #
107
+ def send_keys(keys)
108
+ xse(keys)
109
+ end
110
+
111
+ #
112
+ # LATIN-1 XSendKey event names:
113
+ # ------------------------------------------------------
114
+ # (from /usr/include/X11/keysymdef.h, XK_LATIN1 section)
115
+ #
116
+ # space 0x0020 /* U+0020 SPACE */
117
+ # exclam 0x0021 /* U+0021 EXCLAMATION MARK */
118
+ # quotedbl 0x0022 /* U+0022 QUOTATION MARK */
119
+ # numbersign 0x0023 /* U+0023 NUMBER SIGN */
120
+ # dollar 0x0024 /* U+0024 DOLLAR SIGN */
121
+ # percent 0x0025 /* U+0025 PERCENT SIGN */
122
+ # ampersand 0x0026 /* U+0026 AMPERSAND */
123
+ # apostrophe 0x0027 /* U+0027 APOSTROPHE */
124
+ # quoteright 0x0027 /* deprecated */
125
+ # parenleft 0x0028 /* U+0028 LEFT PARENTHESIS */
126
+ # parenright 0x0029 /* U+0029 RIGHT PARENTHESIS */
127
+ # asterisk 0x002a /* U+002A ASTERISK */
128
+ # plus 0x002b /* U+002B PLUS SIGN */
129
+ # comma 0x002c /* U+002C COMMA */
130
+ # minus 0x002d /* U+002D HYPHEN-MINUS */
131
+ # period 0x002e /* U+002E FULL STOP */
132
+ # slash 0x002f /* U+002F SOLIDUS */
133
+ # 0 0x0030 /* U+0030 DIGIT ZERO */
134
+ # 1 0x0031 /* U+0031 DIGIT ONE */
135
+ # 2 0x0032 /* U+0032 DIGIT TWO */
136
+ # 3 0x0033 /* U+0033 DIGIT THREE */
137
+ # 4 0x0034 /* U+0034 DIGIT FOUR */
138
+ # 5 0x0035 /* U+0035 DIGIT FIVE */
139
+ # 6 0x0036 /* U+0036 DIGIT SIX */
140
+ # 7 0x0037 /* U+0037 DIGIT SEVEN */
141
+ # 8 0x0038 /* U+0038 DIGIT EIGHT */
142
+ # 9 0x0039 /* U+0039 DIGIT NINE */
143
+ # colon 0x003a /* U+003A COLON */
144
+ # semicolon 0x003b /* U+003B SEMICOLON */
145
+ # less 0x003c /* U+003C LESS-THAN SIGN */
146
+ # equal 0x003d /* U+003D EQUALS SIGN */
147
+ # greater 0x003e /* U+003E GREATER-THAN SIGN */
148
+ # question 0x003f /* U+003F QUESTION MARK */
149
+ # at 0x0040 /* U+0040 COMMERCIAL AT */
150
+ # A 0x0041 /* U+0041 LATIN CAPITAL LETTER A */
151
+ # B 0x0042 /* U+0042 LATIN CAPITAL LETTER B */
152
+ # C 0x0043 /* U+0043 LATIN CAPITAL LETTER C */
153
+ # D 0x0044 /* U+0044 LATIN CAPITAL LETTER D */
154
+ # E 0x0045 /* U+0045 LATIN CAPITAL LETTER E */
155
+ # F 0x0046 /* U+0046 LATIN CAPITAL LETTER F */
156
+ # G 0x0047 /* U+0047 LATIN CAPITAL LETTER G */
157
+ # H 0x0048 /* U+0048 LATIN CAPITAL LETTER H */
158
+ # I 0x0049 /* U+0049 LATIN CAPITAL LETTER I */
159
+ # J 0x004a /* U+004A LATIN CAPITAL LETTER J */
160
+ # K 0x004b /* U+004B LATIN CAPITAL LETTER K */
161
+ # L 0x004c /* U+004C LATIN CAPITAL LETTER L */
162
+ # M 0x004d /* U+004D LATIN CAPITAL LETTER M */
163
+ # N 0x004e /* U+004E LATIN CAPITAL LETTER N */
164
+ # O 0x004f /* U+004F LATIN CAPITAL LETTER O */
165
+ # P 0x0050 /* U+0050 LATIN CAPITAL LETTER P */
166
+ # Q 0x0051 /* U+0051 LATIN CAPITAL LETTER Q */
167
+ # R 0x0052 /* U+0052 LATIN CAPITAL LETTER R */
168
+ # S 0x0053 /* U+0053 LATIN CAPITAL LETTER S */
169
+ # T 0x0054 /* U+0054 LATIN CAPITAL LETTER T */
170
+ # U 0x0055 /* U+0055 LATIN CAPITAL LETTER U */
171
+ # V 0x0056 /* U+0056 LATIN CAPITAL LETTER V */
172
+ # W 0x0057 /* U+0057 LATIN CAPITAL LETTER W */
173
+ # X 0x0058 /* U+0058 LATIN CAPITAL LETTER X */
174
+ # Y 0x0059 /* U+0059 LATIN CAPITAL LETTER Y */
175
+ # Z 0x005a /* U+005A LATIN CAPITAL LETTER Z */
176
+ # bracketleft 0x005b /* U+005B LEFT SQUARE BRACKET */
177
+ # backslash 0x005c /* U+005C REVERSE SOLIDUS */
178
+ # bracketright 0x005d /* U+005D RIGHT SQUARE BRACKET */
179
+ # asciicircum 0x005e /* U+005E CIRCUMFLEX ACCENT */
180
+ # underscore 0x005f /* U+005F LOW LINE */
181
+ # grave 0x0060 /* U+0060 GRAVE ACCENT */
182
+ # quoteleft 0x0060 /* deprecated */
183
+ # a 0x0061 /* U+0061 LATIN SMALL LETTER A */
184
+ # b 0x0062 /* U+0062 LATIN SMALL LETTER B */
185
+ # c 0x0063 /* U+0063 LATIN SMALL LETTER C */
186
+ # d 0x0064 /* U+0064 LATIN SMALL LETTER D */
187
+ # e 0x0065 /* U+0065 LATIN SMALL LETTER E */
188
+ # f 0x0066 /* U+0066 LATIN SMALL LETTER F */
189
+ # g 0x0067 /* U+0067 LATIN SMALL LETTER G */
190
+ # h 0x0068 /* U+0068 LATIN SMALL LETTER H */
191
+ # i 0x0069 /* U+0069 LATIN SMALL LETTER I */
192
+ # j 0x006a /* U+006A LATIN SMALL LETTER J */
193
+ # k 0x006b /* U+006B LATIN SMALL LETTER K */
194
+ # l 0x006c /* U+006C LATIN SMALL LETTER L */
195
+ # m 0x006d /* U+006D LATIN SMALL LETTER M */
196
+ # n 0x006e /* U+006E LATIN SMALL LETTER N */
197
+ # o 0x006f /* U+006F LATIN SMALL LETTER O */
198
+ # p 0x0070 /* U+0070 LATIN SMALL LETTER P */
199
+ # q 0x0071 /* U+0071 LATIN SMALL LETTER Q */
200
+ # r 0x0072 /* U+0072 LATIN SMALL LETTER R */
201
+ # s 0x0073 /* U+0073 LATIN SMALL LETTER S */
202
+ # t 0x0074 /* U+0074 LATIN SMALL LETTER T */
203
+ # u 0x0075 /* U+0075 LATIN SMALL LETTER U */
204
+ # v 0x0076 /* U+0076 LATIN SMALL LETTER V */
205
+ # w 0x0077 /* U+0077 LATIN SMALL LETTER W */
206
+ # x 0x0078 /* U+0078 LATIN SMALL LETTER X */
207
+ # y 0x0079 /* U+0079 LATIN SMALL LETTER Y */
208
+ # z 0x007a /* U+007A LATIN SMALL LETTER Z */
209
+ # braceleft 0x007b /* U+007B LEFT CURLY BRACKET */
210
+ # bar 0x007c /* U+007C VERTICAL LINE */
211
+ # braceright 0x007d /* U+007D RIGHT CURLY BRACKET */
212
+ # asciitilde 0x007e /* U+007E TILDE */
213
+ # nobreakspace 0x00a0 /* U+00A0 NO-BREAK SPACE */
214
+ # exclamdown 0x00a1 /* U+00A1 INVERTED EXCLAMATION MARK */
215
+ # cent 0x00a2 /* U+00A2 CENT SIGN */
216
+ # sterling 0x00a3 /* U+00A3 POUND SIGN */
217
+ # currency 0x00a4 /* U+00A4 CURRENCY SIGN */
218
+ # yen 0x00a5 /* U+00A5 YEN SIGN */
219
+ # brokenbar 0x00a6 /* U+00A6 BROKEN BAR */
220
+ # section 0x00a7 /* U+00A7 SECTION SIGN */
221
+ # diaeresis 0x00a8 /* U+00A8 DIAERESIS */
222
+ # copyright 0x00a9 /* U+00A9 COPYRIGHT SIGN */
223
+ # ordfeminine 0x00aa /* U+00AA FEMININE ORDINAL INDICATOR */
224
+ # guillemotleft 0x00ab /* U+00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */
225
+ # notsign 0x00ac /* U+00AC NOT SIGN */
226
+ # hyphen 0x00ad /* U+00AD SOFT HYPHEN */
227
+ # registered 0x00ae /* U+00AE REGISTERED SIGN */
228
+ # macron 0x00af /* U+00AF MACRON */
229
+ # degree 0x00b0 /* U+00B0 DEGREE SIGN */
230
+ # plusminus 0x00b1 /* U+00B1 PLUS-MINUS SIGN */
231
+ # twosuperior 0x00b2 /* U+00B2 SUPERSCRIPT TWO */
232
+ # threesuperior 0x00b3 /* U+00B3 SUPERSCRIPT THREE */
233
+ # acute 0x00b4 /* U+00B4 ACUTE ACCENT */
234
+ # mu 0x00b5 /* U+00B5 MICRO SIGN */
235
+ # paragraph 0x00b6 /* U+00B6 PILCROW SIGN */
236
+ # periodcentered 0x00b7 /* U+00B7 MIDDLE DOT */
237
+ # cedilla 0x00b8 /* U+00B8 CEDILLA */
238
+ # onesuperior 0x00b9 /* U+00B9 SUPERSCRIPT ONE */
239
+ # masculine 0x00ba /* U+00BA MASCULINE ORDINAL INDICATOR */
240
+ # guillemotright 0x00bb /* U+00BB RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */
241
+ # onequarter 0x00bc /* U+00BC VULGAR FRACTION ONE QUARTER */
242
+ # onehalf 0x00bd /* U+00BD VULGAR FRACTION ONE HALF */
243
+ # threequarters 0x00be /* U+00BE VULGAR FRACTION THREE QUARTERS */
244
+ # questiondown 0x00bf /* U+00BF INVERTED QUESTION MARK */
245
+ # Agrave 0x00c0 /* U+00C0 LATIN CAPITAL LETTER A WITH GRAVE */
246
+ # Aacute 0x00c1 /* U+00C1 LATIN CAPITAL LETTER A WITH ACUTE */
247
+ # Acircumflex 0x00c2 /* U+00C2 LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
248
+ # Atilde 0x00c3 /* U+00C3 LATIN CAPITAL LETTER A WITH TILDE */
249
+ # Adiaeresis 0x00c4 /* U+00C4 LATIN CAPITAL LETTER A WITH DIAERESIS */
250
+ # Aring 0x00c5 /* U+00C5 LATIN CAPITAL LETTER A WITH RING ABOVE */
251
+ # AE 0x00c6 /* U+00C6 LATIN CAPITAL LETTER AE */
252
+ # Ccedilla 0x00c7 /* U+00C7 LATIN CAPITAL LETTER C WITH CEDILLA */
253
+ # Egrave 0x00c8 /* U+00C8 LATIN CAPITAL LETTER E WITH GRAVE */
254
+ # Eacute 0x00c9 /* U+00C9 LATIN CAPITAL LETTER E WITH ACUTE */
255
+ # Ecircumflex 0x00ca /* U+00CA LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
256
+ # Ediaeresis 0x00cb /* U+00CB LATIN CAPITAL LETTER E WITH DIAERESIS */
257
+ # Igrave 0x00cc /* U+00CC LATIN CAPITAL LETTER I WITH GRAVE */
258
+ # Iacute 0x00cd /* U+00CD LATIN CAPITAL LETTER I WITH ACUTE */
259
+ # Icircumflex 0x00ce /* U+00CE LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
260
+ # Idiaeresis 0x00cf /* U+00CF LATIN CAPITAL LETTER I WITH DIAERESIS */
261
+ # ETH 0x00d0 /* U+00D0 LATIN CAPITAL LETTER ETH */
262
+ # Eth 0x00d0 /* deprecated */
263
+ # Ntilde 0x00d1 /* U+00D1 LATIN CAPITAL LETTER N WITH TILDE */
264
+ # Ograve 0x00d2 /* U+00D2 LATIN CAPITAL LETTER O WITH GRAVE */
265
+ # Oacute 0x00d3 /* U+00D3 LATIN CAPITAL LETTER O WITH ACUTE */
266
+ # Ocircumflex 0x00d4 /* U+00D4 LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
267
+ # Otilde 0x00d5 /* U+00D5 LATIN CAPITAL LETTER O WITH TILDE */
268
+ # Odiaeresis 0x00d6 /* U+00D6 LATIN CAPITAL LETTER O WITH DIAERESIS */
269
+ # multiply 0x00d7 /* U+00D7 MULTIPLICATION SIGN */
270
+ # Oslash 0x00d8 /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE */
271
+ # Ooblique 0x00d8 /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE */
272
+ # Ugrave 0x00d9 /* U+00D9 LATIN CAPITAL LETTER U WITH GRAVE */
273
+ # Uacute 0x00da /* U+00DA LATIN CAPITAL LETTER U WITH ACUTE */
274
+ # Ucircumflex 0x00db /* U+00DB LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
275
+ # Udiaeresis 0x00dc /* U+00DC LATIN CAPITAL LETTER U WITH DIAERESIS */
276
+ # Yacute 0x00dd /* U+00DD LATIN CAPITAL LETTER Y WITH ACUTE */
277
+ # THORN 0x00de /* U+00DE LATIN CAPITAL LETTER THORN */
278
+ # Thorn 0x00de /* deprecated */
279
+ # ssharp 0x00df /* U+00DF LATIN SMALL LETTER SHARP S */
280
+ # agrave 0x00e0 /* U+00E0 LATIN SMALL LETTER A WITH GRAVE */
281
+ # aacute 0x00e1 /* U+00E1 LATIN SMALL LETTER A WITH ACUTE */
282
+ # acircumflex 0x00e2 /* U+00E2 LATIN SMALL LETTER A WITH CIRCUMFLEX */
283
+ # atilde 0x00e3 /* U+00E3 LATIN SMALL LETTER A WITH TILDE */
284
+ # adiaeresis 0x00e4 /* U+00E4 LATIN SMALL LETTER A WITH DIAERESIS */
285
+ # aring 0x00e5 /* U+00E5 LATIN SMALL LETTER A WITH RING ABOVE */
286
+ # ae 0x00e6 /* U+00E6 LATIN SMALL LETTER AE */
287
+ # ccedilla 0x00e7 /* U+00E7 LATIN SMALL LETTER C WITH CEDILLA */
288
+ # egrave 0x00e8 /* U+00E8 LATIN SMALL LETTER E WITH GRAVE */
289
+ # eacute 0x00e9 /* U+00E9 LATIN SMALL LETTER E WITH ACUTE */
290
+ # ecircumflex 0x00ea /* U+00EA LATIN SMALL LETTER E WITH CIRCUMFLEX */
291
+ # ediaeresis 0x00eb /* U+00EB LATIN SMALL LETTER E WITH DIAERESIS */
292
+ # igrave 0x00ec /* U+00EC LATIN SMALL LETTER I WITH GRAVE */
293
+ # iacute 0x00ed /* U+00ED LATIN SMALL LETTER I WITH ACUTE */
294
+ # icircumflex 0x00ee /* U+00EE LATIN SMALL LETTER I WITH CIRCUMFLEX */
295
+ # idiaeresis 0x00ef /* U+00EF LATIN SMALL LETTER I WITH DIAERESIS */
296
+ # eth 0x00f0 /* U+00F0 LATIN SMALL LETTER ETH */
297
+ # ntilde 0x00f1 /* U+00F1 LATIN SMALL LETTER N WITH TILDE */
298
+ # ograve 0x00f2 /* U+00F2 LATIN SMALL LETTER O WITH GRAVE */
299
+ # oacute 0x00f3 /* U+00F3 LATIN SMALL LETTER O WITH ACUTE */
300
+ # ocircumflex 0x00f4 /* U+00F4 LATIN SMALL LETTER O WITH CIRCUMFLEX */
301
+ # otilde 0x00f5 /* U+00F5 LATIN SMALL LETTER O WITH TILDE */
302
+ # odiaeresis 0x00f6 /* U+00F6 LATIN SMALL LETTER O WITH DIAERESIS */
303
+ # division 0x00f7 /* U+00F7 DIVISION SIGN */
304
+ # oslash 0x00f8 /* U+00F8 LATIN SMALL LETTER O WITH STROKE */
305
+ # ooblique 0x00f8 /* U+00F8 LATIN SMALL LETTER O WITH STROKE */
306
+ # ugrave 0x00f9 /* U+00F9 LATIN SMALL LETTER U WITH GRAVE */
307
+ # uacute 0x00fa /* U+00FA LATIN SMALL LETTER U WITH ACUTE */
308
+ # ucircumflex 0x00fb /* U+00FB LATIN SMALL LETTER U WITH CIRCUMFLEX */
309
+ # udiaeresis 0x00fc /* U+00FC LATIN SMALL LETTER U WITH DIAERESIS */
310
+ # yacute 0x00fd /* U+00FD LATIN SMALL LETTER Y WITH ACUTE */
311
+ # thorn 0x00fe /* U+00FE LATIN SMALL LETTER THORN */
312
+ # ydiaeresis 0x00ff /* U+00FF LATIN SMALL LETTER Y WITH DIAERESIS */
313
+ #
314
+ def keys_to_events(keys)
315
+
316
+ keymap = {
317
+ "`" => "grave",
318
+ " " => "space",
319
+ "~" => "asciitilde",
320
+ "_" => "underscore",
321
+ "\[" => "Escape",
322
+ '"' => "quotedbl",
323
+ }
324
+
325
+ tokens = keys.scan(/(<[^>]+>|.+?)/)
326
+
327
+ tokens.flatten.map do |key|
328
+ mods = []
329
+
330
+ if key =~ /^<(.+)>$/
331
+
332
+ specials = $1.split("-")
333
+ key = specials.pop
334
+
335
+ specials.each do |special|
336
+ if special =~ /^(Ctrl|Shift|Alt)$/
337
+ mods << $1
338
+ else
339
+ raise "Error: unknown modifier #{special}"
340
+ end
341
+ end
342
+
343
+ end
344
+
345
+ mods << "Shift" if key =~ /^[A-Z\~\!\@\#\$\%\^\&\*\(\)\_\+]$/
346
+
347
+ if key =~ /^[A-Z0-9]$/i or key.size > 1
348
+ keyname = key
349
+ else
350
+ keyname = keymap[key] || ("0x%x" % key.ord)
351
+ end
352
+
353
+ "#{mods.join(" ")}<Key>#{keyname}"
354
+ end
355
+ end
356
+
357
+ def xse(keys)
358
+ temp = Tempfile.new("xse")
359
+ events = keys_to_events(keys)
360
+
361
+ p events
362
+ p eventstring = events.map { |e| e + "\n" }.join("")
363
+
364
+ temp.write eventstring
365
+ temp.flush
366
+
367
+ unless system("xse", "-window", window_id, "-file", temp.path)
368
+ raise "Error: couldn't send key commands to 'xse'. (Is xsendevents installed?)"
369
+ end
370
+ end
371
+
81
372
  end
82
373
 
83
374
  end