显示键盘 android (cordova)

Posted

技术标签:

【中文标题】显示键盘 android (cordova)【英文标题】:show keyboard android (cordova) 【发布时间】:2020-10-27 12:10:08 【问题描述】:

大家好,我想在我的应用程序中集成这个简单的打字游戏,但是键盘不会在 android 中自动显示,如果我添加一个输入字段,那么脚本就不起作用,有什么想法吗? (注意:我没有使用 jquery)

loadGame();
polyfillKey(); 


function loadGame() 
  var button = document.createElement('button');
  button.textContent = 'Start Game';
  var main = document.getElementById('main');
  main.appendChild(button);
  var rules = document.createElement('p');
  rules.textContent = 'Letters will fall... if you have a keyboard, press the correct key to knock it away before it hits the ground';
  main.appendChild(rules);
  button.addEventListener('click', function startIt(e) 
    main.textContent = '';
    playGame();
  );


function playGame(replay) 
  var LETTERS = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'];
  var animations = 'a':[],'b':[],'c':[],'d':[],'e':[],'f':[],'g':[],'h':[],'i':[],'j':[],'k':[],'l':[],'m':[],'n':[],'o':[],'p':[],'q':[],'r':[],'s':[],'t':[],'u':[],'v':[],'w':[],'x':[],'y':[],'z':[];
  var gameOn = true;
  var timeOffset = 2000; //interval between letters starting, will be faster over time
  var DURATION = 10000;
  var main = document.getElementById('main');
  var header = document.querySelector('header');
  var scoreElement = document.getElementById('score');
  var score = parseFloat(scoreElement.textContent);
  var rate = 1;
  var RATE_INTERVAL = .05; //playbackRate will increase by .05 for each letter... so after 20 letters, the rate of falling will be 2x what it was at the start
  var misses = 0;

  //Create a letter element and setup its falling animation, add the animation to the active animation array, and setup an onfinish handler that will represent a miss. 
  function create() 
    var idx = Math.floor(Math.random() * LETTERS.length);
    var x = (Math.random() * 85) + 'vw';
    var container = document.createElement('div');
    var letter = document.createElement('span');
    var letterText = document.createElement('b');
    letterText.textContent = LETTERS[idx];
    letter.appendChild(letterText);
    container.appendChild(letter);
    main.appendChild(container);
    var animation = container.animate([
      transform: 'translate3d('+x+',-2.5vh,0)',
      transform: 'translate3d('+x+',82.5vh,0)'
    ], 
      duration: DURATION,
      easing: 'linear',
      fill: 'both'
    );
    
    animations[LETTERS[idx]].splice(0, 0, animation: animation, element: container);
    rate = rate + RATE_INTERVAL;
    animation.playbackRate = rate;
    
    //If an animation finishes, we will consider that as a miss, so we will remove it from the active animations array and increment our miss count
    animation.onfinish = function(e) 
      var target = container;
      var char = target.textContent;
                                      
      animations[char].pop();
      target.classList.add('missed');
      handleMisses();
    
  
  
  //When a miss is registered, check if we have reached the max number of misses
  function handleMisses() 
    misses++;
    var missedMarker = document.querySelector('.misses:not(.missed)');
    if (missedMarker) 
      missedMarker.classList.add('missed');
     else 
      gameOver();
    
  
  
  //End game and show screen
  function gameOver() 
    gameOn = false;
    clearInterval(cleanupInterval);
    getAllAnimations().forEach(function(anim) 
      anim.pause();
    );

    //Could use Web Animations API here, but showing how you can use a mix of Web Animations API and CSS transistions
    document.getElementById('game-over').classList.add('indeed');
  

  //Periodically remove missed elements, and lower the interval between falling elements
  var cleanupInterval = setInterval(function() 
    timeOffset = timeOffset * 4 / 5;
    cleanup();
  , 20000);
  function cleanup() 
    [].slice.call(main.querySelectorAll('.missed')).forEach(function(missed) 
      main.removeChild(missed);
    );
  
  
  //Firefox 48 supports document.getAnimations as per latest spec, Chrome 52 and polyfill use older spec
  function getAllAnimations() 
    if (document.getAnimations) 
      return document.getAnimations();
     else if (document.timeline && document.timeline.getAnimations) 
      return document.timeline.getAnimations();
    
    return [];
  
  
  //On key press, see if it matches an active animating (falling) letter. If so, pop it from active array, pause it (to keep it from triggering "finish" logic), and add an animation on inner element with random 3d rotations that look like the letter is being kicked away to the distance. Also update score.
  function onPress(e) 
    var char = e.key;
    if (char.length === 1) 
      char = char.toLowerCase();
      if (animations[char] && animations[char].length) 
        var popped = animations[char].pop();
        popped.animation.pause();
        var target = popped.element.querySelector('b');
        var degs = [(Math.random() * 1000)-500,(Math.random() * 1000)-500,(Math.random() * 2000)-1000];
        target.animate([
          transform: 'scale(1) rotateX(0deg) rotateY(0deg) rotateZ(0deg)',opacity:1,
          transform: 'scale(0) rotateX('+degs[0]+'deg) rotateY('+degs[1]+'deg) rotateZ('+degs[2]+'deg)', opacity: 0
        ], 
          duration: Math.random() * 500 + 850,
          easing: 'ease-out',
          fill: 'both'
        );
        addScore();
        header.textContent += char;
      
    
  
  function addScore() 
    score++;
    scoreElement.textContent = score;
  
  
  document.body.addEventListener('keypress', onPress);

  //start the letters falling... create the element+animation, and setup timeout for next letter to start
  function setupNextLetter() 
    if (gameOn) 
      create();
      setTimeout(function() 
        setupNextLetter();
      , timeOffset);
    
  
  setupNextLetter();


