如何防止文本字段中向上/向下箭头的默认行为?

发布于 2024-07-25 10:42:02 字数 506 浏览 2 评论 0原文

我正在为关键字创建一个输入字段,当用户写作时,我会在插入符号位置下方的列表上显示关键字的建议。 输入字段是单行,因此我使用向上/向下箭头键选择建议,然后按 Enter 插入它。 它基本上可以正常工作,但有一个很大的例外,即向上/向下键还将插入符号位置更改为 TextField 的开头/结尾。

我尝试在 KeyboardEvent.KEY_DOWN 事件监听器中使用 preventDefault()stopImmediatePropagation() ,我也用它们来更改所选建议,但这并没有改变任何事情。 当 KeyboardEvent.KEY_DOWN 事件被触发时,我检查了卡雷尚未移动,但从视觉上我可以看到它在释放按键(向上按键)之前正在移动。

我可以保存插入符号位置,然后重置默认行为。 但这会适当地涉及一些使用计时器的类似黑客的代码。

那么有人知道如何防止默认行为吗?

I am making a input field for keywords, and while the users writing I'm displaying suggestions for keyword on a list underneath the caret position.
The input field is single line, so I am using the arrow up/down key to select a suggestion and Enter to insert it.
And it's mostly working, with the big exception that the up/down key also changes the caret position to the begining/ending of the TextField.

I've tried using preventDefault() and stopImmediatePropagation() in the KeyboardEvent.KEY_DOWN event listener that I also use to change the selected suggestion, but that does not change anything.
I checked the carret has not yet moved when KeyboardEvent.KEY_DOWN event is fired, bu visually I can see that it is being move before key is released (key up).

I could just save the caret position, and then reset af the default behaviour. But that would properly involve some hack-like code using a timer.

So does anyone know how to prevent the default behaviour?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

南巷近海 2024-08-01 10:42:02

你无法阻止它,但你可以扭转它。 为此,您可以向同一事件(KeyboardEvent.DOWN)添加具有不同优先级的处理程序。 一个将在 TextField 之前执行,并保存选择索引,另一个将在之后执行并恢复它们。 工作代码如下:

    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.ui.Keyboard;

    import mx.controls.TextInput;
    import mx.events.FlexEvent;

    public class FooledTextInput extends TextInput
    {
        private var ssi : int = 0;
        private var sei : int = 0;

        public function FooledTextInput()
        {
            super();

            this.addEventListener(KeyboardEvent.KEY_DOWN, onBeforeKeyDown, false, 10000);
            this.addEventListener(KeyboardEvent.KEY_DOWN, onAfterKeyDown, false, -10000);
        }

        private function onBeforeKeyDown(e : KeyboardEvent) : void
        {
            if (e.keyCode == Keyboard.UP || e.keyCode == Keyboard.DOWN)
            {
                ssi = this.selectionBeginIndex;
                sei = this.selectionEndIndex;
            }   
        } 

        private function onAfterKeyDown(e : KeyboardEvent) : void
        {
            if (e.keyCode == Keyboard.UP || e.keyCode == Keyboard.DOWN)
            {
                this.setSelection(ssi, sei);
            }   
        } 
    }

您可能想要 ssi(选择开始索引)和 sei(选择结束索引)更好的名称,我懒得找到一些。
我认为这个解决方案是基于 Alex Harui 的一篇文章,我不太记得了,但他的博客上有很多与 Flex 相关的好东西。

更新:对于spark TextInput,预防不仅是可能的,而且非常容易。 您需要做的就是在捕获阶段捕获事件并停止传播。 代码:

package
{
    import flash.events.KeyboardEvent;
    import flash.ui.Keyboard;

    import spark.components.TextInput;

    public class HackedTextInput extends TextInput
    {
        public function HackedTextInput()
        {
            super();
            addEventListener(KeyboardEvent.KEY_DOWN, onBeforeKeyDown, true);
        }

        private function onBeforeKeyDown(e:KeyboardEvent) : void
        {
            if (e.keyCode == Keyboard.UP || e.keyCode == Keyboard.DOWN)
            {
                e.stopImmediatePropagation();
            }   
        }  
    }
}

