development

iPad Web App : Safari에서 JavaScript를 사용하여 가상 키보드 감지?

big-blog 2020. 6. 20. 09:32
반응형

iPad Web App : Safari에서 JavaScript를 사용하여 가상 키보드 감지?


iPad 용 웹 앱을 작성하고 있습니다 ( 일반 App Store 앱이 아니라 HTML, CSS 및 JavaScript를 사용하여 작성되었습니다). 키보드가 화면의 많은 부분을 차지하므로 키보드가 표시 될 때 남은 공간에 맞게 앱의 레이아웃을 변경하는 것이 좋습니다. 그러나 키보드가 표시되는지 여부를 감지하는 방법을 찾지 못했습니다.

첫 번째 아이디어는 텍스트 필드에 포커스가있을 때 키보드가 표시되는 것으로 가정했습니다. 그러나 외부 키보드가 iPad에 연결되어 있으면 텍스트 필드에 포커스가있을 때 가상 키보드가 표시되지 않습니다.

내 실험에서 키보드는 DOM 요소의 높이 또는 스크롤 높이에 영향을 미치지 않았으며 키보드가 표시되는지 여부를 나타내는 독점 이벤트 또는 속성을 찾지 못했습니다.


조금 추악하지만 작동하는 솔루션을 찾았습니다. 모든 상황에서 작동하지는 않지만 나에게 효과적입니다. 사용자 인터페이스의 크기를 iPad의 창 크기에 맞추기 때문에 사용자는 일반적으로 스크롤 할 수 없습니다. 즉, 창의 scrollTop을 설정하면 0으로 유지됩니다.

반면에 키보드가 표시되면 스크롤이 갑자기 작동하는 것입니다. 그래서 scrollTop을 설정하고 즉시 값을 테스트 한 다음 재설정 할 수 있습니다. 다음은 jQuery를 사용하여 코드에서 어떻게 보일 수 있는지 보여줍니다.

$(document).ready(function(){
    $('input').bind('focus',function() {
        $(window).scrollTop(10);
        var keyboard_shown = $(window).scrollTop() > 0;
        $(window).scrollTop(0);

        $('#test').append(keyboard_shown?'keyboard ':'nokeyboard ');
    });
});

일반적으로이 정보는 사용자에게 보이지 않을 것으로 예상됩니다. 불행히도, 적어도 시뮬레이터에서 실행할 때 iPad는 눈에 띄게 (빠르지 만) 위아래로 스크롤됩니다. 그러나 적어도 특정 상황에서는 작동합니다.

나는 이것을 iPad에서 테스트했는데 잘 작동하는 것 같습니다.


포커스 아웃 이벤트를 사용하여 키보드 해제를 감지 할 수 있습니다 . 흐릿하지만 거품처럼 보입니다. 키보드가 닫히면 시작됩니다 (물론 다른 경우에도). Safari 및 Chrome에서 이벤트는 레거시 메소드가 아닌 addEventListener로만 등록 할 수 있습니다. 다음은 키보드 해제 후 Phonegap 앱을 복원하는 데 사용한 예입니다.

 document.addEventListener('focusout', function(e) {window.scrollTo(0, 0)});

이 스 니펫이 없으면 앱 컨테이너는 페이지를 새로 고칠 때까지 위로 스크롤 된 위치에있었습니다.


어쩌면 약간 더 나은 해결책은 다양한 입력 필드에서 "blur"이벤트를 바인딩하는 것입니다 (제 경우에는 jQuery 사용).

키보드가 사라지면 모든 양식 필드가 흐리게 표시되기 때문입니다. 그래서 내 상황 에서이 문제는 해결되었습니다.

$('input, textarea').bind('blur', function(e) {

       // Keyboard disappeared
       window.scrollTo(0, 1);

});

도움이되기를 바랍니다. 미셸


온 스크린 키보드가있는 경우, 뷰포트 하단 근처에있는 텍스트 필드에 초점을 맞추면 Safari가 텍스트 필드를보기로 스크롤합니다. 이 현상을 악용하여 키보드의 존재를 감지하는 방법이있을 수 있습니다 (페이지 하단에 작은 텍스트 필드가있어 순간적으로 초점을 얻거나 이와 유사한 것).


포커스 이벤트 중에 문서 높이를 지나서 마술처럼 창을 스크롤 할 수 있습니다. 가상 높이는 innerHeight만큼 줄어 듭니다. 가상 키보드의 크기는 가로 방향과 세로 방향에 따라 다르므로 변경시 다시 감지해야합니다. 사용자가 언제든지 블루투스 키보드를 연결 / 연결 해제 할 수 있으므로 이러한 값을 기억하지 않는 것이 좋습니다.

var element = document.getElementById("element"); // the input field
var focused = false;

var virtualKeyboardHeight = function () {
    var sx = document.body.scrollLeft, sy = document.body.scrollTop;
    var naturalHeight = window.innerHeight;
    window.scrollTo(sx, document.body.scrollHeight);
    var keyboardHeight = naturalHeight - window.innerHeight;
    window.scrollTo(sx, sy);
    return keyboardHeight;
};