function polyfillKey() 
  if (!('KeyboardEvent' in window) ||
        'key' in KeyboardEvent.prototype) 
    return false;
  
  
  console.log('polyfilling KeyboardEvent.prototype.key')
  var keys = ;
  var letter = '';
  for (var i = 65; i < 91; ++i) 
    letter = String.fromCharCode(i);
    keys[i] = letter.toUpperCase();
  
  for (var i = 97; i < 123; ++i) 
    letter = String.fromCharCode(i);
    keys[i] = letter.toLowerCase();
  
  var proto = 
    get: function (x) 
      var key = keys[this.which || this.keyCode];
      console.log(key);
      return key;
    
  ;
  Object.defineProperty(KeyboardEvent.prototype, 'key', proto);
$light: #eee;
$dark: #252627;
$bar: #aa6657;

body 
  height: 100vh;
  background: $dark;
  overflow: hidden;
  display: flex;
  align-items: stretch;
  flex-direction: column;
  color: $light;
  font-family: -apple-system, 'Segoe UI', 'Roboto', 'Helvetica Neue', sans-serif;
  font-family: monospace;
  font-size: 5vh;
  position: relative;

main 
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  
  p 
    font-size: 1rem;
    text-align: center;
    margin-top: 5vh;
    padding: 0 2rem;
    max-width: 30rem;
    line-height: 1.4;
  

header,
footer 
  height: 5vh;
  line-height: 5vh;
  font-size: 3vh;
  background: $bar;
  text-align: right;
  text-transform: uppercase;
  padding: 0 2.5vh;

footer 
  display: flex;
  justify-content: space-between;
  ul 
    display: flex;
    flex-direction: row-reverse;
    
    .misses 
      padding: .5vh;
      transition: all .225s ease-out;
      &.missed 
        opacity: .4;
        transform: rotate(-45deg);
      
    
  