请注意 addEventListener 调用中的最后一个参数,该参数设置为 true 以便在捕获阶段调用处理程序。 遗憾的是,这一解决方案不适用于 mx TextInput,仅适用于 Spark。

You can't prevent it, but you can reverse it. To do that you add to handlers with different priorities to the same event - KeyboardEvent.DOWN. One will execute before the TextField's , and save selection indexes and the other after, restoring them. Working code follows:

    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.ui.Keyboard;

    import mx.controls.TextInput;
    import mx.events.FlexEvent;

    public class FooledTextInput extends TextInput
    {
        private var ssi : int = 0;
        private var sei : int = 0;

        public function FooledTextInput()
        {
            super();

            this.addEventListener(KeyboardEvent.KEY_DOWN, onBeforeKeyDown, false, 10000);
            this.addEventListener(KeyboardEvent.KEY_DOWN, onAfterKeyDown, false, -10000);
        }

        private function onBeforeKeyDown(e : KeyboardEvent) : void
        {
            if (e.keyCode == Keyboard.UP || e.keyCode == Keyboard.DOWN)
            {
                ssi = this.selectionBeginIndex;
                sei = this.selectionEndIndex;
            }   
        } 

        private function onAfterKeyDown(e : KeyboardEvent) : void
        {
            if (e.keyCode == Keyboard.UP || e.keyCode == Keyboard.DOWN)
            {
                this.setSelection(ssi, sei);
            }   
        } 
    }

You might want better names for ssi (selection start index) and sei (selection end index), I was to lazy to find some.
I think this solution was based on a post of Alex Harui, I don't remember exactly, but he's got a lot of good Flex related stuff on his blog.

UPDATE: For the spark TextInput, preventing is not only possible, it is really easy. All you need to do is catch the event in the capture phase and stopping propagation. Code:

package
{
    import flash.events.KeyboardEvent;
    import flash.ui.Keyboard;

    import spark.components.TextInput;

    public class HackedTextInput extends TextInput
    {
        public function HackedTextInput()
        {
            super();
            addEventListener(KeyboardEvent.KEY_DOWN, onBeforeKeyDown, true);
        }

        private function onBeforeKeyDown(e:KeyboardEvent) : void
        {
            if (e.keyCode == Keyboard.UP || e.keyCode == Keyboard.DOWN)
            {
                e.stopImmediatePropagation();
            }   
        }  
    }
}

Note the last parameter in the addEventListener call, which is set to true in order for the handler to be called in the capture phase. Sadly this solution doesn't work for the mx TextInput, only for the spark one.

满天都是小星星 2024-08-01 10:42:02

我在这里发布了解决此问题的方法:
AS3:setSelection 向上箭头覆盖

I have posted a workaround for this problem here :
AS3: setSelection Up Arrow Override

煞人兵器 2024-08-01 10:42:02

bug-a-lot 的解决方案很有趣 - 我没想到要使用优先级。 相反,我利用了事件过程的不同阶段。 我面临的问题是决定箭头键是否应该在给定文本字段中前进或后退一个字符,或者跳转到表单中的下一个或上一个字段。

首先,我覆盖阶段的事件处理键:

stage.addEventListener(KeyboardEvent.KEY_UP, typing);
// Sneak in before the normal processing handles right and left arrow keystrokes.
stage.addEventListener(KeyboardEvent.KEY_DOWN, pretyping, true, 10); 

请注意,我将处理每个键两次 - 在系统执行它的魔法之前(在 KEY_DOWN 之前调用预键入),这样我可以在 Flash 移动它之前以及系统处理它之后看到插入符在哪里(通过键入,称为KEY_UP 之后)。

