@@ -294,6 +294,233 @@ def test_no_canvas_after_close_all(self):
294
294
self .assertIsNone (w .canvas )
295
295
296
296
297
+
298
+ class TestWindowEventHandling (FakedTkinterTestCase ):
299
+
300
+ def setUp (self ):
301
+
302
+ super ().setUp ()
303
+ self .w = window .Window ()
304
+
305
+
306
+ def test_bind_calls_tk_window_bind (self ):
307
+
308
+ handler = lambda e : None
309
+ self .w .bind ('<KeyPress-a>' , handler )
310
+
311
+ self .w ._tk_window .bind .assert_called_with ('<KeyPress-a>' , handler )
312
+
313
+
314
+ def test_bind_unbind_calls_tk_window_bind_unbind (self ):
315
+
316
+ handler = lambda e : None
317
+ self .w .bind ('<KeyPress-a>' , handler )
318
+ self .w .unbind ('<KeyPress-a>' )
319
+
320
+ self .w ._tk_window .bind .assert_called_with ('<KeyPress-a>' , handler )
321
+ self .w ._tk_window .unbind .assert_called_with ('<KeyPress-a>' , mock .ANY )
322
+
323
+
324
+ def test_unbind_unbound_raises_ValueError (self ):
325
+
326
+ with self .assertRaises (ValueError ):
327
+ self .w .unbind ('<KeyPress-a>' )
328
+
329
+
330
+ def test_unbind_default_works_with_no_bindings (self ):
331
+
332
+ self .w .unbind ()
333
+ self .w ._tk_window .unbind .assert_not_called ()
334
+
335
+
336
+ def test_unbind_default_unbinds_all_bindings (self ):
337
+
338
+ self .w .bind ('<KeyPress-a>' , lambda e : None )
339
+ self .w .bind ('<KeyPress-b>' , lambda e : None )
340
+
341
+ self .w .unbind ()
342
+ unbind_call_args = self .w ._tk_window .unbind .call_args_list
343
+ self .assertEqual (len (unbind_call_args ), 2 , 'unbind call count' )
344
+
345
+
346
+ def test_bind_direct_key_with_no_cbs_raises_ValueError (self ):
347
+
348
+ with self .assertRaises (ValueError ):
349
+ self .w .bind_direct_key ('a' )
350
+
351
+
352
+ def test_bind_direct_key_with_press_cb_calls_window_bind_twice (self ):
353
+
354
+ # Ignore any window setup bind calls that may have taken place.
355
+ self .w ._tk_window .bind .reset_mock ()
356
+
357
+ press_cb = lambda e : None
358
+ self .w .bind_direct_key ('x' , press_cb )
359
+
360
+ bind_call_args = self .w ._tk_window .bind .call_args_list
361
+ self .assertEqual (len (bind_call_args ), 2 , 'unbind call count' )
362
+
363
+ first_call , second_call = bind_call_args
364
+ self .assertEqual (first_call , mock .call ('<KeyPress-x>' , mock .ANY ))
365
+ self .assertEqual (second_call , mock .call ('<KeyRelease-x>' , mock .ANY ))
366
+
367
+
368
+ def test_bind_direct_key_with_release_cb_calls_window_bind_twice (self ):
369
+
370
+ # Ignore any window setup bind calls that may have taken place.
371
+ self .w ._tk_window .bind .reset_mock ()
372
+
373
+ release_cb = lambda e : None
374
+ self .w .bind_direct_key ('y' , None , release_cb )
375
+
376
+ bind_call_args = self .w ._tk_window .bind .call_args_list
377
+ self .assertEqual (len (bind_call_args ), 2 , 'unbind call count' )
378
+
379
+ first_call , second_call = bind_call_args
380
+ self .assertEqual (first_call , mock .call ('<KeyPress-y>' , mock .ANY ))
381
+ self .assertEqual (second_call , mock .call ('<KeyRelease-y>' , mock .ANY ))
382
+
383
+
384
+ def test_bind_direct_key_with_both_cbs_calls_window_bind_twice (self ):
385
+
386
+ # Ignore any window setup bind calls that may have taken place.
387
+ self .w ._tk_window .bind .reset_mock ()
388
+
389
+ press_cb = lambda e : None
390
+ release_cb = lambda e : None
391
+ self .w .bind_direct_key ('z' , press_cb , release_cb )
392
+
393
+ bind_call_args = self .w ._tk_window .bind .call_args_list
394
+ self .assertEqual (len (bind_call_args ), 2 , 'bind call count' )
395
+
396
+ first_call , second_call = bind_call_args
397
+ self .assertEqual (first_call , mock .call ('<KeyPress-z>' , mock .ANY ))
398
+ self .assertEqual (second_call , mock .call ('<KeyRelease-z>' , mock .ANY ))
399
+
400
+
401
+ def test_bind_unbind_direct_key_calls_window_bind_unbind_twice (self ):
402
+
403
+ # Ignore any window setup bind calls that may have taken place.
404
+ self .w ._tk_window .bind .reset_mock ()
405
+
406
+ press_cb = lambda e : None
407
+ release_cb = lambda e : None
408
+ self .w .bind_direct_key ('a' , press_cb , release_cb )
409
+ self .w .unbind_direct_key ('a' )
410
+
411
+ bind_call_args = self .w ._tk_window .bind .call_args_list
412
+ self .assertEqual (len (bind_call_args ), 2 , 'bind call count' )
413
+
414
+ first_call , second_call = bind_call_args
415
+ self .assertEqual (first_call , mock .call ('<KeyPress-a>' , mock .ANY ))
416
+ self .assertEqual (second_call , mock .call ('<KeyRelease-a>' , mock .ANY ))
417
+
418
+ unbind_call_args = self .w ._tk_window .unbind .call_args_list
419
+ self .assertEqual (len (unbind_call_args ), 2 , 'unbind call count' )
420
+
421
+ first_call , second_call = unbind_call_args
422
+ self .assertEqual (first_call , mock .call ('<KeyPress-a>' , mock .ANY ))
423
+ self .assertEqual (second_call , mock .call ('<KeyRelease-a>' , mock .ANY ))
424
+
425
+
426
+ def test_unbind_direct_key_unknown_raises_ValueError (self ):
427
+
428
+ with self .assertRaises (ValueError ):
429
+ self .w .unbind_direct_key ('b' )
430
+
431
+
432
+ def test_unbind_default_works_with_no_bindings (self ):
433
+
434
+ self .w .unbind_direct_key ()
435
+ self .w ._tk_window .unbind .assert_not_called ()
436
+
437
+
438
+ def test_unbind_direct_key_default_unbinds_all_direct_keys (self ):
439
+
440
+ press_cb = lambda e : None
441
+ release_cb = lambda e : None
442
+ self .w .bind_direct_key ('a' , press_cb , release_cb )
443
+ self .w .bind_direct_key ('b' , press_cb , release_cb )
444
+
445
+ self .w .unbind_direct_key ()
446
+
447
+ # Expect 4 unbind calls: KeyPress/KeyRelease for 2 keys.
448
+ unbind_call_args = self .w ._tk_window .unbind .call_args_list
449
+ self .assertEqual (len (unbind_call_args ), 4 , 'unbind call count' )
450
+
451
+
452
+ def _event (self , keysym ):
453
+
454
+ event = mock .Mock ()
455
+ event .keysym = keysym
456
+ return event
457
+
458
+
459
+ def test_bind_direct_key_press_and_release (self ):
460
+
461
+ press_cb = mock .Mock ()
462
+ release_cb = mock .Mock ()
463
+ self .w .bind_direct_key ('a' , press_cb , release_cb )
464
+
465
+ # KeyPress event.
466
+ event = self ._event ('a' )
467
+ self .w ._direct_key_press (event )
468
+
469
+ # Press callback called.
470
+ press_cb .assert_called_once ()
471
+ press_cb .assert_called_with (event )
472
+ release_cb .assert_not_called ()
473
+
474
+ press_cb .reset_mock ()
475
+
476
+ # KeyRelease event. Not held down so _direct_key_idle called.
477
+ self .w ._direct_key_release (event )
478
+ self .w ._direct_key_idle (event )
479
+
480
+ # Release callback called.
481
+ press_cb .assert_not_called ()
482
+ release_cb .assert_called_once ()
483
+ release_cb .assert_called_with (event )
484
+
485
+
486
+ def test_bind_direct_key_press_hold_and_release (self ):
487
+
488
+ press_cb = mock .Mock ()
489
+ release_cb = mock .Mock ()
490
+ self .w .bind_direct_key ('a' , press_cb , release_cb )
491
+
492
+ # KeyPress event.
493
+ event = self ._event ('a' )
494
+ self .w ._direct_key_press (event )
495
+
496
+ # Press callback called.
497
+ press_cb .assert_called_once ()
498
+ press_cb .assert_called_with (event )
499
+ release_cb .assert_not_called ()
500
+
501
+ press_cb .reset_mock ()
502
+
503
+ # Holding the key triggers KeyPress/KeyReleases repeatedly.
504
+ # But never idle, so _direct_key_idle never called.
505
+ for _ in range (10 ):
506
+ self .w ._direct_key_release (event )
507
+ self .w ._direct_key_press (event )
508
+
509
+ # No callbacks while key held down.
510
+ press_cb .assert_not_called ()
511
+ release_cb .assert_not_called ()
512
+
513
+ # Last KeyRelease event. Not held down so _direct_key_idle called.
514
+ self .w ._direct_key_release (event )
515
+ self .w ._direct_key_idle (event )
516
+
517
+ # Release callback called.
518
+ press_cb .assert_not_called ()
519
+ release_cb .assert_called_once ()
520
+ release_cb .assert_called_with (event )
521
+
522
+
523
+
297
524
class TestMultipleWindows (FakedTkinterTestCase ):
298
525
299
526
def test_create_two_windows (self ):
0 commit comments