main > div 
  position: absolute;
  top: 5vh;
  left: 0;
  text-transform: uppercase;
  perspective: 300px;
  transition: opacity .7s ease-in;
  font-size: 5vh;
  
  &.popped 
    opacity: 0;
    > span 
      b 
        opacity: 0;
      
      animation-play-state: paused;
    
  
  &.missed 
    opacity: 0;
    > span 
      //  transform: scaleY(0);
      animation-play-state: paused;
    
  
  
  > span 
    position: absolute;
    display: block;
    animation: waver 2s infinite alternate ease-in-out;
    perspective: 300px;
    b 
      display: block;
      padding: 2.5vh;
      transition: opacity .25s linear;
    
  


@keyframes waver 
  100% 
    transform: translate3d(6vw, 0, 0);
  



#game-over 
  opacity: 0;
  pointer-events: none;
  transition: opacity .75s ease-out;
  background: rgba(0,0,0,.75);
  
  position: absolute;
  top: 5vh;
  right: 0;
  bottom: 5vh;
  left: 0;
  width: 100%;
  
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  
  text-transform: uppercase;
  
  &.indeed 
    opacity: 1;
    pointer-events: auto;
  

button 
  appearance: none;
  border-radius: 0;
  border: .3rem solid $light;
  color: $light;
  font-size: 3vh;
  padding: 1.5vh 2vh;
  background: transparent;
  margin-top: 5vh;
  font-family: monospace;
  
  &:hover 
    border-color: $bar;
  
<header></header>
<main id="main"></main>
<footer>
  <ul>
    <li class="misses">+</li>
    <li class="misses">+</li>
    <li class="misses">+</li>
    <li class="misses">+</li>
    <li class="misses">+</li>
    <li class="misses">+</li>
  </ul>
  <div id="score">0</div>
</footer>
<div id="game-over">
  <p>Game Over</p>
</div>

请忽略这个(lorem ipsum text,Your question could not be submit.请看上面的错误。你的问题不能提交。请看上面的错误。你的问题不能提交。请看上面的错误。您的问题无法提交。请参阅上面的错误。您的问题无法提交。请参阅上面的错误。您的问题无法提交。请参阅上面的错误。您的问题无法提交提交。请看上面的错误。您的问题无法提交。请看上面的错误。)

【问题讨论】:

