key-event.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. (function(window, document) {
  2. var KeyEvent = function(data, type) {
  3. this.keyCode = 'keyCode' in data ? data.keyCode : 0;
  4. this.charCode = 'charCode' in data ? data.charCode : 0;
  5. var modifiers = 'modifiers' in data ? data.modifiers : [];
  6. this.ctrlKey = false;
  7. this.metaKey = false;
  8. this.altKey = false;
  9. this.shiftKey = false;
  10. for (var i = 0; i < modifiers.length; i++) {
  11. this[modifiers[i] + 'Key'] = true;
  12. }
  13. this.type = type || 'keypress';
  14. };
  15. KeyEvent.prototype.toNative = function() {
  16. var event = document.createEventObject ? document.createEventObject() : document.createEvent('Events');
  17. if (event.initEvent) {
  18. event.initEvent(this.type, true, true);
  19. }
  20. event.keyCode = this.keyCode;
  21. event.which = this.charCode || this.keyCode;
  22. event.shiftKey = this.shiftKey;
  23. event.metaKey = this.metaKey;
  24. event.altKey = this.altKey;
  25. event.ctrlKey = this.ctrlKey;
  26. return event;
  27. };
  28. KeyEvent.prototype.fire = function(element) {
  29. var event = this.toNative();
  30. if (element.dispatchEvent) {
  31. element.dispatchEvent(event);
  32. return;
  33. }
  34. element.fireEvent('on' + this.type, event);
  35. };
  36. // simulates complete key event as if the user pressed the key in the browser
  37. // triggers a keydown, then a keypress, then a keyup
  38. KeyEvent.simulate = function(charCode, keyCode, modifiers, element, repeat, options) {
  39. if (modifiers === undefined) {
  40. modifiers = [];
  41. }
  42. if (element === undefined) {
  43. element = document;
  44. }
  45. if (repeat === undefined) {
  46. repeat = 1;
  47. }
  48. if (options === undefined) {
  49. options = {};
  50. }
  51. // Re-target the element so that `event.target` becomes the shadow host. See:
  52. // https://developers.google.com/web/fundamentals/web-components/shadowdom#events
  53. // This is a bit of a lie because true events would re-target the event target both for
  54. // closed and open shadow trees. `KeyEvent` is not a true event and will fire the event
  55. // directly from the shadow host for closed shadow trees. For open trees, this would make
  56. // the tests fail as the actual event that will be eventually dispatched would have an
  57. // incorrect `Event.composedPath()` starting with the shadow host instead of the
  58. // initial event target.
  59. if (options.shadowHost && options.shadowHost.shadowRoot === null) {
  60. // closed shadow dom
  61. element = options.shadowHost;
  62. }
  63. var modifierToKeyCode = {
  64. 'shift': 16,
  65. 'ctrl': 17,
  66. 'alt': 18,
  67. 'meta': 91
  68. };
  69. // if the key is a modifier then take it out of the regular
  70. // keypress/keydown
  71. if (keyCode == 16 || keyCode == 17 || keyCode == 18 || keyCode == 91) {
  72. repeat = 0;
  73. }
  74. var modifiersToInclude = [];
  75. var keyEvents = [];
  76. // modifiers would go down first
  77. for (var i = 0; i < modifiers.length; i++) {
  78. modifiersToInclude.push(modifiers[i]);
  79. keyEvents.push(new KeyEvent({
  80. charCode: 0,
  81. keyCode: modifierToKeyCode[modifiers[i]],
  82. modifiers: modifiersToInclude
  83. }, 'keydown'));
  84. }
  85. // @todo factor in duration for these
  86. while (repeat > 0) {
  87. keyEvents.push(new KeyEvent({
  88. charCode: 0,
  89. keyCode: keyCode,
  90. modifiers: modifiersToInclude
  91. }, 'keydown'));
  92. keyEvents.push(new KeyEvent({
  93. charCode: charCode,
  94. keyCode: charCode,
  95. modifiers: modifiersToInclude
  96. }, 'keypress'));
  97. repeat--;
  98. }
  99. keyEvents.push(new KeyEvent({
  100. charCode: 0,
  101. keyCode: keyCode,
  102. modifiers: modifiersToInclude
  103. }, 'keyup'));
  104. // now lift up the modifier keys
  105. for (i = 0; i < modifiersToInclude.length; i++) {
  106. var modifierKeyCode = modifierToKeyCode[modifiersToInclude[i]];
  107. modifiersToInclude.splice(i, 1);
  108. keyEvents.push(new KeyEvent({
  109. charCode: 0,
  110. keyCode: modifierKeyCode,
  111. modifiers: modifiersToInclude
  112. }, 'keyup'));
  113. }
  114. for (i = 0; i < keyEvents.length; i++) {
  115. // console.log('firing', keyEvents[i].type, keyEvents[i].keyCode, keyEvents[i].charCode);
  116. keyEvents[i].fire(element);
  117. }
  118. };
  119. window.KeyEvent = KeyEvent;
  120. // expose as a common js module
  121. if (typeof module !== 'undefined' && module.exports) {
  122. module.exports = KeyEvent;
  123. }
  124. // expose KeyEvent as an AMD module
  125. if (typeof define === 'function' && define.amd) {
  126. define(function() {
  127. return KeyEvent;
  128. });
  129. }
  130. }) (typeof window !== 'undefined' ? window : null, typeof window !== 'undefined' ? document : null);