是否可以在应用程序级别挂钩硬件键盘事件?

时间:2017-11-10 10:30:52

标签: c# ios xamarin xamarin.ios xamarin.forms

我正在为library(purrr) map_dfr(lst, ~as.data.frame(., stringsAsFactors=FALSE)) Xamarin.FormsiOS开发Android申请。

我想在应用程序级别(不是单个页面级别(因为它是一个Xamarin.Forms应用程序))挂钩硬件键盘事件,这样当用户按下键盘上的键时,我可以调用我的动作应用

在Android上,我使用UWP上的以下事件执行了此操作:。

MainActivity

public override bool OnKeyUp([GeneratedEnum] Keycode keyCode, KeyEvent e) { //process key press return base.OnKeyUp(keyCode, e); }

是否等效?

3 个答案:

答案 0 :(得分:3)

您可以使用KeyCommands跟踪从硬件键盘按下的键。

  

<强> keyCommands

     

支持硬件键盘命令的响应器对象可以重新定义此属性,并使用它返回它支持的UIKeyCommand对象数组。每个键命令对象表示要识别的键盘序列以及响应者响应时的操作方法。

     

从此方法返回的关键命令将应用于整个响应程序链。当按下与键命令对象匹配的组合键时,UIKit遍历响应者链,寻找实现相应操作方法的对象。它在找到的第一个对象上调用该方法,然后停止处理该事件。

在Xamarin.forms中,您必须在iOS平台上为 ContentPage 创建自定义渲染器。然后可以在该页面渲染器中添加键命令。

如果您希望按键可以由ViewController(Page)处理,而不仅仅是输入控件(如Entry),请使用lowest使viewcontroller成为第一响应者。

例如,iOS平台中ContentPage的自定义渲染器可能是这样的:

canBecomeFirstResponder

注意这一行,使用using System; using Foundation; using UIKit; using Xamarin.Forms; using Xamarin.Forms.Platform.iOS; using KeyCommandsInXamarinForms.iOS; [assembly: ExportRenderer(typeof(ContentPage), typeof(MyCustomPageRenderer))] namespace KeyCommandsInXamarinForms.iOS { public class MyCustomPageRenderer : PageRenderer { protected override void OnElementChanged(VisualElementChangedEventArgs e) { base.OnElementChanged(e); if (e.OldElement != null || Element == null) { return; } //Create your keycommand as you need. UIKeyCommand keyCommand1 = UIKeyCommand.Create(new NSString("1"), UIKeyModifierFlags.Command, new ObjCRuntime.Selector("Action")); UIKeyCommand keyCommand2 = UIKeyCommand.Create(new NSString("\t"), 0, new ObjCRuntime.Selector("Action")); //Add your keycommands this.AddKeyCommand(keyCommand1); this.AddKeyCommand(keyCommand2); } [Export("Action:")] private void Excute(UIKeyCommand keyCommand) { Console.WriteLine(String.Format("key pressed - {0}", keyCommand.Value); } //Enable viewcontroller to become the first responder, so it is able to respond to the key commands. public override bool CanBecomeFirstResponder { get { return true; } } } } 作为处理程序参数,然后您不需要更改PCL中的任何内容:

typeof(ContentPage)

答案 1 :(得分:1)

iOS的问题是它没有这样的方法。 首先,您需要了解要捕获的按钮。如果你想捕捉音量按钮,那么你可以在这里找到答案: https://forums.xamarin.com/discussion/29648/detect-volume-change-from-hardware-buttons

public override void ViewDidLoad ()
    {
        base.ViewDidLoad ();

        //KVO for outputVolume
        var session = AVAudioSession.SharedInstance();
        var errorOrNull = session.SetActive (true);
        if (errorOrNull != null) {
            //TODO: ...handle it
        }
        session.AddObserver (this, "outputVolume", NSKeyValueObservingOptions.New, IntPtr.Zero);


    }

    public override void ObserveValue (NSString keyPath, NSObject ofObject, NSDictionary change, IntPtr context)
    {
                   //TODO: Filter as appropriate, error-handling, etc.
        var volume = (float) (change ["new"] as NSNumber);

        volumeLabel.Text = volume.ToString();
    }

如果要捕获键盘事件,则必须订阅负责输入过程的视图。

您可以使用NotificationCenter订阅可在一个位置处理输入和接收通知的所有视图。

NSNotificationCenter.DefaultCenter.AddObserver (UITextField.TextFieldTextDidChangeNotification, (notification) =>
{
    Console.WriteLine ("Character received! {0}", notification.Object == TextField);
});

答案 2 :(得分:1)

我需要在我的XamForms应用程序中允许数字输入+输入。这是我在Xamarin Forms 3.0.0.482510 / Xamarin.iOS 11.10中解决它的方式(它与Kevin上面的答案略有不同,因为我想在XamForms共享xaml项目中处理它,而不是在iOS项目中):

在您的iOS项目中(例如,在名为&#39; MobileProject&#39;的解决方案中使用Xamarin Forms共享项目),创建一个新类:

using Foundation;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(MobileProject.MainPage), typeof (com.YourCompany.iOS.KeyboardHookRenderer))]
namespace com.YourCompany.iOS
{
public class KeyboardHookRenderer : PageRenderer
{
    private string _RecvValue = string.Empty;

    public override bool CanBecomeFirstResponder
    {
        get { return true; }
    }

    protected override void OnElementChanged(VisualElementChangedEventArgs e)
    {
        base.OnElementChanged(e);
        string key = string.Empty;
        var selector = new ObjCRuntime.Selector("KeyRecv:");
        UIKeyCommand accelerator1 = UIKeyCommand.Create((NSString)"1", 0, selector);
        AddKeyCommand(accelerator1);
        UIKeyCommand accelerator2 = UIKeyCommand.Create((NSString)"2", 0, selector);
        AddKeyCommand(accelerator2);
        UIKeyCommand accelerator3 = UIKeyCommand.Create((NSString)"3", 0, selector);
        AddKeyCommand(accelerator3);

        ... etc as many as you need or use a loop based on key id...
    }

    [Export("KeyRecv:")]
    public void KeyRecv(UIKeyCommand cmd)
    {
        if (cmd == null)
            return;
        var inputValue = cmd.Input;
        if (inputValue == "\n" || inputValue == "\r")
        {
            ((MobileProject.MainPage) Element)?.HandleHardwareKeyboard(_RecvValue);
            _RecvValue = string.Empty;
        }
        else
        {
            _RecvValue += inputValue;
        }
    }
}
}

然后,在MainPage.xaml.cs中的共享应用程序中,您只需要:

/// <summary>
/// Handle hardware keys (from KeyboardHookRender.cs in iOS project)
/// </summary>
/// <param name="keys">Keys sent, including trailing Cr or Lf</param>
public void HandleHardwareKeyboard(string keys)
{
    SomeTextbox.Text = keys;
    // Whatever else you need to do to handle it
}