/** Capture prior state of text field so we can later tell if user should tab to next field or previous field. */
private function pretyping(evt:KeyboardEvent):void {
    var keyString:String = Configuration.getKeyString(evt);
    if (isFocusInTextBox()) {
        var tf:TextField = getFocus() as TextField;
        capturePhaseCaret = tf.caretIndex;
    }
}

getKeyString 是我的一个方法 - 它所做的就是将这些代码转换为方便的助记符。 isFocusInTextBox 是对我的焦点管理器的调用 - 我替换了标准焦点管理器以克服其他 Flash 问题。 我只需要知道该内容是否是文本字段。

接下来,我必须在 Flash 已经移动插入符号甚至可能跳转到新字段后处理该键,并通过查看先前的状态,确定 Flash 执行的操作并撤消它,然后执行应该执行的操作发生。 我的函数“typing”有很多本次讨论不需要的内容,但它所做的重要事情是调用allowKeyMapping。 allowedKeyMapping 决定用户是从文本字段中的最后一个字符位置输入向前箭头(或向下箭头),还是从开头输入向后箭头。 如果是这样,“键入”将分别跳到下一个或上一个字段。

    /** Prefer default behavior and do not allow certain kestrokes to be reinterpreted by key mappings, such as left and right cursor keys in text boxes. */
    private function allowKeyMapping(keyString:String) {
        var allow:Boolean;
        // If focus is in a text field, allow right arrow to advance to next field only if caret is at end of text.
        // Conversely, allow left arrow to back up to previous field only if caret is at beginning of text.
        // The trick is that the normal processing of keystrokes by TextFields occurs before this method is called,
        // so we need to know the caret position from before the key was pressed, which we have stored in capturePhaseCaret, set in pretyping.
        if (isDragging) {
            allow = false;
        }
        else if (isFocusInTextBox()) {
            var tf:TextField = getFocus() as TextField;
            if (keyString == Configuration.LEFT_CURSOR_KEY) {
                allow = tf.caretIndex == 0 && capturePhaseCaret == 0;
            }
            else if (keyString == Configuration.RIGHT_CURSOR_KEY) {
                allow = tf.caretIndex == tf.text.length && capturePhaseCaret == tf.text.length;
            }
            else {
                allow = true;
            }
        }
        else {
            allow = true;
        }
        return allow;
    }

很抱歉我没有准备一个紧凑的例子。 我只是认为有必要强调一下,无论您是否希望 Flash 为您做事,您都可以避开它们。

The solution by bug-a-lot is intriguing - I didnlt think to use priorities. Instead, I made use of the different phases of the event process. The problem for me was to decide whether the arrow keys should advance or retreat one character within the given text field, or jump to the next or previous field in the form.

First, I override the stage's event handling for the keys:

stage.addEventListener(KeyboardEvent.KEY_UP, typing);
// Sneak in before the normal processing handles right and left arrow keystrokes.
stage.addEventListener(KeyboardEvent.KEY_DOWN, pretyping, true, 10); 

Note that I will process each key twice - before the system does it's wizardry (pretyping is called before the KEY_DOWN) so I can see where the caret is before Flash moves it, and after the system handles it (with typing, called after KEY_UP).

/** Capture prior state of text field so we can later tell if user should tab to next field or previous field. */
private function pretyping(evt:KeyboardEvent):void {
    var keyString:String = Configuration.getKeyString(evt);
    if (isFocusInTextBox()) {
        var tf:TextField = getFocus() as TextField;
        capturePhaseCaret = tf.caretIndex;
    }
}

getKeyString is a method of mine - all it does is turn those codes into convenient mnemonics. And isFocusInTextBox is a call to my focus manager - I replaced the standard focus manager to overcome other Flash issues. I just need to know if the thing is a text field or not.