不幸的是,如果没有焦点输入字段,就无法在 Cordova 中显示键盘。 If I add an input field, the script doesn’t work...,您检查控制台是否有任何错误?脚本的哪一部分不工作,“不工作”是什么意思?根本没有执行或没有返回预期值? 那么如何正确编辑脚本呢? 不,没有错误,但是您必须编辑程序,捕捉输入字段中的内容并将其推送到“游戏”,我不是javascript专家 哦,好吧,即使这样,您的代码的问题是 Android webview 不发送关键代码(它总是 229 ????。更好的方法是使用输入字段。您可以将其设置为 0 宽度以将其从 UI 中隐藏并收听其按键,使用input.value 获取字母并立即将值设置为空以准备下一次输入... 你能演示一下吗 【参考方案1】:

loadGame();
polyfillKey();


function loadGame() 
  var button = document.createElement('button');
  button.textContent = 'Start Game';
  var main = document.getElementById('main');
  main.appendChild(button);
  var rules = document.createElement('p');
  rules.textContent = 'Letters will fall... if you have a keyboard, press the correct key to knock it away before it hits the ground';
  main.appendChild(rules);
  button.addEventListener('click', function startIt(e) 
    main.textContent = '';
    playGame();
  );


function getfocus() 
  document.getElementById("myAnchor").focus();


function losefocus() 
  document.getElementById("myAnchor").blur();


function playGame(replay) 
  var LETTERS = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
  var animations = 
    'a': [],
    'b': [],
    'c': [],
    'd': [],
    'e': [],
    'f': [],
    'g': [],
    'h': [],
    'i': [],
    'j': [],
    'k': [],
    'l': [],
    'm': [],
    'n': [],
    'o': [],
    'p': [],
    'q': [],
    'r': [],
    's': [],
    't': [],
    'u': [],
    'v': [],
    'w': [],
    'x': [],
    'y': [],
    'z': []
  ;
  var gameOn = true;
  var timeOffset = 2000; //interval between letters starting, will be faster over time
  var DURATION = 10000;
  var main = document.getElementById('main');
  var header = document.querySelector('header');
  var scoreElement = document.getElementById('score');
  var score = parseFloat(scoreElement.textContent);
  var rate = 1;
  var RATE_INTERVAL = .05; //playbackRate will increase by .05 for each letter... so after 20 letters, the rate of falling will be 2x what it was at the start
  var misses = 0;

  //Create a letter element and setup its falling animation, add the animation to the active animation array, and setup an onfinish handler that will represent a miss. 
  function create() 
    var idx = Math.floor(Math.random() * LETTERS.length);
    var x = (Math.random() * 85) + 'vw';
    var container = document.createElement('div');
    var letter = document.createElement('span');
    var letterText = document.createElement('b');
    letterText.textContent = LETTERS[idx];
    letter.appendChild(letterText);
    container.appendChild(letter);
    main.appendChild(container);
    var animation = container.animate([
        transform: 'translate3d(' + x + ',-2.5vh,0)'
      ,
      
        transform: 'translate3d(' + x + ',82.5vh,0)'
      
    ], 
      duration: DURATION,
      easing: 'linear',
      fill: 'both'
    );

    animations[LETTERS[idx]].splice(0, 0, 
      animation: animation,
      element: container
    );
    rate = rate + RATE_INTERVAL;
    animation.playbackRate = rate;

    //If an animation finishes, we will consider that as a miss, so we will remove it from the active animations array and increment our miss count
    animation.onfinish = function(e) 
      var target = container;
      var char = target.textContent;

      animations[char].pop();
      target.classList.add('missed');
      handleMisses();
    
  

  //When a miss is registered, check if we have reached the max number of misses
  function handleMisses() 
    misses++;
    var missedMarker = document.querySelector('.misses:not(.missed)');
    if (missedMarker) 
      missedMarker.classList.add('missed');
     else 
      gameOver();
    
  

  //End game and show screen
  function gameOver() 
    gameOn = false;
    clearInterval(cleanupInterval);
    getAllAnimations().forEach(function(anim) 
      anim.pause();
    );

    //Could use Web Animations API here, but showing how you can use a mix of Web Animations API and CSS transistions
    document.getElementById('game-over').classList.add('indeed');
  

  //Periodically remove missed elements, and lower the interval between falling elements
  var cleanupInterval = setInterval(function() 
    timeOffset = timeOffset * 4 / 5;
    cleanup();
  , 20000);

  function cleanup() 
    [].slice.call(main.querySelectorAll('.missed')).forEach(function(missed) 
      main.removeChild(missed);
    );
  

  //Firefox 48 supports document.getAnimations as per latest spec, Chrome 52 and polyfill use older spec
  function getAllAnimations() 
    if (document.getAnimations) 
      return document.getAnimations();
     else if (document.timeline && document.timeline.getAnimations) 
      return document.timeline.getAnimations();
    
    return [];
  

  //On key press, see if it matches an active animating (falling) letter. If so, pop it from active array, pause it (to keep it from triggering "finish" logic), and add an animation on inner element with random 3d rotations that look like the letter is being kicked away to the distance. Also update score.
  function onPress(e) 
    // var char = e.key;
    var char = this.value[this.value.length - 1];
    this.value = '';
    document.getElementById('myBox').innerText = char;

    if (char.length === 1) 
      char = char.toLowerCase();
      if (animations[char] && animations[char].length) 
        var popped = animations[char].pop();
        popped.animation.pause();
        var target = popped.element.querySelector('b');
        var degs = [(Math.random() * 1000) - 500, (Math.random() * 1000) - 500, (Math.random() * 2000) - 1000];
        target.animate([
            transform: 'scale(1) rotateX(0deg) rotateY(0deg) rotateZ(0deg)',
            opacity: 1
          ,
          
            transform: 'scale(0) rotateX(' + degs[0] + 'deg) rotateY(' + degs[1] + 'deg) rotateZ(' + degs[2] + 'deg)',
            opacity: 0
          
        ], 
          duration: Math.random() * 500 + 850,
          easing: 'ease-out',
          fill: 'both'
        );
        addScore();
        header.textContent += char;
      
    
  

  function addScore() 
    score++;
    scoreElement.textContent = score;
  

  // document.body.addEventListener('keypress', onPress);
  document.getElementById('myAnchor').addEventListener('keyup', onPress);

  //start the letters falling... create the element+animation, and setup timeout for next letter to start
  function setupNextLetter() 
    if (gameOn) 
      create();
      setTimeout(function() 
        setupNextLetter();
      , timeOffset);
    
  
  setupNextLetter();


function polyfillKey() 
  if (!('KeyboardEvent' in window) ||
    'key' in KeyboardEvent.prototype) 
    return false;
  

  console.log('polyfilling KeyboardEvent.prototype.key')
  var keys = ;
  var letter = '';
  for (var i = 65; i < 91; ++i) 
    letter = String.fromCharCode(i);
    keys[i] = letter.toUpperCase();
  
  for (var i = 97; i < 123; ++i) 
    letter = String.fromCharCode(i);
    keys[i] = letter.toLowerCase();
  
  var proto = 
    get: function(x) 
      var key = keys[this.which || this.keyCode];
      console.log(key);
      return key;
    
  ;
  Object.defineProperty(KeyboardEvent.prototype, 'key', proto);
$light: #eee;
$dark: #252627;
$bar: #aa6657;
body 
  height: 100vh;
  background: $dark;
  overflow: hidden;
  display: flex;
  align-items: stretch;
  flex-direction: column;
  color: $light;
  font-family: -apple-system, 'Segoe UI', 'Roboto', 'Helvetica Neue', sans-serif;
  font-family: monospace;
  font-size: 5vh;
  position: relative;


main 
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  p 
    font-size: 1rem;
    text-align: center;
    margin-top: 5vh;
    padding: 0 2rem;
    max-width: 30rem;
    line-height: 1.4;
  


header,
footer 
  height: 5vh;
  line-height: 5vh;
  font-size: 3vh;
  background: $bar;
  text-align: right;
  text-transform: uppercase;
  padding: 0 2.5vh;


footer 
  display: flex;
  justify-content: space-between;
  ul 
    display: flex;
    flex-direction: row-reverse;
    .misses 
      padding: .5vh;
      transition: all .225s ease-out;
      &.missed 
        opacity: .4;
        transform: rotate(-45deg);
      
    
  


main>div 
  position: absolute;
  top: 5vh;
  left: 0;
  text-transform: uppercase;
  perspective: 300px;
  transition: opacity .7s ease-in;
  font-size: 5vh;
  &.popped 
    opacity: 0;
    >span 
      b 
        opacity: 0;
      
      animation-play-state: paused;
    
  
  &.missed 
    opacity: 0;
    >span 
      //  transform: scaleY(0);
      animation-play-state: paused;
    
  
  >span 
    position: absolute;
    display: block;
    animation: waver 2s infinite alternate ease-in-out;
    perspective: 300px;
    b 
      display: block;
      padding: 2.5vh;
      transition: opacity .25s linear;
    
  


@keyframes waver 
  100% 
    transform: translate3d(6vw, 0, 0);
  


#game-over 
  opacity: 0;
  pointer-events: none;
  transition: opacity .75s ease-out;
  background: rgba(0, 0, 0, .75);
  position: absolute;
  top: 5vh;
  right: 0;
  bottom: 5vh;
  left: 0;
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  text-transform: uppercase;
  &.indeed 
    opacity: 1;
    pointer-events: auto;
  


button 
  appearance: none;
  border-radius: 0;
  border: .3rem solid $light;
  color: $light;
  font-size: 3vh;
  padding: 1.5vh 2vh;
  background: transparent;
  margin-top: 5vh;
  font-family: monospace;
  &:hover 
    border-color: $bar;
  
<header></header>
<div>
  <input id="myAnchor" style="">
  <span id="myBox"></span>
</div>
<input type="button" onclick="getfocus()" value="Get focus">
<input type="button" onclick="losefocus()" value="Lose focus">
<main id="main"></main>
<footer>
  <ul>
    <li class="misses">+</li>
    <li class="misses">+</li>
    <li class="misses">+</li>
    <li class="misses">+</li>
    <li class="misses">+</li>
    <li class="misses">+</li>
  </ul>
  <div id="score">0</div>
</footer>
<div id="game-over">
  <p>Game Over</p>
</div>

有几种方法可以解决这个问题: 您可以添加此插件https://github.com/driftyco/ionic-plugin-keyboard,并在需要时将其方法调用到键盘show。虽然在很多情况下它不能按预期工作,但它可能非常适合您自己的需要。

但是由于上述方法依赖于本机键盘,我相信这会减少游戏运行的可用空间(键盘至少占屏幕高度的 30%),您可以创建自己的虚拟键盘并分配它的关键代码。按键可以垂直排列在屏幕的两侧(每侧 13 个),这样您就可以完全控制屏幕、键盘的放置位置、何时​​隐藏以及何时显示。

如果您可以开源该项目,我可以帮助实施,因为我已经有一个虚拟键盘插件,用于在多个应用程序上输入验证令牌和 OTP。

编辑

进行了以下更改:

    //The styles were removed to be able to visualize what was going on behind
    <div>
        <input id="myAnchor" style="" >
        <span id="myBox"></span> <!-- box added to show the captured value -->
    </div>
    <input type="button" onclick="getfocus()" value="Get focus">
    <input type="button" onclick="losefocus()" value="Lose focus">

    function onPress(e) 
        // remove the next line
        // var char = e.key;
        // replace the above line with this
        var char = this.value[this.value.length - 1];
        // we have to apply this hack in order to get the last key pressed
        // Android would keep the initial values
        // until the space key or the return key is pressed
        // So, even if we clear the value programmatically, as we did below,
        // the OS would still keep it alive
        this.value = '';//this line could be omitted, but the input would be overloaded
        document.getElementById('myBox').innerText = char;

        if (char.length === 1) 
          char = char.toLowerCase();
          if (animations[char] && animations[char].length) 
            var popped = animations[char].pop();
            popped.animation.pause();
            var target = popped.element.querySelector('b');
            var degs = [(Math.random() * 1000)-500,(Math.random() * 1000)-500,(Math.random() * 2000)-1000];
            target.animate([
              transform: 'scale(1) rotateX(0deg) rotateY(0deg) rotateZ(0deg)',opacity:1,
              transform: 'scale(0) rotateX('+degs[0]+'deg) rotateY('+degs[1]+'deg) rotateZ('+degs[2]+'deg)', opacity: 0
            ], 
              duration: Math.random() * 500 + 850,
              easing: 'ease-out',
              fill: 'both'
            );
            addScore();
            header.textContent += char;
          
        
      

    // remove the line below    
    // document.body.addEventListener('keypress', onPress);
    // replace the above line with this one
    document.getElementById('myAnchor').addEventListener('keyup', onPress);

【讨论】:

我应该将它添加到 html 还是 javascript? sn-p 非常有帮助,在此先感谢 非常感谢,特别感谢您和我一起加倍努力,非常感谢 我想我现在尝试在开始按钮上添加焦点功能 快乐是我的。继续按照您喜欢的方式对其进行自定义。

以上是关于显示键盘 android (cordova)的主要内容,如果未能解决你的问题,请参考以下文章

在 Nexus Player、Android Cordova 应用程序上打开时输入第一个字符的虚拟键盘

Cordova iOs 在视图转换时在 SAPUI5 应用程序中无故显示键盘

Cordova Phonegap 表单输入框在 iOS 上不起作用

Ionic/Cordova:无法以编程方式触发 iOS 键盘

离子显示键盘问题 - 顶部的灰色条

iOS Cordova App 上的键盘响应缓慢