Merge lp:~blackdaemon/enso/win32-selection-fixes into lp:~communityenso/enso/community-enso
- win32-selection-fixes
- Merge into community-enso
Proposed by
blackdaemon
Status: | Needs review | ||||
---|---|---|---|---|---|
Proposed branch: | lp:~blackdaemon/enso/win32-selection-fixes | ||||
Merge into: | lp:~communityenso/enso/community-enso | ||||
Diff against target: |
548 lines (+218/-90) 4 files modified
enso/platform/win32/selection/FileSelection.py (+16/-11) enso/platform/win32/selection/TextSelection.py (+43/-20) enso/platform/win32/selection/_ContextUtils.py (+158/-58) enso/platform/win32/selection/__init__.py (+1/-1) |
||||
To merge this branch: | bzr merge lp:~blackdaemon/enso/win32-selection-fixes | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Community Enso Team | Pending | ||
Review via email: mp+27830@code.launchpad.net |
Commit message
Description of the change
Handling of copy/cut/paste for Vim and gVim
Handling of copy/paste for console windows
To post a comment you must log in.
- 148. By blackdaemon
-
Small fixes
Unmerged revisions
- 148. By blackdaemon
-
Small fixes
- 147. By blackdaemon
-
Handling Vim and gVim copy&paste
- 146. By blackdaemon
-
Handle copy&paste for console windows using "Alt-space e y" and "Alt-space e p"
- 145. By blackdaemon
-
Ignore pylint errors for pywintypes.error
- 144. By blackdaemon
-
Added getWindowProces
sName() - 143. By blackdaemon
-
Added handling of some special keys ([, ])
Fixed sending of extended keys (Ins, Del, Home, [, ], etc)
Added typeShiftKey
Added possibility to send key as string or virtual-code
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'enso/platform/win32/selection/FileSelection.py' | |||
2 | --- enso/platform/win32/selection/FileSelection.py 2008-04-27 11:12:38 +0000 | |||
3 | +++ enso/platform/win32/selection/FileSelection.py 2010-07-30 13:46:41 +0000 | |||
4 | @@ -44,8 +44,10 @@ | |||
5 | 44 | # Imports | 44 | # Imports |
6 | 45 | # ---------------------------------------------------------------------------- | 45 | # ---------------------------------------------------------------------------- |
7 | 46 | 46 | ||
8 | 47 | import os | ||
9 | 47 | import win32con | 48 | import win32con |
10 | 48 | import win32clipboard | 49 | import win32clipboard |
11 | 50 | import win32gui | ||
12 | 49 | import pywintypes | 51 | import pywintypes |
13 | 50 | import logging | 52 | import logging |
14 | 51 | 53 | ||
15 | @@ -144,9 +146,8 @@ | |||
16 | 144 | value = win32clipboard.GetClipboardData( | 146 | value = win32clipboard.GetClipboardData( |
17 | 145 | win32con.CF_HDROP | 147 | win32con.CF_HDROP |
18 | 146 | ) | 148 | ) |
22 | 147 | except pywintypes.error, e: | 149 | except pywintypes.error, e: #IGNORE:E1101 |
23 | 148 | logging.warn( "Error getting CF_HDROP from clipboard: %s" \ | 150 | logging.warn( "Error getting CF_HDROP from clipboard: %s", str(e) ) |
21 | 149 | % ( str(e) ) ) | ||
24 | 150 | value = None | 151 | value = None |
25 | 151 | else: | 152 | else: |
26 | 152 | logging.info( "Clipboard type CF_HDROP not in clipboard." ) | 153 | logging.info( "Clipboard type CF_HDROP not in clipboard." ) |
27 | @@ -167,13 +168,17 @@ | |||
28 | 167 | subclass which is appropriate to the currently active application. | 168 | subclass which is appropriate to the currently active application. |
29 | 168 | """ | 169 | """ |
30 | 169 | 170 | ||
39 | 170 | windowClass = ContextUtils.getForegroundClassNameUnicode() | 171 | hwnd = win32gui.GetForegroundWindow() |
40 | 171 | 172 | className = ContextUtils.getWindowClassName(hwnd) | |
41 | 172 | if windowClass == u"ConsoleWindowClass": | 173 | processName = ContextUtils.getWindowProcessName(hwnd) |
42 | 173 | fsContext = NullFileSelectionContext() | 174 | |
43 | 174 | elif windowClass == u"Emacs": | 175 | fsContext = DefaultFileSelectionContext() |
44 | 175 | fsContext = NullFileSelectionContext() | 176 | |
45 | 176 | else: | 177 | if className == u"Emacs": |
46 | 177 | fsContext = DefaultFileSelectionContext() | 178 | fsContext = NullFileSelectionContext() |
47 | 179 | elif className == u"ConsoleWindowClass": | ||
48 | 180 | fsContext = NullFileSelectionContext() | ||
49 | 181 | elif className == u"Vim" and os.path.basename(processName).lower() == "gvim.exe": | ||
50 | 182 | fsContext = NullFileSelectionContext() | ||
51 | 178 | 183 | ||
52 | 179 | return fsContext | 184 | return fsContext |
53 | 180 | 185 | ||
54 | === modified file 'enso/platform/win32/selection/TextSelection.py' | |||
55 | --- enso/platform/win32/selection/TextSelection.py 2009-02-20 00:39:06 +0000 | |||
56 | +++ enso/platform/win32/selection/TextSelection.py 2010-07-30 13:46:41 +0000 | |||
57 | @@ -42,6 +42,8 @@ | |||
58 | 42 | # Imports | 42 | # Imports |
59 | 43 | # ---------------------------------------------------------------------------- | 43 | # ---------------------------------------------------------------------------- |
60 | 44 | 44 | ||
61 | 45 | import os | ||
62 | 46 | import win32gui | ||
63 | 45 | import win32clipboard | 47 | import win32clipboard |
64 | 46 | import win32con | 48 | import win32con |
65 | 47 | import logging | 49 | import logging |
66 | @@ -103,6 +105,7 @@ | |||
67 | 103 | newDict[ "text" ] = newPlainText | 105 | newDict[ "text" ] = newPlainText |
68 | 104 | if len( newHtml ) > 0: | 106 | if len( newHtml ) > 0: |
69 | 105 | newDict[ "html" ] = newHtml | 107 | newDict[ "html" ] = newHtml |
70 | 108 | return newDict | ||
71 | 106 | 109 | ||
72 | 107 | def _textDictToAscii( textDict ): | 110 | def _textDictToAscii( textDict ): |
73 | 108 | text = textDict.get( "text", u"" ) | 111 | text = textDict.get( "text", u"" ) |
74 | @@ -407,7 +410,7 @@ | |||
75 | 407 | class NonReplacingTextSelection( DefaultTextSelection ): | 410 | class NonReplacingTextSelection( DefaultTextSelection ): |
76 | 408 | """ | 411 | """ |
77 | 409 | In some applications, notably MoonEdit and Emacs, a paste | 412 | In some applications, notably MoonEdit and Emacs, a paste |
79 | 410 | does not replace selected tet: it inserts | 413 | does not replace selected text: it inserts |
80 | 411 | at the cursor. This is the selection context to use for | 414 | at the cursor. This is the selection context to use for |
81 | 412 | those applications. | 415 | those applications. |
82 | 413 | """ | 416 | """ |
83 | @@ -473,20 +476,6 @@ | |||
84 | 473 | these functions are no-ops. | 476 | these functions are no-ops. |
85 | 474 | """ | 477 | """ |
86 | 475 | 478 | ||
87 | 476 | def getSelection( self ): | ||
88 | 477 | """ | ||
89 | 478 | Always blank. | ||
90 | 479 | """ | ||
91 | 480 | return {} | ||
92 | 481 | |||
93 | 482 | def replaceSelection( self, textDict ): | ||
94 | 483 | """ | ||
95 | 484 | Text in the command prompt window is immutable, so | ||
96 | 485 | the replacement behavior is impossible to achieve. | ||
97 | 486 | Return False to indicate failure. | ||
98 | 487 | """ | ||
99 | 488 | return False | ||
100 | 489 | |||
101 | 490 | def simulatePasteKeystroke( self ): | 479 | def simulatePasteKeystroke( self ): |
102 | 491 | # Alt-space pops up the window menu (the thing you get | 480 | # Alt-space pops up the window menu (the thing you get |
103 | 492 | # by clicking in the upper-left corner). Then typing | 481 | # by clicking in the upper-left corner). Then typing |
104 | @@ -495,7 +484,11 @@ | |||
105 | 495 | ContextUtils.typeSequence( "e p" ) | 484 | ContextUtils.typeSequence( "e p" ) |
106 | 496 | 485 | ||
107 | 497 | def simulateCopyKeystroke( self ): | 486 | def simulateCopyKeystroke( self ): |
109 | 498 | pass | 487 | # Alt-space pops up the window menu (the thing you get |
110 | 488 | # by clicking in the upper-left corner). Then typing | ||
111 | 489 | # e and then y selects edit->copy. | ||
112 | 490 | ContextUtils.typeAltKey( " " ) | ||
113 | 491 | ContextUtils.typeSequence( "e y" ) | ||
114 | 499 | 492 | ||
115 | 500 | def simulateCutKeystroke( self ): | 493 | def simulateCutKeystroke( self ): |
116 | 501 | pass | 494 | pass |
117 | @@ -509,6 +502,28 @@ | |||
118 | 509 | return self._pasteText( textDict ) | 502 | return self._pasteText( textDict ) |
119 | 510 | 503 | ||
120 | 511 | 504 | ||
121 | 505 | class VimTextSelection( DefaultTextSelection ): | ||
122 | 506 | """ | ||
123 | 507 | Returned if the currently active application is a Windows Vim/gVim. | ||
124 | 508 | """ | ||
125 | 509 | |||
126 | 510 | def simulatePasteKeystroke( self ): | ||
127 | 511 | # Shift-Insert should work by default in Windows version of Vim/gVim | ||
128 | 512 | ContextUtils.typeShiftKey(win32con.VK_INSERT) | ||
129 | 513 | |||
130 | 514 | def simulateCopyKeystroke( self ): | ||
131 | 515 | # Ctrl-Insert should work by default in Windows version of Vim/gVim | ||
132 | 516 | # But yanking the selection will also clear it. So the sequence is: | ||
133 | 517 | # copy text to clipboard: Ctrl-Insert | ||
134 | 518 | # get to normal mode 2x: Ctrl-[ Ctrl-[ | ||
135 | 519 | # return to last selection: gv | ||
136 | 520 | ContextUtils.typeSequence('CD INS [ [ CU g v') | ||
137 | 521 | |||
138 | 522 | def simulateCutKeystroke( self ): | ||
139 | 523 | # Ctrl-Del should work by default in Windows version of Vim/gVim | ||
140 | 524 | ContextUtils.typeCommandKey(win32con.VK_DELETE) | ||
141 | 525 | |||
142 | 526 | |||
143 | 512 | # ---------------------------------------------------------------------------- | 527 | # ---------------------------------------------------------------------------- |
144 | 513 | # Public Function | 528 | # Public Function |
145 | 514 | # ---------------------------------------------------------------------------- | 529 | # ---------------------------------------------------------------------------- |
146 | @@ -521,16 +536,24 @@ | |||
147 | 521 | If no text is selected, this must return a TextSelection object with | 536 | If no text is selected, this must return a TextSelection object with |
148 | 522 | no text in it -- NOT a None. | 537 | no text in it -- NOT a None. |
149 | 523 | """ | 538 | """ |
150 | 539 | hwnd = win32gui.GetForegroundWindow() | ||
151 | 540 | className = ContextUtils.getWindowClassName(hwnd) | ||
152 | 524 | 541 | ||
154 | 525 | className = ContextUtils.getForegroundClassNameUnicode() | 542 | tsContext = DefaultTextSelection() |
155 | 526 | 543 | ||
156 | 527 | if className == u"Emacs": | 544 | if className == u"Emacs": |
157 | 528 | tsContext = EmacsTextSelection() | 545 | tsContext = EmacsTextSelection() |
158 | 529 | elif className == u"MoonEdit": | 546 | elif className == u"MoonEdit": |
159 | 530 | tsContext = NonReplacingTextSelection() | 547 | tsContext = NonReplacingTextSelection() |
160 | 531 | elif className == u"ConsoleWindowClass": | 548 | elif className == u"ConsoleWindowClass": |
164 | 532 | tsContext = CommandPromptTextSelection() | 549 | processName = ContextUtils.getWindowProcessName(hwnd) |
165 | 533 | else: | 550 | if os.path.basename(processName).lower() == "vim.exe": |
166 | 534 | tsContext = DefaultTextSelection() | 551 | tsContext = VimTextSelection() |
167 | 552 | else: | ||
168 | 553 | tsContext = CommandPromptTextSelection() | ||
169 | 554 | elif className == u"Vim": | ||
170 | 555 | processName = ContextUtils.getWindowProcessName(hwnd) | ||
171 | 556 | if os.path.basename(processName).lower() == "gvim.exe": | ||
172 | 557 | tsContext = VimTextSelection() | ||
173 | 535 | 558 | ||
174 | 536 | return tsContext | 559 | return tsContext |
175 | 537 | 560 | ||
176 | === modified file 'enso/platform/win32/selection/_ContextUtils.py' | |||
177 | --- enso/platform/win32/selection/_ContextUtils.py 2008-04-27 11:12:38 +0000 | |||
178 | +++ enso/platform/win32/selection/_ContextUtils.py 2010-07-30 13:46:41 +0000 | |||
179 | @@ -1,6 +1,6 @@ | |||
180 | 1 | # Copyright (c) 2008, Humanized, Inc. | 1 | # Copyright (c) 2008, Humanized, Inc. |
181 | 2 | # All rights reserved. | 2 | # All rights reserved. |
183 | 3 | # | 3 | # |
184 | 4 | # Redistribution and use in source and binary forms, with or without | 4 | # Redistribution and use in source and binary forms, with or without |
185 | 5 | # modification, are permitted provided that the following conditions are met: | 5 | # modification, are permitted provided that the following conditions are met: |
186 | 6 | # | 6 | # |
187 | @@ -14,7 +14,7 @@ | |||
188 | 14 | # 3. Neither the name of Enso nor the names of its contributors may | 14 | # 3. Neither the name of Enso nor the names of its contributors may |
189 | 15 | # be used to endorse or promote products derived from this | 15 | # be used to endorse or promote products derived from this |
190 | 16 | # software without specific prior written permission. | 16 | # software without specific prior written permission. |
192 | 17 | # | 17 | # |
193 | 18 | # THIS SOFTWARE IS PROVIDED BY Humanized, Inc. ``AS IS'' AND ANY | 18 | # THIS SOFTWARE IS PROVIDED BY Humanized, Inc. ``AS IS'' AND ANY |
194 | 19 | # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | 19 | # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
195 | 20 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 20 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
196 | @@ -37,10 +37,12 @@ | |||
197 | 37 | # Imports | 37 | # Imports |
198 | 38 | # ---------------------------------------------------------------------------- | 38 | # ---------------------------------------------------------------------------- |
199 | 39 | 39 | ||
200 | 40 | import os | ||
201 | 40 | import win32api | 41 | import win32api |
202 | 41 | import win32con | 42 | import win32con |
203 | 42 | import win32gui | 43 | import win32gui |
204 | 43 | import win32clipboard | 44 | import win32clipboard |
205 | 45 | import win32process | ||
206 | 44 | import ctypes | 46 | import ctypes |
207 | 45 | import pywintypes | 47 | import pywintypes |
208 | 46 | import time | 48 | import time |
209 | @@ -95,6 +97,55 @@ | |||
210 | 95 | # key is being depressed." | 97 | # key is being depressed." |
211 | 96 | KEYEVENTF_KEYDOWN = 0 | 98 | KEYEVENTF_KEYDOWN = 0 |
212 | 97 | KEYEVENTF_KEYUP = win32con.KEYEVENTF_KEYUP | 99 | KEYEVENTF_KEYUP = win32con.KEYEVENTF_KEYUP |
213 | 100 | KEYEVENTF_EXTENDEDKEY = win32con.KEYEVENTF_EXTENDEDKEY | ||
214 | 101 | |||
215 | 102 | VK_LBRACKET = 0xDB | ||
216 | 103 | VK_RBRACKET = 0xDD | ||
217 | 104 | |||
218 | 105 | KEY_MAPPING = { "F1" : win32con.VK_F1, | ||
219 | 106 | "F2" : win32con.VK_F2, | ||
220 | 107 | "F3" : win32con.VK_F3, | ||
221 | 108 | "F4" : win32con.VK_F4, | ||
222 | 109 | "F5" : win32con.VK_F5, | ||
223 | 110 | "F6" : win32con.VK_F6, | ||
224 | 111 | "F7" : win32con.VK_F7, | ||
225 | 112 | "F8" : win32con.VK_F8, | ||
226 | 113 | "F9" : win32con.VK_F9, | ||
227 | 114 | "F10": win32con.VK_F10, | ||
228 | 115 | "F11": win32con.VK_F11, | ||
229 | 116 | "F12": win32con.VK_F12, | ||
230 | 117 | "CD" : win32con.VK_LCONTROL, | ||
231 | 118 | "CU" : win32con.VK_LCONTROL, | ||
232 | 119 | "SD" : win32con.VK_LSHIFT, | ||
233 | 120 | "SU" : win32con.VK_LSHIFT, | ||
234 | 121 | "AD" : win32con.VK_MENU, | ||
235 | 122 | "AU" : win32con.VK_MENU, | ||
236 | 123 | "ID" : win32con.VK_LWIN, | ||
237 | 124 | "IU" : win32con.VK_LWIN, | ||
238 | 125 | "LA": win32con.VK_LEFT, | ||
239 | 126 | "RA": win32con.VK_RIGHT, | ||
240 | 127 | "ESC": win32con.VK_ESCAPE, | ||
241 | 128 | "INS": win32con.VK_INSERT, | ||
242 | 129 | "DEL": win32con.VK_DELETE, | ||
243 | 130 | "[": VK_LBRACKET, | ||
244 | 131 | "]": VK_RBRACKET, | ||
245 | 132 | "LBRACKET": VK_LBRACKET, | ||
246 | 133 | "RBRACKET": VK_RBRACKET | ||
247 | 134 | } | ||
248 | 135 | |||
249 | 136 | # List of keys that need to have the win32con.KEYEVENTF_EXTENDEDKEY flag set | ||
250 | 137 | KEYS_EXTENDED = [ | ||
251 | 138 | win32con.VK_UP, | ||
252 | 139 | win32con.VK_DOWN, | ||
253 | 140 | win32con.VK_LEFT, | ||
254 | 141 | win32con.VK_RIGHT, | ||
255 | 142 | win32con.VK_HOME, | ||
256 | 143 | win32con.VK_END, | ||
257 | 144 | win32con.VK_PRIOR, # PgUp | ||
258 | 145 | win32con.VK_NEXT, # PgDn | ||
259 | 146 | win32con.VK_INSERT, | ||
260 | 147 | win32con.VK_DELETE | ||
261 | 148 | ] | ||
262 | 98 | 149 | ||
263 | 99 | # ---------------------------------------------------------------------------- | 150 | # ---------------------------------------------------------------------------- |
264 | 100 | # Private Module Variables | 151 | # Private Module Variables |
265 | @@ -125,10 +176,14 @@ | |||
266 | 125 | # win32all does not provide access to MapVirtualKey, so we have to use | 176 | # win32all does not provide access to MapVirtualKey, so we have to use |
267 | 126 | # ctypes to access the DLL directly, and have to append "A" to the name | 177 | # ctypes to access the DLL directly, and have to append "A" to the name |
268 | 127 | # since the function is implemented in Unicode and ANSI versions. | 178 | # since the function is implemented in Unicode and ANSI versions. |
270 | 128 | 179 | ||
271 | 129 | # This gives a hardware scancode for the virtual key. | 180 | # This gives a hardware scancode for the virtual key. |
272 | 130 | scanCode = ctypes.windll.user32.MapVirtualKeyA( vkCode, 0 ) | 181 | scanCode = ctypes.windll.user32.MapVirtualKeyA( vkCode, 0 ) |
273 | 131 | 182 | ||
274 | 183 | # Some keys needs the 'extended-key' attribute | ||
275 | 184 | if vkCode in KEYS_EXTENDED: | ||
276 | 185 | eventType |= KEYEVENTF_EXTENDEDKEY | ||
277 | 186 | |||
278 | 132 | # This creates the keyboard event (this function is the one called | 187 | # This creates the keyboard event (this function is the one called |
279 | 133 | # by keyboard driver interupt handlers, so it's as low-level as it gets) | 188 | # by keyboard driver interupt handlers, so it's as low-level as it gets) |
280 | 134 | win32api.keybd_event( vkCode, scanCode, eventType, 0 ) | 189 | win32api.keybd_event( vkCode, scanCode, eventType, 0 ) |
281 | @@ -157,7 +212,7 @@ | |||
282 | 157 | try: | 212 | try: |
283 | 158 | win32clipboard.OpenClipboard( 0 ) | 213 | win32clipboard.OpenClipboard( 0 ) |
284 | 159 | success = True | 214 | success = True |
286 | 160 | except pywintypes.error: | 215 | except pywintypes.error: #IGNORE:E1101 |
287 | 161 | if totalTime < CLIPBOARD_OPEN_WAIT_AMOUNT: | 216 | if totalTime < CLIPBOARD_OPEN_WAIT_AMOUNT: |
288 | 162 | sleepForMs( CLIPBOARD_OPEN_WAIT_INTERVAL ) | 217 | sleepForMs( CLIPBOARD_OPEN_WAIT_INTERVAL ) |
289 | 163 | totalTime += CLIPBOARD_OPEN_WAIT_INTERVAL | 218 | totalTime += CLIPBOARD_OPEN_WAIT_INTERVAL |
290 | @@ -186,10 +241,10 @@ | |||
291 | 186 | 241 | ||
292 | 187 | # Postconditions: | 242 | # Postconditions: |
293 | 188 | assert( _hasTheClipboardOpen() ) | 243 | assert( _hasTheClipboardOpen() ) |
295 | 189 | 244 | ||
296 | 190 | try: | 245 | try: |
297 | 191 | win32clipboard.CloseClipboard() | 246 | win32clipboard.CloseClipboard() |
299 | 192 | except pywintypes.error: | 247 | except pywintypes.error: #IGNORE:E1101 |
300 | 193 | logging.warn( "Attempted to close clipboard when not open." ) | 248 | logging.warn( "Attempted to close clipboard when not open." ) |
301 | 194 | global _contextUtilsHasTheClipboardOpen | 249 | global _contextUtilsHasTheClipboardOpen |
302 | 195 | _contextUtilsHasTheClipboardOpen = False | 250 | _contextUtilsHasTheClipboardOpen = False |
303 | @@ -205,7 +260,7 @@ | |||
304 | 205 | function, then closes it when the wrapped function is done, | 260 | function, then closes it when the wrapped function is done, |
305 | 206 | whether or not the wrapped function throws an exception. | 261 | whether or not the wrapped function throws an exception. |
306 | 207 | """ | 262 | """ |
308 | 208 | 263 | ||
309 | 209 | def wrapperFunc( *args, **kwargs ): | 264 | def wrapperFunc( *args, **kwargs ): |
310 | 210 | # If safeOpenClipboard() raises an exception, this function will do | 265 | # If safeOpenClipboard() raises an exception, this function will do |
311 | 211 | # nothing but allow it to be raised. (We shouldn't attempt to close | 266 | # nothing but allow it to be raised. (We shouldn't attempt to close |
312 | @@ -231,7 +286,7 @@ | |||
313 | 231 | the CF_CLIPBOARD_VIEWER_IGNORE format so that clipboard viewers | 286 | the CF_CLIPBOARD_VIEWER_IGNORE format so that clipboard viewers |
314 | 232 | will ignore this alteration of the clipboard. | 287 | will ignore this alteration of the clipboard. |
315 | 233 | """ | 288 | """ |
317 | 234 | 289 | ||
318 | 235 | win32clipboard.EmptyClipboard() | 290 | win32clipboard.EmptyClipboard() |
319 | 236 | setClipboardDataViewerIgnore() | 291 | setClipboardDataViewerIgnore() |
320 | 237 | 292 | ||
321 | @@ -264,7 +319,7 @@ | |||
322 | 264 | """ | 319 | """ |
323 | 265 | LONGTERM TODO: This is kept around for debugging but can be deleted from | 320 | LONGTERM TODO: This is kept around for debugging but can be deleted from |
324 | 266 | production code. | 321 | production code. |
326 | 267 | 322 | ||
327 | 268 | Given a format code (of the kind returned from the windows clipboard | 323 | Given a format code (of the kind returned from the windows clipboard |
328 | 269 | functions), returns a string describing the meaning of that | 324 | functions), returns a string describing the meaning of that |
329 | 270 | format code. | 325 | format code. |
330 | @@ -333,8 +388,18 @@ | |||
331 | 333 | """ | 388 | """ |
332 | 334 | 389 | ||
333 | 335 | _keyboardEvent( win32con.VK_CONTROL, KEYEVENTF_KEYDOWN ) | 390 | _keyboardEvent( win32con.VK_CONTROL, KEYEVENTF_KEYDOWN ) |
336 | 336 | _keyboardEvent( ord(key.upper()), KEYEVENTF_KEYDOWN ) | 391 | |
337 | 337 | _keyboardEvent( ord(key.upper()), KEYEVENTF_KEYUP ) | 392 | if isinstance(key, basestring): |
338 | 393 | if key in KEY_MAPPING: | ||
339 | 394 | key_code = KEY_MAPPING[key] | ||
340 | 395 | else: | ||
341 | 396 | key_code = ord(key.upper()) | ||
342 | 397 | else: | ||
343 | 398 | key_code = key | ||
344 | 399 | |||
345 | 400 | _keyboardEvent( key_code, KEYEVENTF_KEYDOWN ) | ||
346 | 401 | _keyboardEvent( key_code, KEYEVENTF_KEYUP ) | ||
347 | 402 | |||
348 | 338 | _keyboardEvent( win32con.VK_CONTROL, KEYEVENTF_KEYUP ) | 403 | _keyboardEvent( win32con.VK_CONTROL, KEYEVENTF_KEYUP ) |
349 | 339 | logging.info( "I am in typeCommandKey and I just typed " + key ) | 404 | logging.info( "I am in typeCommandKey and I just typed " + key ) |
350 | 340 | 405 | ||
351 | @@ -344,18 +409,50 @@ | |||
352 | 344 | Given a character literal, simulates holding the Alt key down | 409 | Given a character literal, simulates holding the Alt key down |
353 | 345 | and typing that character. | 410 | and typing that character. |
354 | 346 | """ | 411 | """ |
356 | 347 | 412 | ||
357 | 348 | _keyboardEvent( win32con.VK_MENU, KEYEVENTF_KEYDOWN ) | 413 | _keyboardEvent( win32con.VK_MENU, KEYEVENTF_KEYDOWN ) |
360 | 349 | _keyboardEvent( ord(key.upper()), KEYEVENTF_KEYDOWN ) | 414 | |
361 | 350 | _keyboardEvent( ord(key.upper()), KEYEVENTF_KEYUP ) | 415 | if isinstance(key, basestring): |
362 | 416 | if key in KEY_MAPPING: | ||
363 | 417 | key_code = KEY_MAPPING[key] | ||
364 | 418 | else: | ||
365 | 419 | key_code = ord(key.upper()) | ||
366 | 420 | else: | ||
367 | 421 | key_code = key | ||
368 | 422 | |||
369 | 423 | _keyboardEvent( key_code, KEYEVENTF_KEYDOWN ) | ||
370 | 424 | _keyboardEvent( key_code, KEYEVENTF_KEYUP ) | ||
371 | 425 | |||
372 | 351 | _keyboardEvent( win32con.VK_MENU, KEYEVENTF_KEYUP ) | 426 | _keyboardEvent( win32con.VK_MENU, KEYEVENTF_KEYUP ) |
373 | 352 | 427 | ||
374 | 353 | 428 | ||
375 | 429 | def typeShiftKey( key ): | ||
376 | 430 | """ | ||
377 | 431 | Given a character literal, simulates holding the Shift key down | ||
378 | 432 | and typing that character. | ||
379 | 433 | """ | ||
380 | 434 | |||
381 | 435 | _keyboardEvent( win32con.VK_LSHIFT, KEYEVENTF_KEYDOWN ) | ||
382 | 436 | |||
383 | 437 | if isinstance(key, basestring): | ||
384 | 438 | if key in KEY_MAPPING: | ||
385 | 439 | key_code = KEY_MAPPING[key] | ||
386 | 440 | else: | ||
387 | 441 | key_code = ord(key.upper()) | ||
388 | 442 | else: | ||
389 | 443 | key_code = key | ||
390 | 444 | |||
391 | 445 | _keyboardEvent( key_code, KEYEVENTF_KEYDOWN ) | ||
392 | 446 | _keyboardEvent( key_code, KEYEVENTF_KEYUP ) | ||
393 | 447 | |||
394 | 448 | _keyboardEvent( win32con.VK_LSHIFT, KEYEVENTF_KEYUP ) | ||
395 | 449 | |||
396 | 450 | |||
397 | 354 | def tapKey( keyCode ): | 451 | def tapKey( keyCode ): |
398 | 355 | """ | 452 | """ |
399 | 356 | Given a virtual key code, simulates tapping that key. | 453 | Given a virtual key code, simulates tapping that key. |
400 | 357 | """ | 454 | """ |
402 | 358 | 455 | ||
403 | 359 | _keyboardEvent( keyCode, KEYEVENTF_KEYDOWN ) | 456 | _keyboardEvent( keyCode, KEYEVENTF_KEYDOWN ) |
404 | 360 | _keyboardEvent( keyCode, KEYEVENTF_KEYUP ) | 457 | _keyboardEvent( keyCode, KEYEVENTF_KEYUP ) |
405 | 361 | 458 | ||
406 | @@ -384,43 +481,10 @@ | |||
407 | 384 | # keydown, keyup, keypress, and pauses. | 481 | # keydown, keyup, keypress, and pauses. |
408 | 385 | 482 | ||
409 | 386 | keys = keys.split( " " ) | 483 | keys = keys.split( " " ) |
410 | 387 | mapping = { "F1" : win32con.VK_F1, | ||
411 | 388 | "F2" : win32con.VK_F2, | ||
412 | 389 | "F3" : win32con.VK_F3, | ||
413 | 390 | "F4" : win32con.VK_F4, | ||
414 | 391 | "F5" : win32con.VK_F5, | ||
415 | 392 | "F6" : win32con.VK_F6, | ||
416 | 393 | "F7" : win32con.VK_F7, | ||
417 | 394 | "F8" : win32con.VK_F8, | ||
418 | 395 | "F9" : win32con.VK_F9, | ||
419 | 396 | "F10": win32con.VK_F10, | ||
420 | 397 | "F11": win32con.VK_F11, | ||
421 | 398 | "F12": win32con.VK_F12, | ||
422 | 399 | "CD" : win32con.VK_LCONTROL, | ||
423 | 400 | "CU" : win32con.VK_LCONTROL, | ||
424 | 401 | "SD" : win32con.VK_LSHIFT, | ||
425 | 402 | "SU" : win32con.VK_LSHIFT, | ||
426 | 403 | "AD" : win32con.VK_MENU, | ||
427 | 404 | "AU" : win32con.VK_MENU, | ||
428 | 405 | "ID" : win32con.VK_LWIN, | ||
429 | 406 | "IU" : win32con.VK_LWIN, | ||
430 | 407 | "LA": win32con.VK_LEFT, | ||
431 | 408 | "RA": win32con.VK_RIGHT, | ||
432 | 409 | "ESC": win32con.VK_ESCAPE, | ||
433 | 410 | "INS": win32con.VK_INSERT, | ||
434 | 411 | "DEL": win32con.VK_DELETE | ||
435 | 412 | } | ||
436 | 413 | 484 | ||
437 | 414 | for key in keys: | 485 | for key in keys: |
438 | 415 | key = key.upper() | 486 | key = key.upper() |
447 | 416 | 487 | ||
440 | 417 | # Any one-character code means tap and release that literal key. | ||
441 | 418 | if len(key) == 1: | ||
442 | 419 | key_code = ord( key ) | ||
443 | 420 | _keyboardEvent( key_code, KEYEVENTF_KEYDOWN ) | ||
444 | 421 | _keyboardEvent( key_code, KEYEVENTF_KEYUP ) | ||
445 | 422 | continue | ||
446 | 423 | |||
448 | 424 | # "W##" means wait | 488 | # "W##" means wait |
449 | 425 | if key[0] == "W": | 489 | if key[0] == "W": |
450 | 426 | time.sleep( float(key[1:]) ) | 490 | time.sleep( float(key[1:]) ) |
451 | @@ -430,26 +494,30 @@ | |||
452 | 430 | # keybd_event function, and therefore don't use our keyboard | 494 | # keybd_event function, and therefore don't use our keyboard |
453 | 431 | # event wrapper. | 495 | # event wrapper. |
454 | 432 | if key in ["SD", "AD", "ID", "CD"]: | 496 | if key in ["SD", "AD", "ID", "CD"]: |
456 | 433 | win32api.keybd_event( mapping[key], 0, KEYEVENTF_KEYDOWN, 0 ) | 497 | win32api.keybd_event( KEY_MAPPING[key], 0, KEYEVENTF_KEYDOWN, 0 ) |
457 | 434 | continue | 498 | continue |
458 | 435 | if key in ["SU", "AU", "IU", "CU"]: | 499 | if key in ["SU", "AU", "IU", "CU"]: |
460 | 436 | win32api.keybd_event( mapping[key], 0, KEYEVENTF_KEYUP, 0 ) | 500 | win32api.keybd_event( KEY_MAPPING[key], 0, KEYEVENTF_KEYUP, 0 ) |
461 | 437 | continue | 501 | continue |
462 | 438 | 502 | ||
466 | 439 | # Any other multi-character code means look up the code | 503 | # Any one-character code means tap and release that literal key. |
467 | 440 | # in the table above, and tap the key. | 504 | if key in KEY_MAPPING: |
468 | 441 | key_code = mapping[key] | 505 | key_code = KEY_MAPPING[key] |
469 | 506 | else: | ||
470 | 507 | key_code = ord(key.upper()) | ||
471 | 442 | _keyboardEvent( key_code, KEYEVENTF_KEYDOWN ) | 508 | _keyboardEvent( key_code, KEYEVENTF_KEYDOWN ) |
472 | 443 | _keyboardEvent( key_code, KEYEVENTF_KEYUP ) | 509 | _keyboardEvent( key_code, KEYEVENTF_KEYUP ) |
473 | 444 | 510 | ||
474 | 445 | 511 | ||
476 | 446 | def getForegroundClassNameUnicode(): | 512 | def getForegroundClassNameUnicode(hwnd = None): |
477 | 447 | """ | 513 | """ |
479 | 448 | Returns a unicode string containing the class name of the frontmost | 514 | Returns a unicode string containing the class name of the specified |
480 | 449 | application window. | 515 | application window. |
481 | 516 | If hwnd parameter is None, frontmost window will be queried. | ||
482 | 450 | """ | 517 | """ |
483 | 451 | 518 | ||
485 | 452 | hwnd = win32gui.GetForegroundWindow() | 519 | if hwnd is None: |
486 | 520 | hwnd = win32gui.GetForegroundWindow() | ||
487 | 453 | 521 | ||
488 | 454 | # Maximum number of chars we'll accept for the class name; the | 522 | # Maximum number of chars we'll accept for the class name; the |
489 | 455 | # rest will be truncated if it's longer than this. | 523 | # rest will be truncated if it's longer than this. |
490 | @@ -466,6 +534,38 @@ | |||
491 | 466 | return classNameBuf.value | 534 | return classNameBuf.value |
492 | 467 | 535 | ||
493 | 468 | 536 | ||
494 | 537 | def getWindowClassName(hwnd = None): | ||
495 | 538 | """ | ||
496 | 539 | Returns a unicode string containing the class name of the specified | ||
497 | 540 | application window. | ||
498 | 541 | If hwnd parameter is None, frontmost window will be queried. | ||
499 | 542 | """ | ||
500 | 543 | return getForegroundClassNameUnicode(hwnd) | ||
501 | 544 | |||
502 | 545 | |||
503 | 546 | def getWindowProcessName(hwnd = None): | ||
504 | 547 | """ | ||
505 | 548 | Returns a unicode string containing the process name of the specified | ||
506 | 549 | application window (executable path). | ||
507 | 550 | If hwnd parameter is None, frontmost window will be queried. | ||
508 | 551 | """ | ||
509 | 552 | if hwnd is None: | ||
510 | 553 | hwnd = win32gui.GetForegroundWindow() | ||
511 | 554 | # Get PID so we can get process name | ||
512 | 555 | _, process_id = win32process.GetWindowThreadProcessId(hwnd) | ||
513 | 556 | # Get process name | ||
514 | 557 | phandle = win32api.OpenProcess( | ||
515 | 558 | win32con.PROCESS_QUERY_INFORMATION | win32con.PROCESS_VM_READ, | ||
516 | 559 | False, | ||
517 | 560 | process_id) | ||
518 | 561 | if phandle: | ||
519 | 562 | pexe = win32process.GetModuleFileNameEx(phandle, 0) | ||
520 | 563 | pexe = os.path.normcase(os.path.normpath(pexe)) | ||
521 | 564 | return pexe | ||
522 | 565 | else: | ||
523 | 566 | return None | ||
524 | 567 | |||
525 | 568 | |||
526 | 469 | # ---------------------------------------------------------------------------- | 569 | # ---------------------------------------------------------------------------- |
527 | 470 | # Exception | 570 | # Exception |
528 | 471 | # ---------------------------------------------------------------------------- | 571 | # ---------------------------------------------------------------------------- |
529 | @@ -475,5 +575,5 @@ | |||
530 | 475 | Exception raised if the clipboard was unable to be opened after | 575 | Exception raised if the clipboard was unable to be opened after |
531 | 476 | multiple attempts. | 576 | multiple attempts. |
532 | 477 | """ | 577 | """ |
534 | 478 | 578 | ||
535 | 479 | pass | 579 | pass |
536 | 480 | 580 | ||
537 | === modified file 'enso/platform/win32/selection/__init__.py' | |||
538 | --- enso/platform/win32/selection/__init__.py 2008-04-27 11:12:38 +0000 | |||
539 | +++ enso/platform/win32/selection/__init__.py 2010-07-30 13:46:41 +0000 | |||
540 | @@ -70,7 +70,7 @@ | |||
541 | 70 | textSelContext = TextSelection.get() | 70 | textSelContext = TextSelection.get() |
542 | 71 | 71 | ||
543 | 72 | # Trying to "set" a file selection doesn't do anything. | 72 | # Trying to "set" a file selection doesn't do anything. |
545 | 73 | textSelContext.replaceSelection( sel_dict ) | 73 | return textSelContext.replaceSelection( sel_dict ) |
546 | 74 | 74 | ||
547 | 75 | 75 | ||
548 | 76 | # ---------------------------------------------------------------------------- | 76 | # ---------------------------------------------------------------------------- |