raxon-barcode-scanner 0.1.2 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/RaxonBarcodeScannerModule.d.ts +2 -2
- package/build/RaxonBarcodeScannerModule.d.ts.map +1 -1
- package/build/RaxonBarcodeScannerModule.js.map +1 -1
- package/build/useBarcodeScanner.d.ts.map +1 -1
- package/build/useBarcodeScanner.js +8 -5
- package/build/useBarcodeScanner.js.map +1 -1
- package/ios/RaxonBarcodeScanner.podspec +2 -1
- package/ios/RaxonBarcodeScannerModule.swift +122 -254
- package/package.json +6 -2
- package/src/RaxonBarcodeScannerModule.ts +2 -2
- package/src/useBarcodeScanner.ts +9 -5
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { NativeModule } from 'expo';
|
|
2
2
|
import { BarcodeScannerOptions, RaxonBarcodeScannerModuleEvents } from './RaxonBarcodeScanner.types';
|
|
3
3
|
declare class RaxonBarcodeScannerModule extends NativeModule<RaxonBarcodeScannerModuleEvents> {
|
|
4
|
-
startListening(options
|
|
5
|
-
stopListening(): void
|
|
4
|
+
startListening(options: BarcodeScannerOptions): Promise<void>;
|
|
5
|
+
stopListening(): Promise<void>;
|
|
6
6
|
}
|
|
7
7
|
declare const _default: RaxonBarcodeScannerModule;
|
|
8
8
|
export default _default;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RaxonBarcodeScannerModule.d.ts","sourceRoot":"","sources":["../src/RaxonBarcodeScannerModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAuB,MAAM,MAAM,CAAC;AAEzD,OAAO,EACL,qBAAqB,EACrB,+BAA+B,EAChC,MAAM,6BAA6B,CAAC;AAErC,OAAO,OAAO,yBAA0B,SAAQ,YAAY,CAAC,+BAA+B,CAAC;IAC3F,cAAc,CAAC,OAAO,
|
|
1
|
+
{"version":3,"file":"RaxonBarcodeScannerModule.d.ts","sourceRoot":"","sources":["../src/RaxonBarcodeScannerModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAuB,MAAM,MAAM,CAAC;AAEzD,OAAO,EACL,qBAAqB,EACrB,+BAA+B,EAChC,MAAM,6BAA6B,CAAC;AAErC,OAAO,OAAO,yBAA0B,SAAQ,YAAY,CAAC,+BAA+B,CAAC;IAC3F,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAC7D,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;CAC/B;;AAED,wBAAqF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RaxonBarcodeScannerModule.js","sourceRoot":"","sources":["../src/RaxonBarcodeScannerModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAYzD,eAAe,mBAAmB,CAA4B,qBAAqB,CAAC,CAAC","sourcesContent":["import { NativeModule, requireNativeModule } from 'expo';\n\nimport {\n BarcodeScannerOptions,\n RaxonBarcodeScannerModuleEvents,\n} from './RaxonBarcodeScanner.types';\n\ndeclare class RaxonBarcodeScannerModule extends NativeModule<RaxonBarcodeScannerModuleEvents> {\n startListening(options
|
|
1
|
+
{"version":3,"file":"RaxonBarcodeScannerModule.js","sourceRoot":"","sources":["../src/RaxonBarcodeScannerModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAYzD,eAAe,mBAAmB,CAA4B,qBAAqB,CAAC,CAAC","sourcesContent":["import { NativeModule, requireNativeModule } from 'expo';\n\nimport {\n BarcodeScannerOptions,\n RaxonBarcodeScannerModuleEvents,\n} from './RaxonBarcodeScanner.types';\n\ndeclare class RaxonBarcodeScannerModule extends NativeModule<RaxonBarcodeScannerModuleEvents> {\n startListening(options: BarcodeScannerOptions): Promise<void>;\n stopListening(): Promise<void>;\n}\n\nexport default requireNativeModule<RaxonBarcodeScannerModule>('RaxonBarcodeScanner');\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBarcodeScanner.d.ts","sourceRoot":"","sources":["../src/useBarcodeScanner.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,uBAAuB,EACxB,MAAM,6BAA6B,CAAC;AAGrC,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,OAAO,EAChB,aAAa,EAAE,CAAC,OAAO,EAAE,kBAAkB,KAAK,IAAI,EACpD,OAAO,CAAC,EAAE,qBAAqB,GAC9B,uBAAuB,
|
|
1
|
+
{"version":3,"file":"useBarcodeScanner.d.ts","sourceRoot":"","sources":["../src/useBarcodeScanner.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,uBAAuB,EACxB,MAAM,6BAA6B,CAAC;AAGrC,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,OAAO,EAChB,aAAa,EAAE,CAAC,OAAO,EAAE,kBAAkB,KAAK,IAAI,EACpD,OAAO,CAAC,EAAE,qBAAqB,GAC9B,uBAAuB,CAmCzB"}
|
|
@@ -9,12 +9,15 @@ export function useBarcodeScanner(enabled, onReadBarcode, options) {
|
|
|
9
9
|
if (!enabled) {
|
|
10
10
|
return;
|
|
11
11
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
let subscription = null;
|
|
13
|
+
(async () => {
|
|
14
|
+
await RaxonBarcodeScanner.startListening(options ?? {});
|
|
15
|
+
subscription = RaxonBarcodeScanner.addListener('onBarcodeScanned', (event) => {
|
|
16
|
+
onReadBarcodeRef.current(event);
|
|
17
|
+
});
|
|
18
|
+
})();
|
|
16
19
|
return () => {
|
|
17
|
-
subscription
|
|
20
|
+
subscription?.remove();
|
|
18
21
|
RaxonBarcodeScanner.stopListening();
|
|
19
22
|
};
|
|
20
23
|
}, [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBarcodeScanner.js","sourceRoot":"","sources":["../src/useBarcodeScanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAO1C,OAAO,mBAAmB,MAAM,6BAA6B,CAAC;AAE9D,MAAM,UAAU,iBAAiB,CAC/B,OAAgB,EAChB,aAAoD,EACpD,OAA+B;IAE/B,MAAM,gBAAgB,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC;IAE/C,SAAS,CAAC,GAAG,EAAE;QACb,gBAAgB,CAAC,OAAO,GAAG,aAAa,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO;QACT,CAAC;QAED,mBAAmB,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"useBarcodeScanner.js","sourceRoot":"","sources":["../src/useBarcodeScanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAO1C,OAAO,mBAAmB,MAAM,6BAA6B,CAAC;AAE9D,MAAM,UAAU,iBAAiB,CAC/B,OAAgB,EAChB,aAAoD,EACpD,OAA+B;IAE/B,MAAM,gBAAgB,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC;IAE/C,SAAS,CAAC,GAAG,EAAE;QACb,gBAAgB,CAAC,OAAO,GAAG,aAAa,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO;QACT,CAAC;QAED,IAAI,YAAY,GAAkC,IAAI,CAAC;QAEvD,CAAC,KAAK,IAAI,EAAE;YACV,MAAM,mBAAmB,CAAC,cAAc,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;YAExD,YAAY,GAAG,mBAAmB,CAAC,WAAW,CAAC,kBAAkB,EAAE,CAAC,KAAK,EAAE,EAAE;gBAC3E,gBAAgB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAClC,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,EAAE,CAAC;QAEL,OAAO,GAAG,EAAE;YACV,YAAY,EAAE,MAAM,EAAE,CAAC;YACvB,mBAAmB,CAAC,aAAa,EAAE,CAAC;QACtC,CAAC,CAAC;IACJ,CAAC,EAAE;QACD,OAAO;QACP,OAAO,EAAE,YAAY;QACrB,OAAO,EAAE,WAAW;QACpB,OAAO,EAAE,kBAAkB;QAC3B,OAAO,EAAE,eAAe;KACzB,CAAC,CAAC;IAEH,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC;AAClC,CAAC","sourcesContent":["import { useEffect, useRef } from 'react';\n\nimport {\n BarcodeScanPayload,\n BarcodeScannerOptions,\n UseBarcodeScannerResult,\n} from './RaxonBarcodeScanner.types';\nimport RaxonBarcodeScanner from './RaxonBarcodeScannerModule';\n\nexport function useBarcodeScanner(\n enabled: boolean,\n onReadBarcode: (payload: BarcodeScanPayload) => void,\n options?: BarcodeScannerOptions\n): UseBarcodeScannerResult {\n const onReadBarcodeRef = useRef(onReadBarcode);\n\n useEffect(() => {\n onReadBarcodeRef.current = onReadBarcode;\n });\n\n useEffect(() => {\n if (!enabled) {\n return;\n }\n\n let subscription: { remove: () => void } | null = null;\n\n (async () => {\n await RaxonBarcodeScanner.startListening(options ?? {});\n\n subscription = RaxonBarcodeScanner.addListener('onBarcodeScanned', (event) => {\n onReadBarcodeRef.current(event);\n });\n })();\n\n return () => {\n subscription?.remove();\n RaxonBarcodeScanner.stopListening();\n };\n }, [\n enabled,\n options?.intentAction,\n options?.profileName,\n options?.configureDataWedge,\n options?.captureKeyboard,\n ]);\n\n return { isListening: enabled };\n}\n"]}
|
|
@@ -10,10 +10,11 @@ Pod::Spec.new do |s|
|
|
|
10
10
|
s.license = package['license']
|
|
11
11
|
s.author = package['author']
|
|
12
12
|
s.homepage = package['homepage']
|
|
13
|
-
s.platform = :ios, '
|
|
13
|
+
s.platform = :ios, '15.1'
|
|
14
14
|
s.swift_version = '5.4'
|
|
15
15
|
s.source = { git: 'https://github.com/raxonltd/raxon-barcode-scanner.git' }
|
|
16
16
|
s.static_framework = true
|
|
17
|
+
s.frameworks = 'GameController'
|
|
17
18
|
|
|
18
19
|
s.dependency 'ExpoModulesCore'
|
|
19
20
|
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import ExpoModulesCore
|
|
2
|
+
import GameController
|
|
2
3
|
import UIKit
|
|
3
4
|
|
|
4
5
|
// MARK: - RaxonBarcodeScannerModule
|
|
5
6
|
|
|
6
7
|
/// iOS için Bluetooth ve HID barkod okuyucu desteği sağlayan Expo modülü.
|
|
7
|
-
///
|
|
8
|
+
/// GameController framework'ün GCKeyboard API'si ile donanım klavyesi tuşlarını
|
|
9
|
+
/// responder chain'den bağımsız olarak, sistem seviyesinde yakalar.
|
|
8
10
|
public final class RaxonBarcodeScannerModule: Module {
|
|
9
11
|
private var isListening = false
|
|
10
|
-
private var
|
|
11
|
-
private var keyboardHandler: ExternalKeyboardHandler?
|
|
12
|
+
private var keyboardMonitor: HardwareKeyboardMonitor?
|
|
12
13
|
|
|
13
14
|
public required init(appContext: AppContext) {
|
|
14
15
|
super.init(appContext: appContext)
|
|
@@ -19,12 +20,16 @@ public final class RaxonBarcodeScannerModule: Module {
|
|
|
19
20
|
|
|
20
21
|
Events("onBarcodeScanned")
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
AsyncFunction("startListening") { (options: [String: Any]?) in
|
|
24
|
+
await MainActor.run {
|
|
25
|
+
self.startListening(options: options)
|
|
26
|
+
}
|
|
24
27
|
}
|
|
25
28
|
|
|
26
|
-
|
|
27
|
-
|
|
29
|
+
AsyncFunction("stopListening") {
|
|
30
|
+
await MainActor.run {
|
|
31
|
+
self.stopListening()
|
|
32
|
+
}
|
|
28
33
|
}
|
|
29
34
|
|
|
30
35
|
OnDestroy {
|
|
@@ -33,296 +38,159 @@ public final class RaxonBarcodeScannerModule: Module {
|
|
|
33
38
|
}
|
|
34
39
|
|
|
35
40
|
private func startListening(options: [String: Any]?) {
|
|
36
|
-
guard !isListening else {
|
|
37
|
-
stopListening()
|
|
38
|
-
}
|
|
41
|
+
guard !isListening else { return }
|
|
39
42
|
|
|
40
|
-
captureKeyboard = options?["captureKeyboard"] as? Bool ?? true
|
|
43
|
+
let captureKeyboard = options?["captureKeyboard"] as? Bool ?? true
|
|
41
44
|
|
|
42
45
|
if captureKeyboard {
|
|
43
|
-
|
|
46
|
+
let monitor = HardwareKeyboardMonitor()
|
|
47
|
+
monitor.onBarcodeScanned = { [weak self] code in
|
|
48
|
+
self?.sendEvent("onBarcodeScanned", ["code": code])
|
|
49
|
+
}
|
|
50
|
+
monitor.start()
|
|
51
|
+
keyboardMonitor = monitor
|
|
44
52
|
}
|
|
45
53
|
|
|
46
54
|
isListening = true
|
|
47
55
|
}
|
|
48
56
|
|
|
49
57
|
private func stopListening() {
|
|
50
|
-
|
|
58
|
+
keyboardMonitor?.stop()
|
|
59
|
+
keyboardMonitor = nil
|
|
51
60
|
isListening = false
|
|
52
61
|
}
|
|
53
|
-
|
|
54
|
-
private func setupKeyboardCapture() {
|
|
55
|
-
guard let viewController = appContext?.currentViewController else {
|
|
56
|
-
return
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if #available(iOS 13.4, *) {
|
|
60
|
-
keyboardHandler = ExternalKeyboardHandler(
|
|
61
|
-
viewController: viewController,
|
|
62
|
-
onBarcodeScanned: { [weak self] code in
|
|
63
|
-
self?.sendEvent("onBarcodeScanned", ["code": code])
|
|
64
|
-
}
|
|
65
|
-
)
|
|
66
|
-
keyboardHandler?.startListening()
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
private func teardownKeyboardCapture() {
|
|
71
|
-
keyboardHandler?.stopListening()
|
|
72
|
-
keyboardHandler = nil
|
|
73
|
-
}
|
|
74
62
|
}
|
|
75
63
|
|
|
76
|
-
// MARK: -
|
|
64
|
+
// MARK: - HardwareKeyboardMonitor
|
|
77
65
|
|
|
78
|
-
///
|
|
79
|
-
///
|
|
80
|
-
|
|
81
|
-
private final class
|
|
82
|
-
|
|
83
|
-
private let onBarcodeScanned: (String) -> Void
|
|
84
|
-
private var keyBuffer: String = ""
|
|
85
|
-
private var lastKeyTime: TimeInterval = 0
|
|
86
|
-
private let bufferTimeout: TimeInterval = 1.0
|
|
87
|
-
|
|
88
|
-
// Terminatör tuş kodları
|
|
89
|
-
private let terminatorKeyCodes: Set<Int> = [
|
|
90
|
-
36, // Return/Enter
|
|
91
|
-
76, // Numpad Enter
|
|
92
|
-
48, // Tab
|
|
93
|
-
52, // Numpad Equal (bazı okuyucularda)
|
|
94
|
-
67, // Numpad Asterisk (bazı okuyucularda)
|
|
95
|
-
]
|
|
66
|
+
/// GCKeyboard ile donanım klavyesi (Bluetooth barkod okuyucu) girişini izler.
|
|
67
|
+
/// Responder chain'e bağımlı olmadığı için tuş kaybı yaşanmaz ve
|
|
68
|
+
/// ekrandaki input'lar ile etkileşime girmez.
|
|
69
|
+
private final class HardwareKeyboardMonitor {
|
|
70
|
+
var onBarcodeScanned: ((String) -> Void)?
|
|
96
71
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
72
|
+
private var keyBuffer = ""
|
|
73
|
+
private var lastKeyTime: TimeInterval = 0
|
|
74
|
+
// Tuşlar arası bu süre aşılırsa tampon sıfırlanır (insan yazısını barkoddan ayırır)
|
|
75
|
+
private let bufferTimeout: TimeInterval = 0.5
|
|
76
|
+
private var connectObserver: NSObjectProtocol?
|
|
77
|
+
private var attachedInputs: [ObjectIdentifier: GCKeyboardInput] = [:]
|
|
101
78
|
|
|
102
|
-
func
|
|
103
|
-
//
|
|
104
|
-
|
|
79
|
+
func start() {
|
|
80
|
+
// Halihazırda bağlı klavye varsa hemen dinlemeye başla
|
|
81
|
+
attach(to: GCKeyboard.coalesced)
|
|
105
82
|
|
|
106
|
-
//
|
|
107
|
-
|
|
83
|
+
// Sonradan bağlanan klavyeler (örn. Bluetooth okuyucu) için bildirim dinle
|
|
84
|
+
connectObserver = NotificationCenter.default.addObserver(
|
|
85
|
+
forName: .GCKeyboardDidConnect,
|
|
86
|
+
object: nil,
|
|
87
|
+
queue: .main
|
|
88
|
+
) { [weak self] notification in
|
|
89
|
+
self?.attach(to: notification.object as? GCKeyboard)
|
|
90
|
+
}
|
|
108
91
|
}
|
|
109
92
|
|
|
110
|
-
func
|
|
111
|
-
|
|
93
|
+
func stop() {
|
|
94
|
+
if let connectObserver {
|
|
95
|
+
NotificationCenter.default.removeObserver(connectObserver)
|
|
96
|
+
}
|
|
97
|
+
connectObserver = nil
|
|
98
|
+
|
|
99
|
+
for (_, input) in attachedInputs {
|
|
100
|
+
input.keyChangedHandler = nil
|
|
101
|
+
}
|
|
102
|
+
attachedInputs.removeAll()
|
|
112
103
|
keyBuffer = ""
|
|
113
104
|
}
|
|
114
105
|
|
|
115
|
-
private func
|
|
116
|
-
|
|
117
|
-
// Ancak tüm tuşları yakalamak için pressesBegan/pressesEnded daha iyi
|
|
118
|
-
}
|
|
106
|
+
private func attach(to keyboard: GCKeyboard?) {
|
|
107
|
+
guard let input = keyboard?.keyboardInput else { return }
|
|
119
108
|
|
|
120
|
-
|
|
109
|
+
let id = ObjectIdentifier(input)
|
|
110
|
+
guard attachedInputs[id] == nil else { return }
|
|
111
|
+
attachedInputs[id] = input
|
|
121
112
|
|
|
122
|
-
|
|
123
|
-
|
|
113
|
+
input.keyChangedHandler = { [weak self] keyboardInput, _, keyCode, pressed in
|
|
114
|
+
guard pressed else { return }
|
|
115
|
+
self?.handleKey(keyCode, input: keyboardInput)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
124
118
|
|
|
125
|
-
|
|
119
|
+
private func handleKey(_ keyCode: GCKeyCode, input: GCKeyboardInput) {
|
|
126
120
|
let now = Date().timeIntervalSince1970
|
|
127
|
-
|
|
128
|
-
// Zaman aşımı kontrolü - tuşlar arası 1 saniyeden fazla varsa tamponu sıfırla
|
|
129
121
|
if now - lastKeyTime > bufferTimeout {
|
|
130
122
|
keyBuffer = ""
|
|
131
123
|
}
|
|
132
124
|
lastKeyTime = now
|
|
133
125
|
|
|
134
|
-
// Terminatör
|
|
135
|
-
if
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
onBarcodeScanned
|
|
140
|
-
|
|
126
|
+
// Terminatör: Enter / Numpad Enter / Tab
|
|
127
|
+
if keyCode == .returnOrEnter || keyCode == .keypadEnter || keyCode == .tab {
|
|
128
|
+
let code = keyBuffer
|
|
129
|
+
keyBuffer = ""
|
|
130
|
+
if !code.isEmpty {
|
|
131
|
+
let callback = onBarcodeScanned
|
|
132
|
+
DispatchQueue.main.async {
|
|
133
|
+
callback?(code)
|
|
134
|
+
}
|
|
141
135
|
}
|
|
142
|
-
|
|
143
|
-
return false
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Karakter tuşu mu?
|
|
147
|
-
if let char = characterFromKey(key) {
|
|
148
|
-
keyBuffer.append(char)
|
|
149
|
-
return true // Tuşu yut (UI'ya ulaşmasını engelle)
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
return false
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
private func isTerminator(_ keyCode: Int) -> Bool {
|
|
156
|
-
return terminatorKeyCodes.contains(keyCode)
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
private func characterFromKey(_ key: UIKey) -> Character? {
|
|
160
|
-
// Karakter önceliği:
|
|
161
|
-
// 1. modifiersiz karakter (temel ASCII)
|
|
162
|
-
// 2. modifiers varsa ve shift varsa büyük harf
|
|
163
|
-
|
|
164
|
-
var char: Character?
|
|
165
|
-
|
|
166
|
-
// UIKey.characters ile dene
|
|
167
|
-
if let chars = key.characters, !chars.isEmpty {
|
|
168
|
-
char = chars.first
|
|
136
|
+
return
|
|
169
137
|
}
|
|
170
138
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}
|
|
139
|
+
let shiftPressed =
|
|
140
|
+
input.button(forKeyCode: .leftShift)?.isPressed == true ||
|
|
141
|
+
input.button(forKeyCode: .rightShift)?.isPressed == true
|
|
175
142
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
char = characterFromKeyCode(key.keyCode.rawValue)
|
|
143
|
+
if let char = Self.character(for: keyCode, shifted: shiftPressed) {
|
|
144
|
+
keyBuffer.append(char)
|
|
179
145
|
}
|
|
180
|
-
|
|
181
|
-
return char
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
private func characterFromKeyCode(_ keyCode: Int) -> Character? {
|
|
185
|
-
// iOS fiziksel klavye key kodlarından karakter dönüşümü
|
|
186
|
-
// Bluetooth barkod okuyucular genellikle standart USB HID key kodları kullanır
|
|
187
|
-
let mapping: [Int: Character] = [
|
|
188
|
-
// Rakamlar (ana klavye)
|
|
189
|
-
23: "0", 22: "1", 26: "2", 20: "3", 25: "4",
|
|
190
|
-
29: "5", 27: "6", 24: "7", 28: "8", 21: "9",
|
|
191
|
-
|
|
192
|
-
// Numpad rakamlar
|
|
193
|
-
98: "0", 89: "1", 90: "2", 91: "3", 92: "4",
|
|
194
|
-
93: "5", 94: "6", 95: "7", 96: "8", 97: "9",
|
|
195
|
-
|
|
196
|
-
// Harfler (ana klavye)
|
|
197
|
-
12: "q", 13: "w", 14: "e", 15: "r", 17: "t",
|
|
198
|
-
16: "y", 32: "u", 34: "i", 31: "o", 35: "p",
|
|
199
|
-
0: "a", 1: "s", 2: "d", 3: "f", 5: "g",
|
|
200
|
-
4: "h", 38: "k", 37: "j", 40: "l", 6: "z",
|
|
201
|
-
7: "x", 8: "c", 9: "v", 11: "b", 45: "n",
|
|
202
|
-
46: "m",
|
|
203
|
-
|
|
204
|
-
// Özel karakterler
|
|
205
|
-
51: "\u{0008}", // Backspace (silme)
|
|
206
|
-
117: "\u{007F}", // Delete
|
|
207
|
-
42: ",", 43: "-", 44: ".", 47: "/",
|
|
208
|
-
39: "'", 33: "[", 30: "]", 41: ";", 50: "`",
|
|
209
|
-
115: "\u{001B}", // Escape
|
|
210
|
-
|
|
211
|
-
// Boşluk
|
|
212
|
-
49: " ",
|
|
213
|
-
]
|
|
214
|
-
|
|
215
|
-
return mapping[keyCode]
|
|
216
146
|
}
|
|
217
147
|
|
|
218
|
-
// MARK: -
|
|
219
|
-
|
|
220
|
-
private func swizzlePressesMethods() {
|
|
221
|
-
guard let viewController = viewController else { return }
|
|
222
|
-
|
|
223
|
-
let originalPressesBeganSelector = #selector(UIViewController.pressesBegan(_:with:))
|
|
224
|
-
let swizzledPressesBeganSelector = #selector(UIViewController.raxon_pressesBegan(_:with:))
|
|
225
|
-
|
|
226
|
-
let originalPressesEndedSelector = #selector(UIViewController.pressesEnded(_:with:))
|
|
227
|
-
let swizzledPressesEndedSelector = #selector(UIViewController.raxon_pressesEnded(_:with:))
|
|
228
|
-
|
|
229
|
-
swizzleMethod(
|
|
230
|
-
for: UIViewController.self,
|
|
231
|
-
originalSelector: originalPressesBeganSelector,
|
|
232
|
-
swizzledSelector: swizzledPressesBeganSelector
|
|
233
|
-
)
|
|
234
|
-
|
|
235
|
-
swizzleMethod(
|
|
236
|
-
for: UIViewController.self,
|
|
237
|
-
originalSelector: originalPressesEndedSelector,
|
|
238
|
-
swizzledSelector: swizzledPressesEndedSelector
|
|
239
|
-
)
|
|
240
|
-
|
|
241
|
-
// Bu view controller'a weak referans ile handler'a erişim sağla
|
|
242
|
-
objc_setAssociatedObject(
|
|
243
|
-
viewController,
|
|
244
|
-
&AssociatedKeys.keyboardHandler,
|
|
245
|
-
self,
|
|
246
|
-
.OBJC_ASSOCIATION_RETAIN_NONATOMIC
|
|
247
|
-
)
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
private func unswizzlePressesMethods() {
|
|
251
|
-
// Method swizzling geri alınamaz ama handler'ı temizleyebiliriz
|
|
252
|
-
if let viewController = viewController {
|
|
253
|
-
objc_setAssociatedObject(
|
|
254
|
-
viewController,
|
|
255
|
-
&AssociatedKeys.keyboardHandler,
|
|
256
|
-
nil,
|
|
257
|
-
.OBJC_ASSOCIATION_RETAIN_NONATOMIC
|
|
258
|
-
)
|
|
259
|
-
}
|
|
260
|
-
}
|
|
148
|
+
// MARK: - GCKeyCode → Karakter eşleştirmesi
|
|
261
149
|
|
|
262
|
-
private func
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
swizzledSelector: Selector
|
|
266
|
-
) {
|
|
267
|
-
guard let originalMethod = class_getInstanceMethod(classType, originalSelector),
|
|
268
|
-
let swizzledMethod = class_getInstanceMethod(classType, swizzledSelector) else {
|
|
269
|
-
return
|
|
150
|
+
private static func character(for keyCode: GCKeyCode, shifted: Bool) -> Character? {
|
|
151
|
+
if let letter = letters[keyCode] {
|
|
152
|
+
return shifted ? Character(letter.uppercased()) : letter
|
|
270
153
|
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
classType,
|
|
274
|
-
originalSelector,
|
|
275
|
-
method_getImplementation(swizzledMethod),
|
|
276
|
-
method_getTypeEncoding(swizzledMethod)
|
|
277
|
-
)
|
|
278
|
-
|
|
279
|
-
if didAddMethod {
|
|
280
|
-
class_replaceMethod(
|
|
281
|
-
classType,
|
|
282
|
-
swizzledSelector,
|
|
283
|
-
method_getImplementation(originalMethod),
|
|
284
|
-
method_getTypeEncoding(originalMethod)
|
|
285
|
-
)
|
|
286
|
-
} else {
|
|
287
|
-
method_exchangeImplementations(originalMethod, swizzledMethod)
|
|
154
|
+
if let pair = symbols[keyCode] {
|
|
155
|
+
return shifted ? pair.shifted : pair.normal
|
|
288
156
|
}
|
|
157
|
+
return keypad[keyCode]
|
|
289
158
|
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
// MARK: - AssociatedKeys
|
|
293
159
|
|
|
294
|
-
private
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
@objc dynamic func raxon_pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
|
|
303
|
-
// Orijinal implementasyonu çağır (swizzling yüzünden bu aslında orijinal)
|
|
304
|
-
raxon_pressesBegan(presses, with: event)
|
|
160
|
+
private static let letters: [GCKeyCode: Character] = [
|
|
161
|
+
.keyA: "a", .keyB: "b", .keyC: "c", .keyD: "d", .keyE: "e",
|
|
162
|
+
.keyF: "f", .keyG: "g", .keyH: "h", .keyI: "i", .keyJ: "j",
|
|
163
|
+
.keyK: "k", .keyL: "l", .keyM: "m", .keyN: "n", .keyO: "o",
|
|
164
|
+
.keyP: "p", .keyQ: "q", .keyR: "r", .keyS: "s", .keyT: "t",
|
|
165
|
+
.keyU: "u", .keyV: "v", .keyW: "w", .keyX: "x", .keyY: "y",
|
|
166
|
+
.keyZ: "z",
|
|
167
|
+
]
|
|
305
168
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
169
|
+
private static let symbols: [GCKeyCode: (normal: Character, shifted: Character)] = [
|
|
170
|
+
.one: ("1", "!"), .two: ("2", "@"), .three: ("3", "#"),
|
|
171
|
+
.four: ("4", "$"), .five: ("5", "%"), .six: ("6", "^"),
|
|
172
|
+
.seven: ("7", "&"), .eight: ("8", "*"), .nine: ("9", "("),
|
|
173
|
+
.zero: ("0", ")"),
|
|
174
|
+
.spacebar: (" ", " "),
|
|
175
|
+
.hyphen: ("-", "_"),
|
|
176
|
+
.equalSign: ("=", "+"),
|
|
177
|
+
.openBracket: ("[", "{"),
|
|
178
|
+
.closeBracket: ("]", "}"),
|
|
179
|
+
.backslash: ("\\", "|"),
|
|
180
|
+
.semicolon: (";", ":"),
|
|
181
|
+
.quote: ("'", "\""),
|
|
182
|
+
.graveAccentAndTilde: ("`", "~"),
|
|
183
|
+
.comma: (",", "<"),
|
|
184
|
+
.period: (".", ">"),
|
|
185
|
+
.slash: ("/", "?"),
|
|
186
|
+
]
|
|
314
187
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
188
|
+
private static let keypad: [GCKeyCode: Character] = [
|
|
189
|
+
.keypad0: "0", .keypad1: "1", .keypad2: "2", .keypad3: "3",
|
|
190
|
+
.keypad4: "4", .keypad5: "5", .keypad6: "6", .keypad7: "7",
|
|
191
|
+
.keypad8: "8", .keypad9: "9",
|
|
192
|
+
.keypadSlash: "/", .keypadAsterisk: "*",
|
|
193
|
+
.keypadHyphen: "-", .keypadPlus: "+",
|
|
194
|
+
.keypadPeriod: ".", .keypadEqualSign: "=",
|
|
195
|
+
]
|
|
319
196
|
}
|
|
320
|
-
|
|
321
|
-
// MARK: - UIKey Extensions
|
|
322
|
-
|
|
323
|
-
@available(iOS 13.4, *)
|
|
324
|
-
extension UIKey {
|
|
325
|
-
var keyCode: UIKeyboardHIDUsage {
|
|
326
|
-
return self.keyCode
|
|
327
|
-
}
|
|
328
|
-
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "raxon-barcode-scanner",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Zebra and enterprise barcode scanner hook for React Native Expo apps",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -46,7 +46,11 @@
|
|
|
46
46
|
"expo-module.config.json",
|
|
47
47
|
"src"
|
|
48
48
|
],
|
|
49
|
-
"dependencies": {
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"expo": "~56.0.0-preview.9",
|
|
51
|
+
"react": "19.2.3",
|
|
52
|
+
"react-native": "0.85.3"
|
|
53
|
+
},
|
|
50
54
|
"devDependencies": {
|
|
51
55
|
"@babel/core": "^7.26.0",
|
|
52
56
|
"@types/jest": "^29.2.1",
|
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
} from './RaxonBarcodeScanner.types';
|
|
7
7
|
|
|
8
8
|
declare class RaxonBarcodeScannerModule extends NativeModule<RaxonBarcodeScannerModuleEvents> {
|
|
9
|
-
startListening(options
|
|
10
|
-
stopListening(): void
|
|
9
|
+
startListening(options: BarcodeScannerOptions): Promise<void>;
|
|
10
|
+
stopListening(): Promise<void>;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export default requireNativeModule<RaxonBarcodeScannerModule>('RaxonBarcodeScanner');
|
package/src/useBarcodeScanner.ts
CHANGED
|
@@ -23,14 +23,18 @@ export function useBarcodeScanner(
|
|
|
23
23
|
return;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
let subscription: { remove: () => void } | null = null;
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
(async () => {
|
|
29
|
+
await RaxonBarcodeScanner.startListening(options ?? {});
|
|
30
|
+
|
|
31
|
+
subscription = RaxonBarcodeScanner.addListener('onBarcodeScanned', (event) => {
|
|
32
|
+
onReadBarcodeRef.current(event);
|
|
33
|
+
});
|
|
34
|
+
})();
|
|
31
35
|
|
|
32
36
|
return () => {
|
|
33
|
-
subscription
|
|
37
|
+
subscription?.remove();
|
|
34
38
|
RaxonBarcodeScanner.stopListening();
|
|
35
39
|
};
|
|
36
40
|
}, [
|