element.onfocus = function () {
    focused = true;
    setTimeout(function() { 
        element.value = "keyboardHeight = " + virtualKeyboardHeight() 
    }, 1); // to allow for orientation scrolling
};

window.onresize = function () {
    if (focused) {
        element.value = "keyboardHeight = " + virtualKeyboardHeight();
    }
};

element.onblur = function () {
    focused = false;
};

사용자가 블루투스 키보드를 사용하는 경우 keyboardHeight는 44이고 [이전] [다음] 도구 모음의 높이입니다.

이 탐지를 할 때 약간의 깜박임이 있지만 피할 수는 없습니다.


편집 : 실제로 작동하지는 않지만 Apple에서 문서화 : 키보드 표시를 통한 WKWebView 동작 : "iOS 10에서 WKWebView 객체는 키보드가 표시되고 호출되지 않는 경우 window.innerHeight 속성을 업데이트하여 Safari의 기본 동작과 일치합니다. 이벤트 크기 조정 "(아마도 크기 조정 대신 초점 또는 초점 + 지연을 사용하여 키보드 감지)

편집 : 코드는 외부 키보드가 아닌 화면 키보드를 가정합니다. 정보는 온 스크린 키보드에만 관심이있는 다른 사람들에게 유용 할 수 있으므로 그대로 두십시오. 페이지 매개 변수를 보려면 http://jsbin.com/AbimiQup/4사용하십시오 .

document.activeElement키보드가 입력 요소 인지 확인합니다 (입력 유형 = 텍스트, 텍스트 영역 등).

다음 코드는 우리의 목적을 위해 퍼지합니다 (일반적으로 정확하지는 않지만).

function getViewport() {
    if (window.visualViewport && /Android/.test(navigator.userAgent)) {
        // https://developers.google.com/web/updates/2017/09/visual-viewport-api    Note on desktop Chrome the viewport subtracts scrollbar widths so is not same as window.innerWidth/innerHeight
        return {
            left: visualViewport.pageLeft,
            top: visualViewport.pageTop,
            width: visualViewport.width,
            height: visualViewport.height
        };
    }
    var viewport = {
            left: window.pageXOffset,   // http://www.quirksmode.org/mobile/tableViewport.html
            top: window.pageYOffset,
            width: window.innerWidth || documentElement.clientWidth,
            height: window.innerHeight || documentElement.clientHeight
    };
    if (/iPod|iPhone|iPad/.test(navigator.platform) && isInput(document.activeElement)) {       // iOS *lies* about viewport size when keyboard is visible. See http://stackoverflow.com/questions/2593139/ipad-web-app-detect-virtual-keyboard-using-javascript-in-safari Input focus/blur can indicate, also scrollTop: 
        return {
            left: viewport.left,
            top: viewport.top,
            width: viewport.width,
            height: viewport.height * (viewport.height > viewport.width ? 0.66 : 0.45)  // Fudge factor to allow for keyboard on iPad
        };
    }
    return viewport;
}


function isInput(el) {
    var tagName = el && el.tagName && el.tagName.toLowerCase();
    return (tagName == 'input' && el.type != 'button' && el.type != 'radio' && el.type != 'checkbox') || (tagName == 'textarea');
};

The above code is only approximate: It is wrong for split keyboard, undocked keyboard, physical keyboard. As per comment at top, you may be able to do a better job than the given code on Safari (since iOS8?) or WKWebView (since iOS10) using window.innerHeight property.

I have found failures under other circumstances: e.g. give focus to input then go to home screen then come back to page; iPad shouldnt make viewport smaller; old IE browsers won't work, Opera didnt work because Opera kept focus on element after keyboard closed.

However the tagged answer (changing scrolltop to measure height) has nasty UI side effects if viewport zoomable (or force-zoom enabled in preferences). I don't use the other suggested solution (changing scrolltop) because on iOS, when viewport is zoomable and scrolling to focused input, there are buggy interactions between scrolling & zoom & focus (that can leave a just focused input outside of viewport - not visible).


Only tested on Android 4.1.1:

blur event is not a reliable event to test keyboard up and down because the user as the option to explicitly hide the keyboard which does not trigger a blur event on the field that caused the keyboard to show.

resize event however works like a charm if the keyboard comes up or down for any reason.

coffee:

$(window).bind "resize", (event) ->  alert "resize"

fires on anytime the keyboard is shown or hidden for any reason.

Note however on in the case of an android browser (rather than app) there is a retractable url bar which does not fire resize when it is retracted yet does change the available window size.


Instead of detecting the keyboard, try to detect the size of the window

If the height of the window was reduced, and the width is still the same, it means that the keyboard is on. Else the keyboard is off, you can also add to that, test if any input field is on focus or not.

Try this code for example.

