diff options
Diffstat (limited to 'dom/interfaces/base/nsITextInputProcessor.idl')
-rw-r--r-- | dom/interfaces/base/nsITextInputProcessor.idl | 589 |
1 files changed, 589 insertions, 0 deletions
diff --git a/dom/interfaces/base/nsITextInputProcessor.idl b/dom/interfaces/base/nsITextInputProcessor.idl new file mode 100644 index 000000000..2ba6b1ecc --- /dev/null +++ b/dom/interfaces/base/nsITextInputProcessor.idl @@ -0,0 +1,589 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +interface nsIDOMKeyEvent; +interface mozIDOMWindow; +interface nsITextInputProcessorCallback; + +/** + * An nsITextInputProcessor instance is associated with a top level widget which + * handles native IME. It's associated by calling beginInputTransaction() or + * beginInputTransactionForTests(). While an instance has composition, nobody + * can steal the rights to make composition on the top level widget. In other + * words, if another instance is composing on a top level widget, either + * beginInputTransaction() or beginInputTransactionForTests() returns false + * (i.e., not throws an exception). + * + * NOTE: See nsITextInputProcessorCallback.idl for examples of |callback| in + * following examples, + * + * Example #1 JS-IME can start composition like this: + * + * var TIP = Components.classes["@mozilla.org/text-input-processor;1"]. + * createInstance(Components.interfaces.nsITextInputProcessor); + * if (!TIP.beginInputTransaction(window, callback)) { + * return; // You failed to get the rights to make composition + * } + * // Create a keyboard event if the following compositionc change is caused + * // by a key event. + * var keyEvent = + * new KeyboardEvent("", { key: "foo", code: "bar", keyCode: buzz }); + * // Set new composition string first + * TIP.setPendingCompositionString("some-words-are-inputted"); + * // Set clause information. + * TIP.appendClauseToPendingComposition(23, TIP.ATTR_RAW_CLAUSE); + * // Set caret position, this is optional. + * TIP.setCaretInPendingComposition(23); + * // Flush the pending composition + * if (!TIP.flushPendingComposition(keyEvent)) { + * // If it returns false, it fails to start composition. + * return; + * } + * + * Example #2 JS-IME can separate composition string to two or more clauses: + * + * // Create a keyboard event if the following compositionc change is caused + * // by a key event. + * var keyEvent = + * new KeyboardEvent("", { key: "foo", code: "bar", keyCode: buzz }); + * // First, set composition string again + * TIP.setPendingCompositionString("some-words-are-inputted"); + * // Then, if "are" is selected to convert, there are 3 clauses: + * TIP.appendClauseToPendingComposition(11, TIP.ATTR_CONVERTED_CLAUSE); + * TIP.appendClauseToPendingComposition(3, TIP.ATTR_SELECTED_CLAUSE); + * TIP.appendClauseToPendingComposition(9, TIP.ATTR_CONVERTED_CLAUSE); + * // Show caret at the beginning of the selected clause + * TIP.setCaretInPendingComposition(11); + * // Flush the pending composition. Note that if there is a composition, + * // flushPendingComposition() won't return false. + * TIP.flushPendingComposition(keyEvent); + * + * Example #3 JS-IME can commit composition with specific string with this: + * + * // Create a keyboard event if the following compositionc change is caused + * // by a key event. + * var keyEvent1 = + * new KeyboardEvent("", { key: "foo", code: "bar", keyCode: buzz }); + * // First, there is a composition. + * TIP.setPendingCompositionString("some-words-directly-inputted"); + * TIP.appendClauseToPendingComposition(28, TIP.ATTR_RAW_CLAUSE); + * TIP.flushPendingComposition(keyEvent1); + * // Create a keyboard event if the following commit composition is caused + * // by a key event. + * var keyEvent2 = + * new KeyboardEvent("", { key: "foo", code: "bar", keyCode: buzz }); + * // This is useful when user selects a commit string from candidate list UI + * // which is provided by JS-IME. + * TIP.commitCompositionWith("selected-words-from-candidate-list", keyEvent2); + * + * Example #4 JS-IME can commit composition with the last composition string + * without specifying commit string: + * + * // Create a keyboard event if the following compositionc change is caused + * // by a key event. + * var keyEvent1 = + * new KeyboardEvent("", { key: "foo", code: "bar", keyCode: buzz }); + * // First, there is a composition. + * TIP.setPendingCompositionString("some-words-will-be-commited"); + * TIP.appendClauseToPendingComposition(27, TIP.ATTR_RAW_CLAUSE); + * TIP.flushPendingComposition(keyEvent1); + * // Create a keyboard event if the following commit is caused by a key + * // event. + * var keyEvent2 = + * new KeyboardEvent("", { key: "Enter", code: "Enter", + keyCode: KeyboardEvent.DOM_VK_RETURN }); + * // This is useful when user just type Enter key. + * TIP.commitComposition(keyEvent2); + * + * Example #5 JS-IME can cancel composition with this: + * + * // Create a keyboard event if the following composition change is caused + * // by a key event. + * var keyEvent1 = + * new KeyboardEvent("", { key: "foo", code: "bar", keyCode: buzz }); + * // First, there is a composition. + * TIP.setPendingCompositionString("some-words-will-be-canceled"); + * TIP.appendClauseToPendingComposition(27, TIP.ATTR_RAW_CLAUSE); + * TIP.flushPendingComposition(keyEvent1); + * // Create a keyboard event if the following canceling composition is + * // caused by a key event. + * var keyEvent2 = + * new KeyboardEvent("", { key: "Escape", code: "Escape", + keyCode: KeyboardEvent.DOM_VK_ESCAPE }); + * // This is useful when user doesn't want to commit the composition. + * // FYI: This is same as TIP.commitCompositionWith("") for now. + * TIP.cancelComposition(keyEvent2); + * + * Example #6 JS-IME can insert text only with commitCompositionWith(): + * + * // Create a keyboard event if the following inserting text is caused by a + * // key event. + * var keyEvent1 = + * new KeyboardEvent("", { key: "foo", code: "bar", keyCode: buzz }); + * if (!TIP.beginInputTransaction(window, callback)) { + * return; // You failed to get the rights to make composition + * } + * TIP.commitCompositionWith("Some words", keyEvent1); + * + * Example #7 JS-IME can start composition explicitly: + * + * if (!TIP.beginInputTransaction(window, callback)) { + * return; // You failed to get the rights to make composition + * } + * // Create a keyboard event if the following starting composition is caused + * // by a key event. + * var keyEvent1 = + * new KeyboardEvent("", { key: "foo", code: "bar", keyCode: buzz }); + * // If JS-IME don't want to show composing string in the focused editor, + * // JS-IME can dispatch only compositionstart event with this. + * if (!TIP.startComposition(keyEvent1)) { + * // Failed to start composition. + * return; + * } + * // And when user selects a result from UI of JS-IME, commit with it. + * // Then, the key event should be null. + * TIP.commitCompositionWith("selected-words"); + * + * Example #8 JS-IME or JS-Keyboard should dispatch key events even during + * composition (non-printable key case): + * + * if (!TIP.beginInputTransaction(window, callback)) { + * return; // You failed to get the rights to dispatch key events + * } + * + * // You don't need to specify .keyCode value if it's non-printable key + * // because it can be computed from .key value. + * // If you specify non-zero value to .keyCode, it'll be used. + * var keyEvent = new KeyboardEvent("", { code: "Enter", key: "Enter" }); + * if (TIP.keydown(keyEvent)) { + * // Handle its default action + * } + * + * // Even if keydown event was consumed, keyup event should be dispatched. + * if (TIP.keyup(keyEvent)) { + * // Handle its default action + * } + * + * Example #9 JS-IME or JS-Keyboard should dispatch key events even during + * composition (printable key case): + * + * if (!TIP.beginInputTransaction(window, callback)) { + * return; // You failed to get the rights to dispatch key events + * } + * + * // You need to specify .keyCode value if it's printable key. + * // The rules of .keyCode value is documented in MDN: + * // https://developer.mozilla.org/docs/Web/API/KeyboardEvent.keyCode + * // + * // #1 If the key location is DOM_KEY_LOCATION_NUMPAD and NumLock is + * // active, you should specify DOM_VK_NUMPAD[0-9], DOM_VK_MULTIPLY, + * // DOM_VK_ADD, DOM_VK_SEPARATOR, DOM_VK_SUBTRACT, DOM_VK_DECIMAL or + * // DOM_VK_DIVIDE. + * // #2 If the key is Spacebar, use DOM_VK_SPACE. + * // + * // Following rules are printable keys in DOM_KEY_LOCATION_STANDARD. + * // .keyCode value for a key shouldn't be changed by modifier states: + * // #1 If the key can input [0-9] with any modifier state (except + * // NumLock state), the value should be DOM_VK_[0-9]. + * // #2 Otherwise, and if the key inputs an ASCII alphabet with no + * // active modifiers, use DOM_VK_[A-Z]. + * // #3 Otherwise, and if the key inputs an ASCII alphabet with no + * // active modifiers except Shift key state, use DOM_VK_[A-Z] for + * // the shifted character. E.g., if a key causes non-alphabet + * // character such as "@" or a Unicode character without Shift key + * // but "a" is inputted when Shift key is pressed, the proper + * // keyCode is DOM_VK_A. + * // #4 Otherwise, and if the key inputs another ASCII character with + * // no modifier states, use a proper value for the character. E.g., + * // if the key inputs "*" without Shift key state, it should be + * // DOM_VK_ASTERISK. + * // #5 Otherwise, and if the key inputs another ASCII character with + * // Shift key state, use a proper value for the character. E.g., + * // if a key causes a Unicode character without Shift key but "&" + * // is inputted when Shift key is pressed, the proper keyCode is + * // DOM_VK_AMPERSAND. + * // See above document for the other cases. + * // + * // NOTE: If the software keyboard is 10-key like simple phone, + * // We don't have common rules to decide its .keyCode value. + * // Above rules should be used when the JS-Keyboard emulates PC + * // keyboard. + * // .key value should be inputting character by the key with current + * // modifier state. + * // .code value should be empty string if the JS-Keyboard isn't emulating + * // physical keyboard. Otherwise, use same value with physical keyboard's + * // same key. + * var keyEvent = new KeyboardEvent("", { code: "KeyA", key: "a", + * keyCode: KeyboardEvent.DOM_VK_A }); + * if (TIP.keydown(keyEvent)) { + * // Handle its default action + * } + * + * // Even if keydown event was consumed, keyup event should be dispatched. + * if (TIP.keyup(keyEvent)) { + * // Handle its default action + * } + * + * Example #10 JS-Keyboard doesn't need to initialize modifier states at + * calling either keydown() or keyup(). + * + * // Neither beginInputTransaction() nor beginInputTransactionForTests() + * // resets modifier state. + * if (!TIP.beginInputTransaction(window, callback)) { + * return; // You failed to get the rights to dispatch key events + * } + * + * var leftShift = new KeyboardEvent("", { code: "ShiftLeft", key: "Shift" }); + * + * // This causes following key events will be shifted automatically. + * TIP.keydown(leftShift); + * + * var rightShift = + * new KeyboardEvent("", { code: "ShiftRight", key: "Shift" }); + * + * TIP.keydown(rightShift); + * + * // keyup of one of shift key doesn't cause inactivating "Shift" state. + * TIP.keyup(rightShift); + * + * // This causes inactivating "Shift" state completely. + * TIP.keyup(leftShift); + */ + +[scriptable, builtinclass, uuid(47ae2181-2e98-4d58-84a2-b8db6764ce9a)] +interface nsITextInputProcessor : nsISupports +{ + /** + * Returns true if this instance was dispatched compositionstart but hasn't + * dispatched compositionend yet. + */ + readonly attribute boolean hasComposition; + + /** + * When you create an instance, you must call beginInputTransaction() first + * except when you created the instance for automated tests. + * + * @param aWindow A DOM window. The instance will look for a top + * level widget from this. + * @param aCallback Callback interface which handles requests to + * IME and notifications to IME. This must not be + * null. + * @return If somebody uses internal text input service for a + * composition, this returns false. Otherwise, returns + * true. I.e., only your TIP can create composition + * when this returns true. If this returns false, + * your TIP should wait next chance. + */ + boolean beginInputTransaction(in mozIDOMWindow aWindow, + in nsITextInputProcessorCallback aCallback); + + /** + * When you create an instance for automated test, you must call + * beginInputTransaction(), first. See beginInputTransaction() for more + * detail of this. + * Note that aCallback can be null. If it's null, nsITextInputProcessor + * implementation will handle them automatically. + */ + [optional_argc] boolean + beginInputTransactionForTests( + in mozIDOMWindow aWindow, + [optional] in nsITextInputProcessorCallback aCallback); + + /** + * startComposition() dispatches compositionstart event explicitly. + * IME does NOT need to call this typically since compositionstart event + * is automatically dispatched by sendPendingComposition() if + * compositionstart event hasn't been dispatched yet. If this is called + * when compositionstart has already been dispatched, this throws an + * exception. + * + * @param aKeyboardEvent Key event which causes starting composition. + * If its type value is "keydown", this method + * dispatches only keydown event first. Otherwise, + * dispatches keydown first and keyup at last. + * @param aKeyFlags See KEY_* constants. + * @return Returns true if composition starts normally. + * Otherwise, returns false because it might be + * canceled by the web application. + */ + [optional_argc] + boolean startComposition([optional] in nsIDOMKeyEvent aKeyboardEvent, + [optional] in unsigned long aKeyFlags); + + /** + * Set new composition string. Pending composition will be flushed by + * a call of flushPendingComposition(). However, if the new composition + * string isn't empty, you need to call appendClauseToPendingComposition() to + * fill all characters of aString with one or more clauses before flushing. + * Note that if you need to commit or cancel composition, use + * commitComposition(), commitCompositionWith() or cancelComposition(). + */ + void setPendingCompositionString(in DOMString aString); + + // ATTR_RAW_CLAUSE means that the clause hasn't been selected nor converted + // yet. + const unsigned long ATTR_RAW_CLAUSE = 0x02; + // ATTR_SELECTED_RAW_CLAUSE means that the clause hasn't been converted yet + // but is selected for converting to the other string. + const unsigned long ATTR_SELECTED_RAW_CLAUSE = 0x03; + // ATTR_CONVERTED_CLAUSE means that the clause has already been converted but + // is not selected. This does NOT mean that this clause isn't modifiable. + const unsigned long ATTR_CONVERTED_CLAUSE = 0x04; + // ATTR_SELECTED_CLAUSE means that the clause has already been converted and + // is selected. In other words, the clause is being converted. + const unsigned long ATTR_SELECTED_CLAUSE = 0x05; + + /** + * Append a clause to the pending composition. + * + * If you need to fill the pending composition string with a clause, you + * should call this once. For example: + * appendClauseToPendingComposition(compositionString.length, + * ATTR_RAW_CLAUSE); + * is enough. If you need to separate the pending composition string to + * multiple clauses, you need to call this multiple times. For example, + * if your pending composition string has three clauses and the second clause + * is being converted: + * appendClauseToPendingComposition(firstClauseLength, + * ATTR_CONVERTED_CLAUSE); + * appendClauseToPendingComposition(secondClauseLength, + * ATTR_SELECTED_CLAUSE); + * appendClauseToPendingComposition(thirdClauseLength, + * ATTR_CONVERTED_CLAUSE); + * Note that if sum of aLength mismatches length of the pending composition + * string, flushPendingComposition() will throw an exception. I.e., + * |firstClauseLength + secondClauseLength + thirdClauseLength| must be + * same as the length of pending composition string. + * + * TODO: Should be able to specify custom clause style. + * + * @param aLength Length of the clause. + * @param aAttribute One of ATTR_* constants. + */ + void appendClauseToPendingComposition(in unsigned long aLength, + in unsigned long aAttribute); + + /** + * Set caret offset in the pending composition string. If you don't need to + * show a caret, you don't need to call this. + * + * @param aOffset Caret offset in the pending composition string. + * This must be between 0 and length of the pending + * composition string. + */ + void setCaretInPendingComposition(in unsigned long aOffset); + + /** + * flushPendingComposition() must be called after + * setPendingCompositionString() and appendClauseToPendingComposition() + * (setCaretInPendingComposition() is optional) are called. + * + * Note that compositionstart will be automatically dispatched if this is + * called when there is no composition. + * + * Note that if sum of lengths of appended clauses are not same as composition + * string or caret offset is larger than the composition string length, this + * throws an exception. + * + * @param aKeyboardEvent Key event which causes the composition string. + * If its type value is "keydown", this method + * dispatches only keydown event first. Otherwise, + * dispatches keydown first and keyup at last. + * @param aKeyFlags See KEY_* constants. + * @return Returns true if there is a composition already or + * starting composition automatically. + * Otherwise, i.e., if it cannot start composition + * automatically, e.g., canceled by web apps, returns + * false. + */ + [optional_argc] + boolean flushPendingComposition( + [optional] in nsIDOMKeyEvent aKeyboardEvent, + [optional] in unsigned long aKeyFlags); + + /** + * commitComposition() will commit composition with the last composition + * string. If there is no composition, this will throw an exception. + * + * @param aKeyboardEvent Key event which causes the commit composition. + * If its type value is "keydown", this method + * dispatches only keydown event first. Otherwise, + * dispatches keydown first and keyup at last. + * @param aKeyFlags See KEY_* constants. + */ + [optional_argc] + void commitComposition([optional] in nsIDOMKeyEvent aKeyboardEvent, + [optional] in unsigned long aKeyFlags); + + /** + * commitCompositionWith() will commit composition with the specific string. + * If there is no composition, this will start composition and commit it + * with the specified string. + * + * @param aCommitString The string to be committed. + * @param aKeyboardEvent Key event which causes the commit composition. + * If its type value is "keydown", this method + * dispatches only keydown event first. Otherwise, + * dispatches keydown first and keyup at last. + * @param aKeyFlags See KEY_* constants. + * @return Returns true if there is a composition already or + * starting composition automatically. + * Otherwise, i.e., if it cannot start composition + * automatically, e.g., canceled by web apps, returns + * false. + */ + [optional_argc] + boolean commitCompositionWith(in DOMString aCommitString, + [optional] in nsIDOMKeyEvent aKeyboardEvent, + [optional] in unsigned long aKeyFlags); + + /** + * cancelComposition() will cancel composition. This is for now the same as + * calling commitComposition(""). However, in the future, this might work + * better. If your IME needs to cancel composition, use this instead of + * commitComposition(). + * + * Note that if you tries to cancel composition when there is no composition, + * this throws an exception. + * + * @param aKeyboardEvent Key event which causes the canceling composition. + * If its type value is "keydown", this method + * dispatches only keydown event first. Otherwise, + * dispatches keydown first and keyup at last. + * @param aKeyFlags See KEY_* constants. + */ + [optional_argc] + void cancelComposition([optional] in nsIDOMKeyEvent aKeyboardEvent, + [optional] in unsigned long aKeyFlags); + + // Specifying KEY_DEFAULT_PREVENTED can dispatch key events whose + // defaultPrevented are true. Note that if this is specified, keypress event + // won't be fired. + const unsigned long KEY_DEFAULT_PREVENTED = 0x00000001; + // If KEY_NON_PRINTABLE_KEY is specified and the .key value isn't valid + // key name, the methods will throws an exception. In other words, this + // flag prevents to dispatch key events with wrong key values and to cause + // such key events input the key values as text. + const unsigned long KEY_NON_PRINTABLE_KEY = 0x00000002; + // If KEY_FORCE_PRINTABLE_KEY is specified and even if the .key value is a + // registered key name, it's treated as inputting text value. + const unsigned long KEY_FORCE_PRINTABLE_KEY = 0x00000004; + // If KEY_KEEP_KEY_LOCATION_STANDARD is specified when its .location is not + // initialized or initialized with 0, the value isn't computed with .code + // value. Note that if .location is initialized with non-zero value, + // this flag causes throwing an exception. + // NOTE: This is not recommended to use except for tests. + const unsigned long KEY_KEEP_KEY_LOCATION_STANDARD = 0x00000008; + // If KEY_KEEP_KEYCODE_ZERO is specified when its .keyCode is not initialized + // or initialized with 0, the value isn't computed with .key value when it + // represents non-printable key. Note that if .keyCode is initialized with + // non-zero value, this flag causes throwing an exception. + const unsigned long KEY_KEEP_KEYCODE_ZERO = 0x00000010; + // If KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT is specified when the key event is + // a modifier key's, keydown() and keyup() only modifies its modifier state + // without dispatching key events. This is useful for testing odd behavior + // or emulating legacy API behavior. + const unsigned long KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT = 0x00000020; + + // These values can be used to do bitwise operation with the return value of + // the keydown() method. + const unsigned long KEYEVENT_NOT_CONSUMED = 0x00000000; + const unsigned long KEYDOWN_IS_CONSUMED = 0x00000001; + const unsigned long KEYPRESS_IS_CONSUMED = 0x00000002; + + /** + * keydown() may dispatch a keydown event and some keypress events if + * preceding keydown event isn't consumed and they are necessary. + * Note that even if this is called during composition, key events may not + * be dispatched. In this case, this returns false. + * + * You should initialize at least .key value and .code value of the event. + * Additionally, if you try to emulate a printable key, .keyCode value should + * be specified if there is proper key value. See the comment of above + * example how to decide .keyCode value of a printable key. On the other + * hand, .keyCode value is automatically computed when you try to emulate + * non-printable key. However, if you try to emulate physical keyboard of + * desktop platform, you need to specify proper value explicitly because + * the mapping table of this API isn't enough to emulate the behavior of + * Gecko for desktop platforms. + * + * NOTE: Even if this has composition, JS-Keyboard should call keydown() and + * keyup(). Although, with the default preferences and normal + * conditions, DOM key events won't be fired during composition. + * However, they MAY be dispatched for some reasons, e.g., the web + * content listens only key events, or if the standard DOM event spec + * will be changed in the future. + * + * @param aKeyboardEvent Must be a keyboard event which should be dispatched + * as a keydown event and keypress events. + * #1 Note that you don't need to set charCode value + * because it's computed from its key value. + * #2 If code value is set properly and location value + * isn't specified (i.e., 0), the location value will + * be guessed from the code value. + * #3 Non-defined code names are not allowed. If your + * key isn't registered, file a bug. If your key isn't + * defined by any standards, use "" (empty string). + * #4 .keyCode is guessed from .key value if the key + * name is registered and .keyCode isn't initialized. + * #5 modifier key states, e.g., .shiftKey, are + * ignored. Instead, modifier states are managed by + * each instance and set automatically. + * @param aKeyFlags Special flags. The values can be some of KEY_* + * constants. + * @return KEYEVENT_NOT_CONSUMED, if the keydown event nor + * the following keypress event(s) are consumed. + * KEYDOWN_IS_CONSUMED, if the keydown event is + * consumed. No keypress event will be dispatched in + * this case. + * KEYPRESS_IS_CONSUMED, if the keypress event(s) is + * consumed when dispatched. + * Note that keypress event is always consumed by + * native code for the printable keys (indicating the + * default action has been taken). + */ + [optional_argc] + unsigned long keydown(in nsIDOMKeyEvent aKeyboardEvent, + [optional] in unsigned long aKeyFlags); + + /** + * Similar to keydown(), but this dispatches only a keyup event. + */ + [optional_argc] + boolean keyup(in nsIDOMKeyEvent aKeyboardEvent, + [optional] in unsigned long aKeyFlags); + + /** + * getModifierState() returns modifier state managed by this instance. + * + * @param aModifier One of modifier key names. This doesn't support + * virtual modifiers like "Accel". + * @return true if the modifier key is active. Otherwise, + * false. + */ + boolean getModifierState(in DOMString aModifierKey); + + /** + * shareModifierStateOf() makes the instance shares modifier state of + * another instance. When this is called, the instance refers the modifier + * state of another instance. After that, changes to either this and the + * other instance's modifier state is synchronized. + * + * @param aOther Another instance which will be referred by the + * instance. If this is null, the instance restarts + * to manage modifier state independently. + */ + void shareModifierStateOf(in nsITextInputProcessor aOther); +}; + +%{C++ +#define TEXT_INPUT_PROCESSOR_CID \ + { 0xcaaab47f, 0x1e31, 0x478e, \ + { 0x89, 0x19, 0x97, 0x09, 0x04, 0xe9, 0xcb, 0x72 } } +#define TEXT_INPUT_PROCESSOR_CONTRACTID \ + "@mozilla.org/text-input-processor;1" +%} |