رسیدگی به کنش‌های صفحه‌کلید

وقتی کاربر روی عنصر نوشتاری ویرایش‌پذیری مثل TextField تمرکز می‌کند، و دستگاه صفحه‌کلید سخت‌افزاری متصل دارد، همه ورودی‌ها توسط سیستم مدیریت می‌شود. با مدیریت رویدادهای کلیدی می‌توانید میان‌برهای صفحه‌کلید ارائه دهید.

میان‌برهای پیش‌فرض صفحه‌کلید

میان‌برهای صفحه‌کلید زیر به‌طور پیش‌فرض دردسترس است.

میان‌برهای صفحه‌کلید کنش ترکیب‌پذیرهایی که از میان‌بر پشتیبانی می‌کنند
تبدیل+مهار+کلید چپ‌بَر/کلید راست‌بَر انتخاب نوشتار تا ابتدای/انتهای کلمه BasicTextField، TextField
تبدیل+مهار+کلید بالابر/کلید پایین‌بر انتخاب نوشتار تا ابتدای/انتهای پاراگراف BasicTextField، TextField
تبدیل+دگرساز+کلید بالابر/کلید پایین‌بر یا تبدیل+متا+کلید چپ‌بر/کلید راست‌بر انتخاب نوشتار تا ابتدا/انتهای نوشتار BasicTextField، TextField
تبدیل+کلید چپ‌بَر/کلید راست‌بَر انتخاب نویسه‌ها BasicTextField، TextField
Ctrl+A انتخاب همه BasicTextField، TextField
Ctrl+C/Ctrl+X/Ctrl+V کپی/برش/جای‌گذاری BasicTextField، TextField
Ctrl+Z/Ctrl+Shift+Z واگرداندن/ازنو انجام دادن BasicTextField، TextField
PageDown/PageUp پیمایش LazyColumn، اصلاح‌گر verticalScroll، اصلاح‌گر scrollable

رویدادهای کلیدی

در Compose، می‌توانید با اصلاح‌کننده onKeyEvent، یک کلیدزنی تکی را مدیریت کنید. اصلاح‌کننده یک لامبدا را می‌پذیرد که وقتی مؤلفه اصلاح‌شده رویداد کلیدی را دریافت می‌کند، فراخوانی می‌شود. رویداد کلیدی به‌عنوان یک شیء KeyEvent توصیف می‌شود. با مراجعه به شیء در لامبدای منتقل‌شده به اصلاح‌گر onKeyEvent می‌توانید اطلاعات هر رویداد کلیدی را دریافت کنید.

یک ضربه کلید دو رویداد کلیدی ارسال می‌کند. یکی وقتی کاربر کلید را فشار می‌دهد راه‌اندازی می‌شود؛ دیگری وقتی کلید رها می‌شود راه‌اندازی می‌شود. با مراجعه به مشخصه type شیء KeyEvent می‌توانید دو رویداد کلیدی را از هم تشخیص دهید.

مقدار برگشتی لامبدای onKeyEvent نشان می‌دهد که آیا رویداد کلیدی مدیریت شده است یا نه. اگر برنامه‌تان رویداد کلیدی را مدیریت می‌کند، true را برگردانید، که انتشار رویداد را متوقف می‌کند.

تکه‌کد زیر نشان می‌دهد که چگونه می‌توان تابع doSomething() را هنگامی که کاربر کلید S را در مؤلفه Box رها می‌کند، فراخوانی کرد:

Box(
    modifier = Modifier
        .onKeyEvent {
            if (
                it.type == KeyEventType.KeyUp &&
                it.key == Key.S
            ) {
                doSomething()
                true
            } else {
                false
            }
        }
        .focusable()
) {
    Text("Press S key")
}

کلیدهای توصیف‌گر

شیء KeyEvent دارای مشخصه‌های زیر است که نشان می‌دهد آیا کلیدهای اصلاح‌گر فشار داده شده‌اند یا نه:

در شرح رویدادهای کلیدی که برنامه‌تان مدیریت می‌کند، دقیق باشید. قطعه کد زیر تابع doSomething() را فقط درصورتی فراخوانی می‌کند که کاربر فقط کلید S را رها کند. اگر کاربر کلید اصلاح‌گری را فشار دهد، مثلاً کلید تبدیل، برنامه تابع را فراخوانی نمی‌کند.

Box(
    modifier = Modifier
        .focusable()
        .onKeyEvent {
            if (
                it.type == KeyEventType.KeyUp &&
                it.key == Key.S &&
                !it.isAltPressed &&
                !it.isCtrlPressed &&
                !it.isMetaPressed &&
                !it.isShiftPressed
            ) {
                doSomething()
                true
            } else {
                false
            }
        }
) {
    Text("Press S key with a modifier key")
}

رویدادهای کلیک کلید «فاصله» و «ورود»