var last_h = $(window).height(); //  store the intial height.
var last_w = $(window).width(); //  store the intial width.
var keyboard_is_on = false;
$(window).resize(function () {
    if ($("input").is(":focus")) {
        keyboard_is_on =
               ((last_w == $(window).width()) && (last_h > $(window).height()));
    }   
});     

This solution remembers the scroll position

    var currentscroll = 0;

    $('input').bind('focus',function() {
        currentscroll = $(window).scrollTop();
    });

    $('input').bind('blur',function() {
        if(currentscroll != $(window).scrollTop()){

        $(window).scrollTop(currentscroll);

        }
    });

Try this one:

var lastfoucsin;

$('.txtclassname').click(function(e)
{
  lastfoucsin=$(this);

//the virtual keyboard appears automatically

//Do your stuff;

});


//to check ipad virtual keyboard appearance. 
//First check last focus class and close the virtual keyboard.In second click it closes the wrapper & lable

$(".wrapperclass").click(function(e)
{

if(lastfoucsin.hasClass('txtclassname'))
{

lastfoucsin=$(this);//to avoid error

return;

}

//Do your stuff 
$(this).css('display','none');
});`enter code here`

As noted in the previous answers somewhere the window.innerHeight variable gets updated properly now on iOS10 when the keyboard appears and since I don't need the support for earlier versions I came up with the following hack that might be a bit easier then the discussed "solutions".

//keep track of the "expected" height
var windowExpectedSize = window.innerHeight;

//update expected height on orientation change
window.addEventListener('orientationchange', function(){
    //in case the virtual keyboard is open we close it first by removing focus from the input elements to get the proper "expected" size
    if (window.innerHeight != windowExpectedSize){
        $("input").blur();
        $("div[contentEditable]").blur();     //you might need to add more editables here or you can focus something else and blur it to be sure
        setTimeout(function(){
            windowExpectedSize = window.innerHeight;
        },100);
    }else{
        windowExpectedSize = window.innerHeight;
    }
});

//and update the "expected" height on screen resize - funny thing is that this is still not triggered on iOS when the keyboard appears
window.addEventListener('resize', function(){
    $("input").blur();  //as before you can add more blurs here or focus-blur something
    windowExpectedSize = window.innerHeight;
});

then you can use:

if (window.innerHeight != windowExpectedSize){ ... }

to check if the keyboard is visible. I've been using it for a while now in my web app and it works well, but (as all of the other solutions) you might find a situation where it fails because the "expected" size is not updated properly or something.


I did some searching, and I couldn't find anything concrete for a "on keyboard shown" or "on keyboard dismissed". See the official list of supported events. Also see Technical Note TN2262 for iPad. As you probably already know, there is a body event onorientationchange you can wire up to detect landscape/portrait.

Similarly, but a wild guess... have you tried detecting resize? Viewport changes may trigger that event indirectly from the keyboard being shown / hidden.

window.addEventListener('resize', function() { alert(window.innerHeight); });

Which would simply alert the new height on any resize event....


I haven't attempted this myself, so its just an idea... but have you tried using media queries with CSS to see when the height of the window changes and then change the design for that? I would imagine that Safari mobile isn't recognizing the keyboard as part of the window so that would hopefully work.

Example:

@media all and (height: 200px){
    #content {height: 100px; overflow: hidden;}
}

The problem is that, even in 2014, devices handle screen resize events, as well as scroll events, inconsistently while the soft keyboard is open.

I've found that, even if you're using a bluetooth keyboard, iOS in particular triggers some strange layout bugs; so instead of detecting a soft keyboard, I've just had to target devices that are very narrow and have touchscreens.

I use media queries (or window.matchMedia) for width detection and Modernizr for touch event detection.


Perhaps it's easier to have a checkbox in your app's settings where the user can toggle 'external keyboard attached?'.

In small print, explain to the user that external keyboards are currently not detectable in today's browsers.


Answering this for 2019.

On iOS 12, I am not seeing window.innerHeight changing depending whether the keyboard is displayed. This is consistent with the native WKWebView behavior that simply pushes part of the view offscreen rather than resizing it (which I believe is the Android behavior).

The only way I have been consistently successful has been to create a fixed position element and check its position. The element must be created some time before the position check; typically by creating it once on load and doing the check later.

var testElement = document.createElement('p');
testElement.style.position = 'fixed';

function isKeyboardVisible() {
  testElement.style.top = 0;
  return !!testElement.offsetTop;
}

setTimeout(function() {
  document.write(isKeyboardVisible() ?
    'Keyboard is visible' :
    'Keyboard is not visisble');
}, 1000);
<input type="text">


Well, you can detect when your input boxes have the focus, and you know the height of the keyboard. There is also CSS available to get the orientation of the screen, so I think you can hack it.

You would want to handle the case of a physical keyboard somehow, though.

참고URL : https://stackoverflow.com/questions/2593139/ipad-web-app-detect-virtual-keyboard-using-javascript-in-safari

반응형