// ==UserScript==
// @name Peniquitous
// @description Ubiquitous Ctrl-P & Ctrl-N
// @version 0.1.0
// @namespace com.teddywing
// ==/UserScript==
// Copyright (c) 2015, 2021 Teddy Wing
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
function key_event () {
//
// Apache License
// Version 2.0, January 2004
// http://www.apache.org/licenses/
//
// TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
//
// 1. Definitions.
//
// "License" shall mean the terms and conditions for use, reproduction,
// and distribution as defined by Sections 1 through 9 of this document.
//
// "Licensor" shall mean the copyright owner or entity authorized by
// the copyright owner that is granting the License.
//
// "Legal Entity" shall mean the union of the acting entity and all
// other entities that control, are controlled by, or are under common
// control with that entity. For the purposes of this definition,
// "control" means (i) the power, direct or indirect, to cause the
// direction or management of such entity, whether by contract or
// otherwise, or (ii) ownership of fifty percent (50%) or more of the
// outstanding shares, or (iii) beneficial ownership of such entity.
//
// "You" (or "Your") shall mean an individual or Legal Entity
// exercising permissions granted by this License.
//
// "Source" form shall mean the preferred form for making modifications,
// including but not limited to software source code, documentation
// source, and configuration files.
//
// "Object" form shall mean any form resulting from mechanical
// transformation or translation of a Source form, including but
// not limited to compiled object code, generated documentation,
// and conversions to other media types.
//
// "Work" shall mean the work of authorship, whether in Source or
// Object form, made available under the License, as indicated by a
// copyright notice that is included in or attached to the work
// (an example is provided in the Appendix below).
//
// "Derivative Works" shall mean any work, whether in Source or Object
// form, that is based on (or derived from) the Work and for which the
// editorial revisions, annotations, elaborations, or other modifications
// represent, as a whole, an original work of authorship. For the purposes
// of this License, Derivative Works shall not include works that remain
// separable from, or merely link (or bind by name) to the interfaces of,
// the Work and Derivative Works thereof.
//
// "Contribution" shall mean any work of authorship, including
// the original version of the Work and any modifications or additions
// to that Work or Derivative Works thereof, that is intentionally
// submitted to Licensor for inclusion in the Work by the copyright owner
// or by an individual or Legal Entity authorized to submit on behalf of
// the copyright owner. For the purposes of this definition, "submitted"
// means any form of electronic, verbal, or written communication sent
// to the Licensor or its representatives, including but not limited to
// communication on electronic mailing lists, source code control systems,
// and issue tracking systems that are managed by, or on behalf of, the
// Licensor for the purpose of discussing and improving the Work, but
// excluding communication that is conspicuously marked or otherwise
// designated in writing by the copyright owner as "Not a Contribution."
//
// "Contributor" shall mean Licensor and any individual or Legal Entity
// on behalf of whom a Contribution has been received by Licensor and
// subsequently incorporated within the Work.
//
// 2. Grant of Copyright License. Subject to the terms and conditions of
// this License, each Contributor hereby grants to You a perpetual,
// worldwide, non-exclusive, no-charge, royalty-free, irrevocable
// copyright license to reproduce, prepare Derivative Works of,
// publicly display, publicly perform, sublicense, and distribute the
// Work and such Derivative Works in Source or Object form.
//
// 3. Grant of Patent License. Subject to the terms and conditions of
// this License, each Contributor hereby grants to You a perpetual,
// worldwide, non-exclusive, no-charge, royalty-free, irrevocable
// (except as stated in this section) patent license to make, have made,
// use, offer to sell, sell, import, and otherwise transfer the Work,
// where such license applies only to those patent claims licensable
// by such Contributor that are necessarily infringed by their
// Contribution(s) alone or by combination of their Contribution(s)
// with the Work to which such Contribution(s) was submitted. If You
// institute patent litigation against any entity (including a
// cross-claim or counterclaim in a lawsuit) alleging that the Work
// or a Contribution incorporated within the Work constitutes direct
// or contributory patent infringement, then any patent licenses
// granted to You under this License for that Work shall terminate
// as of the date such litigation is filed.
//
// 4. Redistribution. You may reproduce and distribute copies of the
// Work or Derivative Works thereof in any medium, with or without
// modifications, and in Source or Object form, provided that You
// meet the following conditions:
//
// (a) You must give any other recipients of the Work or
// Derivative Works a copy of this License; and
//
// (b) You must cause any modified files to carry prominent notices
// stating that You changed the files; and
//
// (c) You must retain, in the Source form of any Derivative Works
// that You distribute, all copyright, patent, trademark, and
// attribution notices from the Source form of the Work,
// excluding those notices that do not pertain to any part of
// the Derivative Works; and
//
// (d) If the Work includes a "NOTICE" text file as part of its
// distribution, then any Derivative Works that You distribute must
// include a readable copy of the attribution notices contained
// within such NOTICE file, excluding those notices that do not
// pertain to any part of the Derivative Works, in at least one
// of the following places: within a NOTICE text file distributed
// as part of the Derivative Works; within the Source form or
// documentation, if provided along with the Derivative Works; or,
// within a display generated by the Derivative Works, if and
// wherever such third-party notices normally appear. The contents
// of the NOTICE file are for informational purposes only and
// do not modify the License. You may add Your own attribution
// notices within Derivative Works that You distribute, alongside
// or as an addendum to the NOTICE text from the Work, provided
// that such additional attribution notices cannot be construed
// as modifying the License.
//
// You may add Your own copyright statement to Your modifications and
// may provide additional or different license terms and conditions
// for use, reproduction, or distribution of Your modifications, or
// for any such Derivative Works as a whole, provided Your use,
// reproduction, and distribution of the Work otherwise complies with
// the conditions stated in this License.
//
// 5. Submission of Contributions. Unless You explicitly state otherwise,
// any Contribution intentionally submitted for inclusion in the Work
// by You to the Licensor shall be under the terms and conditions of
// this License, without any additional terms or conditions.
// Notwithstanding the above, nothing herein shall supersede or modify
// the terms of any separate license agreement you may have executed
// with Licensor regarding such Contributions.
//
// 6. Trademarks. This License does not grant permission to use the trade
// names, trademarks, service marks, or product names of the Licensor,
// except as required for reasonable and customary use in describing the
// origin of the Work and reproducing the content of the NOTICE file.
//
// 7. Disclaimer of Warranty. Unless required by applicable law or
// agreed to in writing, Licensor provides the Work (and each
// Contributor provides its Contributions) on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied, including, without limitation, any warranties or conditions
// of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
// PARTICULAR PURPOSE. You are solely responsible for determining the
// appropriateness of using or redistributing the Work and assume any
// risks associated with Your exercise of permissions under this License.
//
// 8. Limitation of Liability. In no event and under no legal theory,
// whether in tort (including negligence), contract, or otherwise,
// unless required by applicable law (such as deliberate and grossly
// negligent acts) or agreed to in writing, shall any Contributor be
// liable to You for damages, including any direct, indirect, special,
// incidental, or consequential damages of any character arising as a
// result of this License or out of the use or inability to use the
// Work (including but not limited to damages for loss of goodwill,
// work stoppage, computer failure or malfunction, or any and all
// other commercial damages or losses), even if such Contributor
// has been advised of the possibility of such damages.
//
// 9. Accepting Warranty or Additional Liability. While redistributing
// the Work or Derivative Works thereof, You may choose to offer,
// and charge a fee for, acceptance of support, warranty, indemnity,
// or other liability obligations and/or rights consistent with this
// License. However, in accepting such obligations, You may act only
// on Your own behalf and on Your sole responsibility, not on behalf
// of any other Contributor, and only if You agree to indemnify,
// defend, and hold each Contributor harmless for any liability
// incurred by, or claims asserted against, such Contributor by reason
// of your accepting any such warranty or additional liability.
//
// END OF TERMS AND CONDITIONS
//
// --- Exceptions to the Apache 2.0 License ----
//
// As an exception, if, as a result of your compiling your source code, portions
// of this Software are embedded into an Object form of such source code, you
// may redistribute such embedded portions in such Object form without complying
// with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
//
// In addition, if you combine or link compiled forms of this Software with
// software that is licensed under the GPLv2 ("Combined Software") and if a
// court of competent jurisdiction determines that the patent provision (Section
// 3), the indemnity provision (Section 9) or other Section of the License
// conflicts with the conditions of the GPLv2, you may retroactively and
// prospectively choose to deem waived or otherwise exclude such Section(s) of
// the License, but only in their entirety and only with respect to the Combined
// Software.
var KeyEvent = function(data, type) {
this.keyCode = 'keyCode' in data ? data.keyCode : 0;
this.charCode = 'charCode' in data ? data.charCode : 0;
var modifiers = 'modifiers' in data ? data.modifiers : [];
this.ctrlKey = false;
this.metaKey = false;
this.altKey = false;
this.shiftKey = false;
for (var i = 0; i < modifiers.length; i++) {
this[modifiers[i] + 'Key'] = true;
}
this.type = type || 'keypress';
};
KeyEvent.prototype.toNative = function() {
var event = document.createEventObject ? document.createEventObject() : document.createEvent('Events');
if (event.initEvent) {
event.initEvent(this.type, true, true);
}
event.keyCode = this.keyCode;
event.which = this.charCode || this.keyCode;
event.shiftKey = this.shiftKey;
event.metaKey = this.metaKey;
event.altKey = this.altKey;
event.ctrlKey = this.ctrlKey;
return event;
};
KeyEvent.prototype.fire = function(element) {
var event = this.toNative();
if (element.dispatchEvent) {
element.dispatchEvent(event);
return;
}
element.fireEvent('on' + this.type, event);
};
// simulates complete key event as if the user pressed the key in the browser
// triggers a keydown, then a keypress, then a keyup
KeyEvent.simulate = function(charCode, keyCode, modifiers, element, repeat, options) {
if (modifiers === undefined) {
modifiers = [];
}
if (element === undefined) {
element = document;
}
if (repeat === undefined) {
repeat = 1;
}
if (options === undefined) {
options = {};
}
// Re-target the element so that `event.target` becomes the shadow host. See:
// https://developers.google.com/web/fundamentals/web-components/shadowdom#events
// This is a bit of a lie because true events would re-target the event target both for
// closed and open shadow trees. `KeyEvent` is not a true event and will fire the event
// directly from the shadow host for closed shadow trees. For open trees, this would make
// the tests fail as the actual event that will be eventually dispatched would have an
// incorrect `Event.composedPath()` starting with the shadow host instead of the
// initial event target.
if (options.shadowHost && options.shadowHost.shadowRoot === null) {
// closed shadow dom
element = options.shadowHost;
}
var modifierToKeyCode = {
'shift': 16,
'ctrl': 17,
'alt': 18,
'meta': 91
};
// if the key is a modifier then take it out of the regular
// keypress/keydown
if (keyCode == 16 || keyCode == 17 || keyCode == 18 || keyCode == 91) {
repeat = 0;
}
var modifiersToInclude = [];
var keyEvents = [];
// modifiers would go down first
for (var i = 0; i < modifiers.length; i++) {
modifiersToInclude.push(modifiers[i]);
keyEvents.push(new KeyEvent({
charCode: 0,
keyCode: modifierToKeyCode[modifiers[i]],
modifiers: modifiersToInclude
}, 'keydown'));
}
// @todo factor in duration for these
while (repeat > 0) {
keyEvents.push(new KeyEvent({
charCode: 0,
keyCode: keyCode,
modifiers: modifiersToInclude
}, 'keydown'));
keyEvents.push(new KeyEvent({
charCode: charCode,
keyCode: charCode,
modifiers: modifiersToInclude
}, 'keypress'));
repeat--;
}
keyEvents.push(new KeyEvent({
charCode: 0,
keyCode: keyCode,
modifiers: modifiersToInclude
}, 'keyup'));
// now lift up the modifier keys
for (i = 0; i < modifiersToInclude.length; i++) {
var modifierKeyCode = modifierToKeyCode[modifiersToInclude[i]];
modifiersToInclude.splice(i, 1);
keyEvents.push(new KeyEvent({
charCode: 0,
keyCode: modifierKeyCode,
modifiers: modifiersToInclude
}, 'keyup'));
}
for (i = 0; i < keyEvents.length; i++) {
// console.log('firing', keyEvents[i].type, keyEvents[i].keyCode, keyEvents[i].charCode);
keyEvents[i].fire(element);
}
};
window.KeyEvent = KeyEvent;
// expose as a common js module
if (typeof module !== 'undefined' && module.exports) {
module.exports = KeyEvent;
}
// expose KeyEvent as an AMD module
if (typeof define === 'function' && define.amd) {
define(function() {
return KeyEvent;
});
}
}
function peniquitous () {
// Copyright (c) 2015, 2021 Teddy Wing
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
var key_codes = {
p: 80,
n: 78,
UP_ARROW: 38,
DOWN_ARROW: 40
};
// Additional types:
// * email
// * number
// * tel
// * url
var all_inputs = document.querySelectorAll('input[type="text"], input[type="search"]');
for (var i = 0; i < all_inputs.length; i++) {
all_inputs[i].addEventListener('keyup', function(e) {
if (e.ctrlKey && e.keyCode === key_codes.p) {
KeyEvent.simulate(0, key_codes.UP_ARROW, [], e.target);
}
else if (e.ctrlKey && e.keyCode === key_codes.n) {
KeyEvent.simulate(0, key_codes.DOWN_ARROW, [], e.target);
}
});
}
}
(function() {
[
key_event,
peniquitous
].forEach(function(script) {
var s = document.createElement('script');
s.appendChild(
document.createTextNode('(' + script + ')();')
);
document.documentElement.appendChild(s);
});
})();