کلیدهای نوار فاصله و ورود نیز رویدادهای کلیک را راه‌اندازی می‌کنند. برای مثال، کاربران می‌توانند بازپخش رسانه را بااستفاده از کلید فاصله یا کلید Enter و با مدیریت رویدادهای کلیک به‌صورت زیر تغییر دهند (پخش یا مکث کنند):

MediaPlayer(modifier = Modifier.clickable { togglePausePlay() })

اصلاح‌کننده clickable رویدادهای کلیدی را رهگیری می‌کند و وقتی کلید کلید فاصله یا ورود فشار داده می‌شود، فراخوانی برگشتی onClick() را فراخوانی می‌کند. به همین دلیل است که با فشار دادن کلید نوار فاصله یا Enter در گزیده، تابع togglePausePlay() فراخوانده می‌شود.

رویدادهای کلیدی مصرف‌نشده

رویدادهای کلیدی مصرف‌نشده از مؤلفه‌ای که رویداد در آن رخ داده است به مؤلفه بیرونی دربرگیرنده منتشر می‌شوند. در مثال زیر، InnerComponent رویدادهای کلیدی را هنگام رها شدن کلید S مصرف می‌کند، بنابراین OuterComponent هیچ رویداد کلیدی‌ای را که با رها شدن کلید S راه‌اندازی شده باشد دریافت نمی‌کند. به‌همین دلیل است که تابع actionB() هرگز فراخوانی نمی‌شود.

رویدادهای کلیدی دیگر در InnerComponent، مثل رها کردن کلید D، می‌تواند توسط OuterComponent مدیریت شود. تابع actionC() فراخوانده می‌شود زیرا رویداد کلیدی برای رها کردن کلید D به OuterComponent منتشر می‌شود.

OuterComponent(
    modifier = Modifier.onKeyEvent {
        when {
            it.type == KeyEventType.KeyUp && it.key == Key.S -> {
                actionB() // This function is never called.
                true
            }

            it.type == KeyEventType.KeyUp && it.key == Key.D -> {
                actionC()
                true
            }

            else -> false
        }
    }
) {
    InnerComponent(
        modifier = Modifier.onKeyEvent {
            if (it.type == KeyEventType.KeyUp && it.key == Key.S) {
                actionA()
                true
            } else {
                false
            }
        }
    )
}

اصلاح‌گر onKeyPreviewEvent

در برخی موارد استفاده، می‌خواهید رویداد کلید را قبل‌از اینکه کنش پیش‌فرض را راه‌اندازی کند رهگیری کنید. افزودن میان‌برهای سفارشی به TextField یکی از این موارد است. تکه‌کد زیر به کاربران امکان می‌دهد با فشار دادن کلید جدول به عنصر قابل‌تمرکز بعدی بروند.

val focusManager = LocalFocusManager.current
var textFieldValue by remember { mutableStateOf(TextFieldValue()) }

TextField(
    textFieldValue,
    onValueChange = {
        textFieldValue = it
    },
    modifier = Modifier.onPreviewKeyEvent {
        if (it.type == KeyEventType.KeyUp && it.key == Key.Tab) {
            focusManager.moveFocus(FocusDirection.Next)
            true
        } else {
            false
        }
    }
)

به‌طور پیش‌فرض، مؤلفه TextField هربار که کاربران کلید جهش را فشار می‌دهند، یک نویسه جهش اضافه می‌کند، حتی اگر رویداد کلید با اصلاح‌کننده onKeyEvent مدیریت شود. برای جابه‌جا کردن تمرکز صفحه‌کلید بدون افزودن نویسه‌های جهش، رویداد کلید را قبل‌از راه‌اندازی کنش‌های مرتبط با رویداد کلید، مانند قطعه کد، مدیریت کنید. ‫onKeyPreviewEvent() لامبدا با برگرداندن true رویداد کلیدی را رهگیری می‌کند.

مؤلفه والد می‌تواند رویداد کلیدی را که در فرزندانش اتفاق می‌افتد رهگیری کند. در قطعه کد زیر، وقتی کاربران کلید S را فشار می‌دهند، تابع previewSKey() فراخوانی می‌شود و تابع actionForPreview() فراخوانی نمی‌شود.

Column(
    modifier = Modifier.onPreviewKeyEvent {
        if (it.key == Key.S) {
            previewSKey()
            true
        } else {
            false
        }
    }
) {
    Box(
        modifier = Modifier
            .focusable()
            .onPreviewKeyEvent {
                actionForPreview(it)
                false
            }
            .onKeyEvent {
                actionForKeyEvent(it)
                true
            }
    ) {
        Text("Press any key")
    }
}

‫onPreviewKeyEvent() لامبدا برای عنصر Box وقتی کاربران کلید Tab را فشار می‌دهند نیز راه‌اندازی نمی‌شود. ابتدا onPreviewKeyEvent() لامبدا در مؤلفه والد فراخوانی می‌شود، سپس onPreviewKeyEvent() در مؤلفه فرزند فراخوانی می‌شود. بااستفاده از این رفتار می‌توانید میان‌برهای صفحه‌کلید سراسری را پیاده‌سازی کنید.

منابع بیشتر