| | 213 | raise NotImplementedError() |
| | 214 | |
| | 215 | |
| | 216 | |
| | 217 | # |
| | 218 | # Pipe support (XXX this should go in _dumbwin32proc.py) |
| | 219 | # |
| | 220 | import win32pipe |
| | 221 | |
| | 222 | |
| | 223 | class _PollableReadPipe(_PollableReader): |
| | 224 | def __init__(self, pipe, receivedCallback, lostCallback): |
| | 225 | _PollableReader.__init__(self, pipe, receivedCallback, lostCallback) |
| | 226 | # security attributes for pipes |
| | 227 | |
| | 228 | def checkWork(self): |
| | 229 | finished = 0 |
| | 230 | fullDataRead = [] |
| | 231 | |
| | 232 | while 1: |
| | 233 | try: |
| | 234 | buffer, bytesToRead, result = win32pipe.PeekNamedPipe(self.handle, 1) |
| | 235 | # finished = (result == -1) |
| | 236 | if not bytesToRead: |
| | 237 | break |
| | 238 | hr, data = win32file.ReadFile(self.handle, bytesToRead, None) |
| | 239 | fullDataRead.append(data) |
| | 240 | except win32api.error: |
| | 241 | finished = 1 |
| | 242 | break |
| | 243 | |
| | 244 | dataBuf = ''.join(fullDataRead) |
| | 245 | if dataBuf: |
| | 246 | self.receivedCallback(dataBuf) |
| | 247 | if finished: |
| | 248 | self.cleanup() |
| | 249 | return len(dataBuf) |
| | 250 | |
| | 251 | |
| | 252 | class _PollableWritePipe(_PollableWriter): |
| | 253 | def __init__(self, writePipe, lostCallback): |
| | 254 | _PollableWriter.__init__(self, writePipe, lostCallback) |
| | 255 | |
| | 256 | try: |
| | 257 | win32pipe.SetNamedPipeHandleState(writePipe, |
| | 258 | win32pipe.PIPE_NOWAIT, |
| | 259 | None, |
| | 260 | None) |
| | 261 | except pywintypes.error: |
| | 262 | # Maybe it's an invalid handle. Who knows. |
| | 263 | pass |
| | 264 | |
| | 265 | def checkWork(self): |
| | 298 | |
| | 299 | # |
| | 300 | # Console support (XXX this should go in _conio.py) |
| | 301 | # |
| | 302 | # Only base support provided. |
| | 303 | # |
| | 304 | import win32console |
| | 305 | |
| | 306 | |
| | 307 | ENABLE_NORMAL_MODE = win32console.ENABLE_ECHO_INPUT | win32console.ENABLE_LINE_INPUT |
| | 308 | ENABLE_WINDOW_INPUT = win32console.ENABLE_WINDOW_INPUT |
| | 309 | |
| | 310 | |
| | 311 | class _PollableReadConsole(_PollableReader): |
| | 312 | def __init__(self, conIn, conOut, receivedCallback, lostCallback): |
| | 313 | _PollableReader.__init__(self, conIn, receivedCallback, lostCallback) |
| | 314 | self.cp = "cp%d" % win32console.GetConsoleCP() |
| | 315 | self.buf = [] |
| | 316 | |
| | 317 | # We need this for echoing |
| | 318 | self._stdout = conOut |
| | 319 | |
| | 320 | defaultMode = conIn.GetConsoleMode() |
| | 321 | conIn.SetConsoleMode(defaultMode | ENABLE_WINDOW_INPUT) |
| | 322 | self._windowChangeCallback = None |
| | 323 | |
| | 324 | self.checkWork = self._checkWork |
| | 325 | |
| | 326 | def enableRawMode(self, enabled=True): |
| | 327 | """Enable raw mode. |
| | 328 | """ |
| | 329 | |
| | 330 | mode = self.handle.GetConsoleMode() |
| | 331 | if enabled: |
| | 332 | # Flush buffer |
| | 333 | dataBuf = ''.join(self.buf) |
| | 334 | self.buf = [] |
| | 335 | |
| | 336 | if dataBuf: |
| | 337 | self.receivedCallback(dataBuf) |
| | 338 | |
| | 339 | self.checkWork = self._checkWork_raw |
| | 340 | |
| | 341 | # Set mode on the system console, too |
| | 342 | # XXX check me (this seems not to work) |
| | 343 | self.handle.SetConsoleMode(mode & ~ENABLE_NORMAL_MODE) |
| | 344 | else: |
| | 345 | self.checkWork = self._checkWork |
| | 346 | |
| | 347 | # Set mode on the system console, too |
| | 348 | self.handle.SetConsoleMode(mode | ENABLE_NORMAL_MODE) |
| | 349 | |
| | 350 | def setWindowChandeCallback(self, callback): |
| | 351 | """callback is called when the console window buffer is |
| | 352 | changed. |
| | 353 | |
| | 354 | Note: WINDOW_BUFFER_SIZE_EVENT is only raised when changing |
| | 355 | the window *buffer* size from the console menu |
| | 356 | """ |
| | 357 | |
| | 358 | self._windowChangeCallback = callback |
| | 359 | |
| | 360 | |
| | 361 | def _checkWork(self): |
| | 362 | try: |
| | 363 | info = self._stdout.GetConsoleScreenBufferInfo() |
| | 364 | except pywintypes.error: |
| | 365 | # stdout handle has been closed |
| | 366 | self.cleanup() |
| | 367 | return 0 |
| | 368 | |
| | 369 | rowSize = info["MaximumWindowSize"].X |
| | 370 | |
| | 371 | # How much data we read |
| | 372 | workUnits = 0 |
| | 373 | |
| | 374 | # Initialize the current cursor position |
| | 375 | if not self.buf: |
| | 376 | self.pos = info["CursorPosition"] |
| | 377 | |
| | 378 | while 1: |
| | 379 | n = self.handle.GetNumberOfConsoleInputEvents() |
| | 380 | if n == 0: |
| | 381 | break |
| | 382 | |
| | 383 | records = self.handle.ReadConsoleInput(n) |
| | 384 | |
| | 385 | # Process input |
| | 386 | for record in records: |
| | 387 | if record.EventType == win32console.WINDOW_BUFFER_SIZE_EVENT: |
| | 388 | rowSize = record.Size.X |
| | 389 | if self._windowChangeCallback: |
| | 390 | self._windowChangeCallback() |
| | 391 | if record.EventType != win32console.KEY_EVENT \ |
| | 392 | or not record.KeyDown: |
| | 393 | continue |
| | 394 | |
| | 395 | char = record.Char |
| | 396 | n = record.RepeatCount |
| | 397 | if char == '\b': |
| | 398 | pos = self._stdout.GetConsoleScreenBufferInfo()["CursorPosition"] |
| | 399 | |
| | 400 | # Move the cursor |
| | 401 | x = pos.X - n |
| | 402 | if x >= 0: |
| | 403 | pos.X = x |
| | 404 | # XXX assuming |x| < rowSize (I'm lazy) |
| | 405 | elif pos.Y > self.pos.Y: |
| | 406 | pos.X = rowSize - 1 |
| | 407 | pos.Y -= 1 |
| | 408 | |
| | 409 | self._stdout.SetConsoleCursorPosition(pos) |
| | 410 | self._stdout.WriteConsoleOutputCharacter(' ' * n, pos) |
| | 411 | |
| | 412 | self.buf = self.buf[:-n] |
| | 413 | continue |
| | 414 | elif char == '\0': |
| | 415 | vCode = record.VirtualKeyCode |
| | 416 | # XXX TODO handle keyboard navigation |
| | 417 | continue |
| | 418 | elif char == '\r': |
| | 419 | char = '\r\n' * n # XXX check me |
| | 420 | |
| | 421 | self.buf.append(char) |
| | 422 | self._stdout.WriteConsole(char) # do echo |
| | 423 | |
| | 424 | dataBuf = ''.join(self.buf) |
| | 425 | self.buf = [] |
| | 426 | self.pos = info["CursorPosition"] |
| | 427 | |
| | 428 | self.receivedCallback(dataBuf) |
| | 429 | return len(dataBuf) |
| | 430 | |
| | 431 | char = char * n |
| | 432 | data = char.encode(self.cp) |
| | 433 | self._stdout.WriteConsole(data) # do echo |
| | 434 | |
| | 435 | self.buf.append(data) |
| | 436 | workUnits += n |
| | 437 | |
| | 438 | return workUnits |
| | 439 | |
| | 440 | def _checkWork_raw(self): |
| | 441 | # local buffer |
| | 442 | buf = [] |
| | 443 | |
| | 444 | while 1: # XXX is this loop really needed? |
| | 445 | n = self.handle.GetNumberOfConsoleInputEvents() |
| | 446 | if n == 0: |
| | 447 | break |
| | 448 | |
| | 449 | records = self.handle.ReadConsoleInput(n) |
| | 450 | |
| | 451 | # Process input |
| | 452 | for record in records: |
| | 453 | if record.EventType == win32console.WINDOW_BUFFER_SIZE_EVENT: |
| | 454 | if self._windowChangeCallback: |
| | 455 | self._windowChangeCallback() |
| | 456 | if record.EventType != win32console.KEY_EVENT \ |
| | 457 | or not record.KeyDown: |
| | 458 | continue |
| | 459 | |
| | 460 | char = record.Char |
| | 461 | n = record.RepeatCount |
| | 462 | if char == '\0': |
| | 463 | continue |
| | 464 | elif char == '\r': |
| | 465 | char = '\r\n' * n # XXX check me |
| | 466 | |
| | 467 | char = char * n |
| | 468 | data = char.encode(self.cp) |
| | 469 | |
| | 470 | buf.append(data) |
| | 471 | |
| | 472 | |
| | 473 | dataBuf = ''.join(buf) |
| | 474 | if dataBuf: |
| | 475 | self.receivedCallback(dataBuf) |
| | 476 | |
| | 477 | return len(dataBuf) |
| | 478 | |
| | 479 | |
| | 480 | class _PollableWriteConsole(_PollableWriter): |
| | 481 | def __init__(self, con, lostCallback): |
| | 482 | _PollableWriter.__init__(self, con, lostCallback) |
| | 483 | |
| | 484 | self.cp = "cp%d" % win32console.GetConsoleOutputCP() |
| | 485 | |
| | 486 | |
| | 487 | def checkWork(self): |
| | 488 | numBytesWritten = 0 |
| | 489 | if not self.outQueue: |
| | 490 | if self.disconnecting: |
| | 491 | self.writeConnectionLost() |
| | 492 | return 0 |
| | 493 | try: |
| | 494 | self.handle.WriteConsole('') |
| | 495 | except pywintypes.error: |
| | 496 | self.writeConnectionLost() |
| | 497 | return numBytesWritten |
| | 498 | while self.outQueue: |
| | 499 | data = self.outQueue.pop(0) |
| | 500 | errCode = 0 |
| | 501 | try: |
| | 502 | # XXX check if this can block |
| | 503 | nBytesWritten = self.handle.WriteConsole(data) |
| | 504 | except win32console.error: |
| | 505 | self.writeConnectionLost() |
| | 506 | break |
| | 507 | else: |
| | 508 | # assert not errCode, "wtf an error code???" |
| | 509 | numBytesWritten += nBytesWritten |
| | 510 | if len(data) > nBytesWritten: |
| | 511 | self.outQueue.insert(0, data[nBytesWritten:]) |
| | 512 | break |
| | 513 | else: |
| | 514 | resumed = self.bufferEmpty() |
| | 515 | if not resumed and self.disconnecting: |
| | 516 | self.writeConnectionLost() |
| | 517 | return numBytesWritten |