Next I have to process the key after Flash has already moved the caret and maybe even jumped to a new field, and by looking at the prior state, decide what Flash did and undo it and then do what ought to happen. My function "typing" has a lot of stuff not needed for this discussion, but the important thing it does is call allowKeyMapping. allowKeyMapping decides if the user entered forward arrow (or down arrow) from the last character position in the text field, or entered backward arrow from the beginning. If so, "typing" will tab to the next or previous field, respectively.

    /** Prefer default behavior and do not allow certain kestrokes to be reinterpreted by key mappings, such as left and right cursor keys in text boxes. */
    private function allowKeyMapping(keyString:String) {
        var allow:Boolean;
        // If focus is in a text field, allow right arrow to advance to next field only if caret is at end of text.
        // Conversely, allow left arrow to back up to previous field only if caret is at beginning of text.
        // The trick is that the normal processing of keystrokes by TextFields occurs before this method is called,
        // so we need to know the caret position from before the key was pressed, which we have stored in capturePhaseCaret, set in pretyping.
        if (isDragging) {
            allow = false;
        }
        else if (isFocusInTextBox()) {
            var tf:TextField = getFocus() as TextField;
            if (keyString == Configuration.LEFT_CURSOR_KEY) {
                allow = tf.caretIndex == 0 && capturePhaseCaret == 0;
            }
            else if (keyString == Configuration.RIGHT_CURSOR_KEY) {
                allow = tf.caretIndex == tf.text.length && capturePhaseCaret == tf.text.length;
            }
            else {
                allow = true;
            }
        }
        else {
            allow = true;
        }
        return allow;
    }

I am sorry I do not have a compact example prepared. I just thought it important to emphasize that you can get around Flash's penchant for doing things for you whether you want them to happen or not.

左岸枫 2024-08-01 10:42:02

bug-a-lot 的解决方案可能会产生一些轻弹效果。

这里描述了使用 stage.invalidate() 和 stage 的 Event.RENDER 的有效解决方案和好技巧:

AS3: setSelection 向上箭头覆盖

There could be some flick effect with the bug-a-lot's solution.

There is a working solution and good trick using stage.invalidate() and stage's Event.RENDER described here :

AS3: setSelection Up Arrow Override

罪#恶を代价 2024-08-01 10:42:02

这是我解决该问题的方法。 我确信有更好的方法,但它可能需要扩展 TextInput 控件。

private function onKeyDown(event:KeyboardEvent):void
{
    if(event.keyCode == flash.ui.Keyboard.UP)
    {
        var begin:int = textinput.selectionBeginIndex;
        var end:int = textinput.selectionEndIndex;
        textinput.setSelection(begin,end);
    }
}

不性感,但很有效。

This is my workaround for that problem. I'm sure there is a better way but it would probably require extending the TextInput control.

private function onKeyDown(event:KeyboardEvent):void
{
    if(event.keyCode == flash.ui.Keyboard.UP)
    {
        var begin:int = textinput.selectionBeginIndex;
        var end:int = textinput.selectionEndIndex;
        textinput.setSelection(begin,end);
    }
}

Not sexy but it works.

万人眼中万个我 2024-08-01 10:42:02

默认情况下,UIComponent 上的事件优先级为 0
所以你可以随时停止阻止某些事情发生,在这里你可以阻止所有KeyboardEvent.KEY_DOWN

yourObject.addEventListener(KeyboardEvent.KEY_DOWN, _preventDefault, false, 1, true );
private function _preventDefault(event:KeyboardEvent):void 
{
event.preventDefault();
event.stopImmediatePropagation();
}

by default event are priority 0 on UIComponent
so you can always stop stop something to happen, here you prevent all KeyboardEvent.KEY_DOWN

yourObject.addEventListener(KeyboardEvent.KEY_DOWN, _preventDefault, false, 1, true );
private function _preventDefault(event:KeyboardEvent):void 
{
event.preventDefault();
event.stopImmediatePropagation();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文