raxon-barcode-scanner 0.1.3 → 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 -266
- 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,308 +38,159 @@ public final class RaxonBarcodeScannerModule: Module {
|
|
|
33
38
|
}
|
|
34
39
|
|
|
35
40
|
private func startListening(options: [String: Any]?) {
|
|
36
|
-
|
|
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
|
-
// UIApplication'dan aktif view controller'ı al
|
|
56
|
-
guard let viewController = findActiveViewController() else {
|
|
57
|
-
return
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if #available(iOS 13.4, *) {
|
|
61
|
-
keyboardHandler = ExternalKeyboardHandler(
|
|
62
|
-
viewController: viewController,
|
|
63
|
-
onBarcodeScanned: { [weak self] code in
|
|
64
|
-
self?.sendEvent("onBarcodeScanned", ["code": code])
|
|
65
|
-
}
|
|
66
|
-
)
|
|
67
|
-
keyboardHandler?.startListening()
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
private func findActiveViewController() -> UIViewController? {
|
|
72
|
-
// UIApplication üzerinden root view controller'ı bul
|
|
73
|
-
guard let windowScene = UIApplication.shared.connectedScenes
|
|
74
|
-
.first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene,
|
|
75
|
-
let keyWindow = windowScene.windows.first(where: { $0.isKeyWindow }) else {
|
|
76
|
-
return nil
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
var topController = keyWindow.rootViewController
|
|
80
|
-
while let presentedController = topController?.presentedViewController {
|
|
81
|
-
topController = presentedController
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
return topController
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
private func teardownKeyboardCapture() {
|
|
88
|
-
keyboardHandler?.stopListening()
|
|
89
|
-
keyboardHandler = nil
|
|
90
|
-
}
|
|
91
62
|
}
|
|
92
63
|
|
|
93
|
-
// MARK: -
|
|
64
|
+
// MARK: - HardwareKeyboardMonitor
|
|
94
65
|
|
|
95
|
-
///
|
|
96
|
-
///
|
|
97
|
-
|
|
98
|
-
private final class
|
|
99
|
-
|
|
100
|
-
private let onBarcodeScanned: (String) -> Void
|
|
101
|
-
private var keyBuffer: String = ""
|
|
102
|
-
private var lastKeyTime: TimeInterval = 0
|
|
103
|
-
private let bufferTimeout: TimeInterval = 1.0
|
|
104
|
-
|
|
105
|
-
// Terminatör tuş kodları
|
|
106
|
-
private let terminatorKeyCodes: Set<Int> = [
|
|
107
|
-
36, // Return/Enter
|
|
108
|
-
76, // Numpad Enter
|
|
109
|
-
48, // Tab
|
|
110
|
-
52, // Numpad Equal (bazı okuyucularda)
|
|
111
|
-
67, // Numpad Asterisk (bazı okuyucularda)
|
|
112
|
-
]
|
|
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)?
|
|
113
71
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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] = [:]
|
|
118
78
|
|
|
119
|
-
func
|
|
120
|
-
//
|
|
121
|
-
|
|
79
|
+
func start() {
|
|
80
|
+
// Halihazırda bağlı klavye varsa hemen dinlemeye başla
|
|
81
|
+
attach(to: GCKeyboard.coalesced)
|
|
122
82
|
|
|
123
|
-
//
|
|
124
|
-
|
|
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
|
+
}
|
|
125
91
|
}
|
|
126
92
|
|
|
127
|
-
func
|
|
128
|
-
|
|
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()
|
|
129
103
|
keyBuffer = ""
|
|
130
104
|
}
|
|
131
105
|
|
|
132
|
-
private func
|
|
133
|
-
|
|
134
|
-
// Ancak tüm tuşları yakalamak için pressesBegan/pressesEnded daha iyi
|
|
135
|
-
}
|
|
106
|
+
private func attach(to keyboard: GCKeyboard?) {
|
|
107
|
+
guard let input = keyboard?.keyboardInput else { return }
|
|
136
108
|
|
|
137
|
-
|
|
109
|
+
let id = ObjectIdentifier(input)
|
|
110
|
+
guard attachedInputs[id] == nil else { return }
|
|
111
|
+
attachedInputs[id] = input
|
|
138
112
|
|
|
139
|
-
|
|
140
|
-
|
|
113
|
+
input.keyChangedHandler = { [weak self] keyboardInput, _, keyCode, pressed in
|
|
114
|
+
guard pressed else { return }
|
|
115
|
+
self?.handleKey(keyCode, input: keyboardInput)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
141
118
|
|
|
142
|
-
|
|
119
|
+
private func handleKey(_ keyCode: GCKeyCode, input: GCKeyboardInput) {
|
|
143
120
|
let now = Date().timeIntervalSince1970
|
|
144
|
-
|
|
145
|
-
// Zaman aşımı kontrolü - tuşlar arası 1 saniyeden fazla varsa tamponu sıfırla
|
|
146
121
|
if now - lastKeyTime > bufferTimeout {
|
|
147
122
|
keyBuffer = ""
|
|
148
123
|
}
|
|
149
124
|
lastKeyTime = now
|
|
150
125
|
|
|
151
|
-
// Terminatör
|
|
152
|
-
if
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
onBarcodeScanned
|
|
157
|
-
|
|
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
|
+
}
|
|
158
135
|
}
|
|
159
|
-
|
|
160
|
-
return false
|
|
136
|
+
return
|
|
161
137
|
}
|
|
162
138
|
|
|
163
|
-
|
|
164
|
-
|
|
139
|
+
let shiftPressed =
|
|
140
|
+
input.button(forKeyCode: .leftShift)?.isPressed == true ||
|
|
141
|
+
input.button(forKeyCode: .rightShift)?.isPressed == true
|
|
142
|
+
|
|
143
|
+
if let char = Self.character(for: keyCode, shifted: shiftPressed) {
|
|
165
144
|
keyBuffer.append(char)
|
|
166
|
-
return true // Tuşu yut (UI'ya ulaşmasını engelle)
|
|
167
145
|
}
|
|
168
|
-
|
|
169
|
-
return false
|
|
170
146
|
}
|
|
171
147
|
|
|
172
|
-
|
|
173
|
-
return terminatorKeyCodes.contains(keyCode)
|
|
174
|
-
}
|
|
148
|
+
// MARK: - GCKeyCode → Karakter eşleştirmesi
|
|
175
149
|
|
|
176
|
-
private func
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
// 2. modifiers varsa ve shift varsa büyük harf
|
|
180
|
-
|
|
181
|
-
var char: Character?
|
|
182
|
-
|
|
183
|
-
// UIKey.characters ile dene (String, Optional değil)
|
|
184
|
-
let chars = key.characters
|
|
185
|
-
if !chars.isEmpty {
|
|
186
|
-
char = chars.first
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// UIKey.charactersIgnoringModifiers ile dene (String, Optional değil)
|
|
190
|
-
if char == nil {
|
|
191
|
-
let charsIgnoringModifiers = key.charactersIgnoringModifiers
|
|
192
|
-
if !charsIgnoringModifiers.isEmpty {
|
|
193
|
-
char = charsIgnoringModifiers.first
|
|
194
|
-
}
|
|
150
|
+
private static func character(for keyCode: GCKeyCode, shifted: Bool) -> Character? {
|
|
151
|
+
if let letter = letters[keyCode] {
|
|
152
|
+
return shifted ? Character(letter.uppercased()) : letter
|
|
195
153
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
if char == nil {
|
|
199
|
-
char = characterFromKeyCode(key.keyCode.rawValue)
|
|
154
|
+
if let pair = symbols[keyCode] {
|
|
155
|
+
return shifted ? pair.shifted : pair.normal
|
|
200
156
|
}
|
|
201
|
-
|
|
202
|
-
return char
|
|
157
|
+
return keypad[keyCode]
|
|
203
158
|
}
|
|
204
159
|
|
|
205
|
-
private
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
// Numpad rakamlar
|
|
214
|
-
98: "0", 89: "1", 90: "2", 91: "3", 92: "4",
|
|
215
|
-
93: "5", 94: "6", 95: "7", 96: "8", 97: "9",
|
|
216
|
-
|
|
217
|
-
// Harfler (ana klavye)
|
|
218
|
-
12: "q", 13: "w", 14: "e", 15: "r", 17: "t",
|
|
219
|
-
16: "y", 32: "u", 34: "i", 31: "o", 35: "p",
|
|
220
|
-
0: "a", 1: "s", 2: "d", 3: "f", 5: "g",
|
|
221
|
-
4: "h", 38: "k", 37: "j", 40: "l", 6: "z",
|
|
222
|
-
7: "x", 8: "c", 9: "v", 11: "b", 45: "n",
|
|
223
|
-
46: "m",
|
|
224
|
-
|
|
225
|
-
// Özel karakterler
|
|
226
|
-
51: "\u{0008}", // Backspace (silme)
|
|
227
|
-
117: "\u{007F}", // Delete
|
|
228
|
-
42: ",", 43: "-", 44: ".", 47: "/",
|
|
229
|
-
39: "'", 33: "[", 30: "]", 41: ";", 50: "`",
|
|
230
|
-
115: "\u{001B}", // Escape
|
|
231
|
-
|
|
232
|
-
// Boşluk
|
|
233
|
-
49: " ",
|
|
234
|
-
]
|
|
235
|
-
|
|
236
|
-
return mapping[keyCode]
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
// MARK: - Method Swizzling
|
|
240
|
-
|
|
241
|
-
private func swizzlePressesMethods() {
|
|
242
|
-
guard let viewController = viewController else { return }
|
|
243
|
-
|
|
244
|
-
let originalPressesBeganSelector = #selector(UIViewController.pressesBegan(_:with:))
|
|
245
|
-
let swizzledPressesBeganSelector = #selector(UIViewController.raxon_pressesBegan(_:with:))
|
|
246
|
-
|
|
247
|
-
let originalPressesEndedSelector = #selector(UIViewController.pressesEnded(_:with:))
|
|
248
|
-
let swizzledPressesEndedSelector = #selector(UIViewController.raxon_pressesEnded(_:with:))
|
|
249
|
-
|
|
250
|
-
swizzleMethod(
|
|
251
|
-
for: UIViewController.self,
|
|
252
|
-
originalSelector: originalPressesBeganSelector,
|
|
253
|
-
swizzledSelector: swizzledPressesBeganSelector
|
|
254
|
-
)
|
|
255
|
-
|
|
256
|
-
swizzleMethod(
|
|
257
|
-
for: UIViewController.self,
|
|
258
|
-
originalSelector: originalPressesEndedSelector,
|
|
259
|
-
swizzledSelector: swizzledPressesEndedSelector
|
|
260
|
-
)
|
|
261
|
-
|
|
262
|
-
// Bu view controller'a weak referans ile handler'a erişim sağla
|
|
263
|
-
objc_setAssociatedObject(
|
|
264
|
-
viewController,
|
|
265
|
-
&AssociatedKeys.keyboardHandler,
|
|
266
|
-
self,
|
|
267
|
-
.OBJC_ASSOCIATION_RETAIN_NONATOMIC
|
|
268
|
-
)
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
private func unswizzlePressesMethods() {
|
|
272
|
-
// Method swizzling geri alınamaz ama handler'ı temizleyebiliriz
|
|
273
|
-
if let viewController = viewController {
|
|
274
|
-
objc_setAssociatedObject(
|
|
275
|
-
viewController,
|
|
276
|
-
&AssociatedKeys.keyboardHandler,
|
|
277
|
-
nil,
|
|
278
|
-
.OBJC_ASSOCIATION_RETAIN_NONATOMIC
|
|
279
|
-
)
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
private func swizzleMethod(
|
|
284
|
-
for classType: AnyClass,
|
|
285
|
-
originalSelector: Selector,
|
|
286
|
-
swizzledSelector: Selector
|
|
287
|
-
) {
|
|
288
|
-
guard let originalMethod = class_getInstanceMethod(classType, originalSelector),
|
|
289
|
-
let swizzledMethod = class_getInstanceMethod(classType, swizzledSelector) else {
|
|
290
|
-
return
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
let didAddMethod = class_addMethod(
|
|
294
|
-
classType,
|
|
295
|
-
originalSelector,
|
|
296
|
-
method_getImplementation(swizzledMethod),
|
|
297
|
-
method_getTypeEncoding(swizzledMethod)
|
|
298
|
-
)
|
|
299
|
-
|
|
300
|
-
if didAddMethod {
|
|
301
|
-
class_replaceMethod(
|
|
302
|
-
classType,
|
|
303
|
-
swizzledSelector,
|
|
304
|
-
method_getImplementation(originalMethod),
|
|
305
|
-
method_getTypeEncoding(originalMethod)
|
|
306
|
-
)
|
|
307
|
-
} else {
|
|
308
|
-
method_exchangeImplementations(originalMethod, swizzledMethod)
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
}
|
|
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
|
+
]
|
|
312
168
|
|
|
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
|
-
private
|
|
316
|
-
|
|
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
|
+
]
|
|
317
196
|
}
|
|
318
|
-
|
|
319
|
-
// MARK: - UIViewController Extension
|
|
320
|
-
|
|
321
|
-
@available(iOS 13.4, *)
|
|
322
|
-
extension UIViewController {
|
|
323
|
-
@objc dynamic func raxon_pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
|
|
324
|
-
// Orijinal implementasyonu çağır (swizzling yüzünden bu aslında orijinal)
|
|
325
|
-
raxon_pressesBegan(presses, with: event)
|
|
326
|
-
|
|
327
|
-
// Handler varsa tuşları işle
|
|
328
|
-
if let handler = objc_getAssociatedObject(self, &AssociatedKeys.keyboardHandler)
|
|
329
|
-
as? ExternalKeyboardHandler {
|
|
330
|
-
for press in presses {
|
|
331
|
-
_ = handler.handlePress(press)
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
@objc dynamic func raxon_pressesEnded(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
|
|
337
|
-
// Orijinal implementasyonu çağır
|
|
338
|
-
raxon_pressesEnded(presses, with: event)
|
|
339
|
-
}
|
|
340
|
-
}
|
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
|
}, [
|