PosKeyboard 實作 (POS for .NET v1.14 SDK 文件)
PosKeyboard 服務物件會從 POS 鍵盤讀取按鍵。 POS 鍵盤可能是輔助鍵盤,也可能是由系統鍵盤上部分或所有按鍵組成的虛擬鍵盤。 在 Microsoft Point of Service for .NET (POS for .NET) 中,POS 鍵盤基底類別為 PosKeyboardBase。
PosKeyboard 服務物件遵循一般輸入裝置模型:
- 從 POS 鍵盤接收輸入時,DataEvent 會排入佇列。
- 如果 AutoDisable 屬性為 true,則當 DataEvent 事件排入佇列時,裝置會自動停用本身。 這會自動透過 PosKeyboardBase 類別完成。
- 當 DataEventEnabled 屬性為 true,且符合其他事件傳遞需求時,排入佇列的 DataEvent 事件將會傳遞至應用程式。 PosKeyboardBase 類別會自動管理事件傳遞。
- 當收集或處理輸入時,若發生錯誤,ErrorEvent 事件會排入佇列,當 DataEventEnabled 為 true,且符合其他事件傳遞需求時,該事件則會傳遞至應用程式。
- 可以讀取由 PosKeyboardBase 類別維護的 DataCount 屬性,以取得已排入佇列的事件數目。
- 呼叫 ClearInput() 即可刪除所有已排入佇列的輸入。
POS 鍵盤是專用裝置:
- 應用程式必須宣告裝置,然後才能將其啟用。
- 應用程式必須宣告並啟用裝置,然後該裝置才能開始讀取輸入。
本節包含範例 PosKeyboard 服務物件,該物件會產生使用 DataEvents 傳送至應用程式的模擬按鍵。 這個範例取決於服務物件讀取器執行緒簡介中呈現的執行緒協助程式物件。 若要編譯此範例,您需要包含來自該主題的程式碼。
撰寫服務物件
為 Microsoft.PointofService、Microsoft.PointOfService.BaseServiceObjects 和 System.Threading 新增 using 指示詞。
新增全域屬性 PosAssembly。
為您的專案選擇適當的命名空間名稱。
建立衍生自 PosKeyboardBase 的服務物件類別。
使用 DeviceType.PosKeyboard 值作為裝置類型,將 ServiceObject 屬性新增至服務物件類別。
將功能新增至鍵盤服務物件範例
建立執行緒協助程式類別 KeyboardThreadingObject,其衍生自服務物件讀取執行緒一節中的 ServiceObjectThreadHelper。
在 KeyboardThreadingObject 類別中實作 ServiceObjectThreadProcedure 方法。 這是將在個別執行緒上執行的程序。 在下列範例程式碼中,此方法會模擬鍵盤輸入。
這個範例類別會實作稱為 SendKey 的方法,以及另一個稱為 ChangePowerState 的方法。 這些方法是包裝受保護成員的包裝函式。 因為這些成員受到保護,所以無法直接從執行緒物件叫用這些成員。
覆寫 PosCommon.Open 方法,以指定此服務物件所支援的功能,並建立新的執行緒協助程式物件。
特別覆寫 PosCommon.DeviceEnable 以開啟和關閉執行緒協助程式。
從 PosCommon 實作抽象虛擬方法,這會提供最低功能。
執行應用程式
此範例服務物件可以結合 POS for .NET 軟體開發套件 (SDK) 隨附的測試應用程式執行。
測試服務物件
啟動測試應用程式,然後從 [鍵盤] 下拉式清單中選取 [SamplePosKeyboard]。
開啟並宣告裝置,然後選取該裝置搭配 [DeviceEnabled] 核取方塊以將其啟用。
核取 [DataEventEnabled] 方塊可讓服務物件將單一模擬按鍵傳送至應用程式。 呼叫 KeyDown 時,PosKeyboardBase 類別會自動將 DataEvent 排入佇列。
選取 [自動啟用資料事件] 方塊可讓服務物件繼續傳遞字元,相隔兩秒。
服務物件會傳送 'a' 到 'z' 字元的模擬按鍵。 之後,將會傳送 StatusUpdateEvent 事件,指出裝置現在已離線。 當 Properties.PowerState 變更時,PosKeyboardBase 類別會自動傳送此事件。
範例
此範例示範如何開發簡單的 PosKeyboard 服務物件。 其支援個別的讀取器執行緒,以非同步方式將 DataEvents 傳送至應用程式。 編譯後,您可以結合 POS for .NET SDK 隨附的測試應用程式執行服務物件。
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using Microsoft.PointOfService;
using Microsoft.PointOfService.BaseServiceObjects;
[assembly: PosAssembly("Service Object Contractors, Inc.")]
namespace SOSamples.Keyboard
{
[ServiceObject(
DeviceType.PosKeyboard,
"SamplePosKeyboard",
"Sample PosKeyboard Service Object",
1,
9)]
public class SampleKeyboard : PosKeyboardBase
{
KeyboardThreadingObject ReadThread = null;
public SampleKeyboard()
{
// DevicePath must be set before Open() is called.
// In the case of Play and Plug hardware, the
// POS for .NET Base class will set this value.
DevicePath = "Sample Keyboard";
// NOTE: You can test the power notification events
// sent from this Service Object by selecting the
// "Power Notify" check box.
// Let the application know advanced power
// reporting is supported.
Properties.CapPowerReporting = PowerReporting.Advanced;
Properties.CapKeyUp = false;
}
~SampleKeyboard()
{
// Code added from previous sections to terminate
// the read thread started by the thread-helper
// object.
if (ReadThread != null)
{
ReadThread.CloseThread();
}
Dispose(false);
}
// Expose the protected KeyDown() method so that it can be
// called from our threading helper.
public void SendKey(int key)
{
KeyDown(key);
}
// Expose the protected PowerState property so it can be
// changed from the threading helper.
public void ChangePowerState(PowerState state)
{
Properties.PowerState = state;
}
#region Override Virtual PosCommon Members
public override void Open()
{
base.Open();
// Create the reader-thread object.
ReadThread = new KeyboardThreadingObject(this);
}
public override bool DeviceEnabled
{
get
{
return base.DeviceEnabled;
}
set
{
if (value != base.DeviceEnabled)
{
base.DeviceEnabled = value;
if (value == false)
{
// Stop the reader thread when the device
// is disabled.
ReadThread.CloseThread();
}
else
{
try
{
// By enabling the device, start the
// reader thread.
ReadThread.OpenThread();
}
catch (Exception e)
{
base.DeviceEnabled = false;
if (e is PosControlException)
throw;
throw new PosControlException(
"Unable to Enable Device",
ErrorCode.Failure, e);
}
}
}
}
}
#endregion Override Virtual PosCommon Members
#region Implement Abstract PosCommon Members
private string MyHealthText = "";
// PosCommon.CheckHealthText.
public override string CheckHealthText
{
get
{
// VerifyState(mustBeClaimed,
// mustBeEnabled).
VerifyState(false, false);
return MyHealthText;
}
}
// PosCommon.CheckHealth.
public override string CheckHealth(
HealthCheckLevel level)
{
// Verify that device is open, claimed and enabled.
VerifyState(true, true);
// Your code here:
// Check the health of the device and return a
// descriptive string.
// Cache result in the CheckHealthText property.
MyHealthText = "Ok";
return MyHealthText;
}
// PosCommon.DirectIOData.
public override DirectIOData DirectIO(
int command,
int data,
object obj)
{
// Verify that the device is open.
VerifyState(false, false);
return new DirectIOData(data, obj);
}
#endregion Implement Abstract PosCommon Members
}
#region Thread Helper Class
public class KeyboardThreadingObject :
ServiceObjectThreadHelper, IDisposable
{
// This is a helper class which will depend on
// being able to call back into the actual Service
// Object to pass along data. However, you cannot
// keep a strong reference to the Service Object,
// since that may prevent clean disposal, leaving
// hardware resources unavailable to other processes.
// Therefore, you create a weak reference. From this
// reference, you can get a temporary strong reference,
// which you can act on and then release.
WeakReference ServiceObjectReference;
// The name of the Service Object.
string ObjectName;
public KeyboardThreadingObject(SampleKeyboard so)
{
ObjectName = GetType().Name;
ServiceObjectReference = new WeakReference(so);
}
// This method will be called during initialization.
public override void ServiceObjectThreadOpen()
{
Logger.Info(ObjectName, "Keyboard Thread Open");
}
// This method will be called curing shutdown.
public override void ServiceObjectThreadClose()
{
Logger.Info(ObjectName, "Keyboard Thread Open");
}
// Your code used to monitor your device for input should
// go here. The implementation below generates simulated
// input as an example.
public override void ServiceObjectThreadProcedure(
AutoResetEvent ThreadStopEvent)
{
Logger.Info(ObjectName,
"Keyboard Thread Procedure Entered");
int KeyValue = (int)'a';
while (true)
{
// When this method is called by the
// ServiceObjectThreadHelper, it is obligated to
// exit when the event ThreadStopEvent has been
// set.
if (ThreadStopEvent.WaitOne(2000, false))
{
break;
}
if (KeyValue <= (int) 'z')
{
Logger.Info(ObjectName, "Reader Thread cycling");
// Try to get a strong reference to the Service
// Object using the weak reference saved when
// this helper object was created.
SampleKeyboard Keyboard =
ServiceObjectReference.Target
as SampleKeyboard;
// If this fails, that means the Service Object
// has already been disposed of - exit the thread.
if (Keyboard == null)
{
break;
}
if (Keyboard.DataEventEnabled == true)
{
// Call a method implemented in our Keyboard
// class to queue the key stroke.
Keyboard.SendKey(KeyValue);
// Simulate input by moving through the
// alphabet, sending one character at a time.
KeyValue++;
if (KeyValue >= (int)'z')
{
// Once you run out of input, simulate a
// power state change. Setting the SO's
// PowerState property to
// PowerState.Offline will cause a
// StatusUpdateEvent to be sent to the
// application.
Keyboard.ChangePowerState(
PowerState.Offline);
// Release the strong reference.
Keyboard = null;
// There is no more work, so exit the
// loop.
break;
}
}
// Release the strong reference.
Keyboard = null;
}
}
}
}
#endregion Thread Helper Class
}
編譯程式碼
- 此範例需要包含來自服務物件讀取器執行緒簡介一節的程式碼。
- 必須參考組件 Microsoft.PointOfService 和 Microsoft.PointOfService.BaseServiceObjects。