epitools 0.5.7 → 0.5.8

Sign up to get free protection for your applications and to get access to all the features.
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