Changeset 423:959722a16e8d for src
- Timestamp:
- 02/16/13 13:43:47 (12 years ago)
- Branch:
- xplane
- Phase:
- public
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/mlx/xplane.py
r421 r423 15 15 from xplra import TYPE_INT, TYPE_FLOAT, TYPE_DOUBLE 16 16 from xplra import TYPE_FLOAT_ARRAY, TYPE_INT_ARRAY, TYPE_BYTE_ARRAY 17 from xplra import HOTKEY_MODIFIER_SHIFT, HOTKEY_MODIFIER_CONTROL 17 18 18 19 #------------------------------------------------------------------------------ … … 30 31 31 32 _mps2knots = 3600.0 / 1852 33 34 #------------------------------------------------------------------------------ 35 36 class Request(object): 37 """Base class for one-shot requests.""" 38 def __init__(self, handler, callback, extra): 39 """Construct the request.""" 40 self._handler = handler 41 self._callback = callback 42 self._extra = extra 43 self._result = None 44 45 def process(self, time): 46 """Process the request. 47 48 Return True if the request has succeeded, False if data validation 49 has failed for a reading request. An exception may also be thrown 50 if there is some lower-level communication problem.""" 51 if self._process(time): 52 Handler._callSafe(lambda: self._callback(self._result, 53 self._extra)) 54 return True 55 else: 56 return False 57 58 def fail(self): 59 """Handle the failure of this request.""" 60 Handler._callSafe(lambda: self._callback(False, self._extra)) 61 62 class DataRequest(Request): 63 """A simple, one-shot data read or write request.""" 64 def __init__(self, handler, forWrite, data, callback, extra, 65 validator = None): 66 """Construct the request.""" 67 super(DataRequest, self).__init__(handler, callback, extra) 68 69 self._forWrite = forWrite 70 self._validator = validator 71 72 xplane = handler._xplane 73 self._multiBuffer = xplane.createMultiSetter() if forWrite \ 74 else xplane.createMultiGetter() 75 76 Handler._setupMultiBuffer(self._multiBuffer, 77 [(d[0], d[1]) for d in data]) 78 79 if forWrite: 80 index = 0 81 for (_, _, value) in data: 82 self._multiBuffer[index] = value 83 index += 1 84 85 86 def fail(self): 87 """Handle the failure of this request.""" 88 if self._forWrite: 89 super(DataRequest, self).fail() 90 else: 91 Handler._callSafe(lambda: self._callback(None, self._extra)) 92 93 def _process(self, time): 94 """Process the request.""" 95 if self._forWrite: 96 self._multiBuffer.execute() 97 self._result = True 98 return True 99 elif Handler._performRead(self._multiBuffer, 100 self._extra, self._validator): 101 self._result = self._multiBuffer 102 return True 103 else: 104 return False 105 106 class ShowMessageRequest(Request): 107 """Request to show a message in the simulator window.""" 108 def __init__(self, handler, message, duration, callback, extra): 109 """Construct the request.""" 110 super(ShowMessageRequest, self).__init__(handler, 111 callback, extra) 112 self._message = message 113 self._duration = duration 114 115 def _process(self, time): 116 """Process the request.""" 117 self._handler._xplane.showMessage(self._message, self._duration) 118 self._result = True 119 return True 120 121 class RegisterHotkeysRequest(Request): 122 """Request to register hotkeys with the simulator.""" 123 def __init__(self, handler, hotkeyCodes, callback, extra): 124 """Construct the request.""" 125 super(RegisterHotkeysRequest, self).__init__(handler, 126 callback, 127 extra) 128 self._hotkeyCodes = hotkeyCodes 129 130 def _process(self, time): 131 """Process the request.""" 132 self._handler._xplane.registerHotkeys(self._hotkeyCodes) 133 self._result = True 134 return True 135 136 class UnregisterHotkeysRequest(Request): 137 """Request to register hotkeys with the simulator.""" 138 def _process(self, time): 139 """Process the request.""" 140 self._handler._xplane.unregisterHotkeys() 141 self._result = True 142 return True 143 144 class PeriodicRequest(object): 145 """A periodic request.""" 146 def __init__(self, handler, id, period, callback, extra): 147 """Construct the periodic request.""" 148 self._handler = handler 149 self._id = id 150 self._period = period 151 self._nextFire = time.time() 152 self._callback = callback 153 self._extra = extra 154 self._result = None 155 156 @property 157 def id(self): 158 """Get the ID of this periodic request.""" 159 return self._id 160 161 @property 162 def nextFire(self): 163 """Get the next firing time.""" 164 return self._nextFire 165 166 def process(self, now): 167 """Check if this request should be executed, and if so, do so. 168 169 now is the time at which the request is being executed. If this 170 function is called too early, nothing is done, and True is 171 returned. 172 173 Return True if the request has succeeded, False if data validation 174 has failed. An exception may also be thrown if there is some 175 lower-level communication problem.""" 176 if now<self._nextFire: 177 return True 178 179 isOK = self._process(time) 180 181 if isOK: 182 Handler._callSafe(lambda: self._callback(self._result, 183 self._extra)) 184 now = time.time() 185 while self._nextFire <= now: 186 self._nextFire += self._period 187 188 return isOK 189 190 def fail(self): 191 """Handle the failure of this request.""" 192 pass 193 194 def __cmp__(self, other): 195 """Compare two periodic requests. They are ordered by their next 196 firing times.""" 197 return cmp(self._nextFire, other._nextFire) 198 199 class PeriodicDataRequest(PeriodicRequest): 200 """A periodic request.""" 201 def __init__(self, handler, id, period, data, callback, extra, 202 validator): 203 """Construct the periodic request.""" 204 super(PeriodicDataRequest, self).__init__(handler, id, period, 205 callback, extra) 206 self._validator = validator 207 self._multiGetter = handler._xplane.createMultiGetter() 208 Handler._setupMultiBuffer(self._multiGetter, data) 209 210 def _process(self, now): 211 """Process the request.""" 212 if Handler._performRead(self._multiGetter, 213 self._extra, self._validator): 214 self._result = self._multiGetter 215 return True 216 else: 217 return False 218 219 #------------------------------------------------------------------------------ 220 221 class HotkeysStateRequest(PeriodicRequest): 222 """Periodic hotkey query request.""" 223 def _process(self, now): 224 """Process the request.""" 225 self._result = self._handler._xplane.queryHotkeys() 226 return True 32 227 33 228 #------------------------------------------------------------------------------ … … 97 292 98 293 @staticmethod 99 def _performRead(multiGetter, callback,extra, validator):294 def _performRead(multiGetter, extra, validator): 100 295 """Perform a read request. 101 296 … … 112 307 if validator is None or \ 113 308 Handler._callSafe(lambda: validator(multiGetter, extra)): 114 Handler._callSafe(lambda: callback(multiGetter, extra))115 309 return True 116 310 else: … … 118 312 return False 119 313 120 class Request(object):121 """A simple, one-shot request."""122 def __init__(self, handler, forWrite, data, callback, extra,123 validator = None):124 """Construct the request."""125 self._forWrite = forWrite126 self._callback = callback127 self._extra = extra128 self._validator = validator129 130 xplane = handler._xplane131 self._multiBuffer = xplane.createMultiSetter() if forWrite \132 else xplane.createMultiGetter()133 134 Handler._setupMultiBuffer(self._multiBuffer,135 [(d[0], d[1]) for d in data])136 137 if forWrite:138 index = 0139 for (_, _, value) in data:140 self._multiBuffer[index] = value141 index += 1142 143 def process(self, time):144 """Process the request.145 146 Return True if the request has succeeded, False if data validation147 has failed for a reading request. An exception may also be thrown148 if there is some lower-level communication problem."""149 if self._forWrite:150 self._multiBuffer.execute()151 Handler._callSafe(lambda: self._callback(True, self._extra))152 return True153 else:154 return Handler._performRead(self._multiBuffer, self._callback,155 self._extra, self._validator)156 157 def fail(self):158 """Handle the failure of this request."""159 if self._forWrite:160 Handler._callSafe(lambda: self._callback(False, self._extra))161 else:162 Handler._callSafe(lambda: self._callback(None, self._extra))163 164 class PeriodicRequest(object):165 """A periodic request."""166 def __init__(self, handler, id, period, data, callback, extra,167 validator):168 """Construct the periodic request."""169 self._id = id170 self._period = period171 self._nextFire = time.time()172 self._callback = callback173 self._extra = extra174 self._validator = validator175 176 self._multiGetter = handler._xplane.createMultiGetter()177 Handler._setupMultiBuffer(self._multiGetter, data)178 179 @property180 def id(self):181 """Get the ID of this periodic request."""182 return self._id183 184 @property185 def nextFire(self):186 """Get the next firing time."""187 return self._nextFire188 189 def process(self, time):190 """Check if this request should be executed, and if so, do so.191 192 time is the time at which the request is being executed. If this193 function is called too early, nothing is done, and True is194 returned.195 196 Return True if the request has succeeded, False if data validation197 has failed. An exception may also be thrown if there is some198 lower-level communication problem."""199 if time<self._nextFire:200 return True201 202 isOK = Handler._performRead(self._multiGetter, self._callback,203 self._extra, self._validator)204 205 if isOK:206 while self._nextFire <= time:207 self._nextFire += self._period208 209 return isOK210 211 def fail(self):212 """Handle the failure of this request."""213 pass214 215 def __cmp__(self, other):216 """Compare two periodic requests. They are ordered by their next217 firing times."""218 return cmp(self._nextFire, other._nextFire)219 220 class ShowMessageRequest(object):221 """Request to show a message in the simulator window."""222 def __init__(self, handler, message, duration, callback, extra):223 """Construct the request."""224 self._handler = handler225 self._message = message226 self._duration = duration227 self._callback = callback228 self._extra = extra229 230 def process(self, time):231 """Process the request.232 233 Return True if the request has succeeded. An exception may also be234 thrown if there is some lower-level communication problem."""235 self._handler._xplane.showMessage(self._message, self._duration)236 Handler._callSafe(lambda: self._callback(True, self._extra))237 return True238 239 def fail(self):240 """Handle the failure of this request."""241 Handler._callSafe(lambda: self._callback(False, self._extra))242 243 314 def __init__(self, connectionListener, 244 315 connectAttempts = -1, connectInterval = 0.2): … … 276 347 """ 277 348 with self._requestCondition: 278 self._requests.append( Handler.Request(self, False, data,279 280 349 self._requests.append(DataRequest(self, False, data, 350 callback, extra, 351 validator)) 281 352 self._requestCondition.notify() 282 353 … … 295 366 """ 296 367 with self._requestCondition: 297 request = Handler.Request(self, True, data, callback, extra)368 request = DataRequest(self, True, data, callback, extra) 298 369 #print "xplane.Handler.requestWrite", request 299 370 self._requests.append(request) … … 311 382 id = self._nextPeriodicID 312 383 self._nextPeriodicID += 1 313 request = Handler.PeriodicRequest(self, id, period, data, callback, 314 extra, validator) 384 request = PeriodicDataRequest(self, id, period, 385 data, callback, 386 extra, validator) 315 387 self._periodicRequests.append(request) 316 388 self._requestCondition.notify() … … 329 401 """Request showing a message in the simulator.""" 330 402 with self._requestCondition: 331 self._requests.append(Handler.ShowMessageRequest(self, 332 message, duration, 333 callback, extra)) 403 self._requests.append(ShowMessageRequest(self, 404 message, duration, 405 callback, extra)) 406 self._requestCondition.notify() 407 408 def registerHotkeys(self, hotkeys, callback, extra = None): 409 """Request registering the given hotkeys.""" 410 with self._requestCondition: 411 self._requests.append(RegisterHotkeysRequest(self, hotkeys, 412 callback, extra)) 413 self._requestCondition.notify() 414 415 def requestHotkeysState(self, period, callback, extra = None): 416 """Request a periodic query of the hotkey status.""" 417 with self._requestCondition: 418 id = self._nextPeriodicID 419 self._nextPeriodicID += 1 420 request = HotkeysStateRequest(self, id, period, callback, extra) 421 self._periodicRequests.append(request) 422 self._requestCondition.notify() 423 return id 424 425 def unregisterHotkeys(self, callback, extra = None): 426 """Request unregistering the hotkeys.""" 427 with self._requestCondition: 428 self._requests.append(UnregisterHotkeysRequest(self, 429 callback, extra)) 334 430 self._requestCondition.notify() 335 431 … … 557 653 558 654 @staticmethod 559 def _appendHotkeyData(data, offset, hotkey): 560 """Append the data for the given hotkey to the given array, that is 561 intended to be passed to requestWrite call on the handler.""" 562 data.append((offset + 0, "b", ord(hotkey.key))) 563 564 modifiers = 0 565 if hotkey.ctrl: modifiers |= 0x02 566 if hotkey.shift: modifiers |= 0x01 567 data.append((offset + 1, "b", modifiers)) 568 569 data.append((offset + 2, "b", 0)) 570 571 data.append((offset + 3, "b", 0)) 655 def _getHotkeyCode(hotkey): 656 """Get the hotkey code for the given hot key.""" 657 code = ord(hotkey.key) 658 if hotkey.shift: code |= HOTKEY_MODIFIER_SHIFT 659 if hotkey.ctrl: code |= HOTKEY_MODIFIER_CONTROL 660 return code 572 661 573 662 def __init__(self, connectionListener, connectAttempts = -1, … … 619 708 620 709 self._hotkeyLock = threading.Lock() 621 self._hotkey s = None710 self._hotkeyCodes = None 622 711 self._hotkeySetID = 0 623 712 self._hotkeySetGeneration = 0 … … 749 838 - the ID of the hotkey set as returned by this function, 750 839 - the list of the indexes of the hotkeys that were pressed.""" 751 pass 752 # TODO: implement hotkey handling for X-Plane 753 # with self._hotkeyLock: 754 # assert self._hotkeys is None 755 756 # self._hotkeys = hotkeys 757 # self._hotkeySetID += 1 758 # self._hotkeySetGeneration = 0 759 # self._hotkeyCallback = callback 760 761 # self._handler.requestRead([(0x320c, "u")], 762 # self._handleNumHotkeys, 763 # (self._hotkeySetID, 764 # self._hotkeySetGeneration)) 765 766 # return self._hotkeySetID 840 with self._hotkeyLock: 841 assert self._hotkeyCodes is None 842 843 self._hotkeyCodes = \ 844 [self._getHotkeyCode(hotkey) for hotkey in hotkeys] 845 self._hotkeySetID += 1 846 self._hotkeySetGeneration = 0 847 self._hotkeyCallback = callback 848 849 self._handler.registerHotkeys(self._hotkeyCodes, 850 self._handleHotkeysRegistered, 851 (self._hotkeySetID, 852 self._hotkeySetGeneration)) 853 854 return self._hotkeySetID 767 855 768 856 def clearHotkeys(self): … … 777 865 clearHotkeys(), this stored ID should be cleared so that the check 778 866 fails for sure.""" 779 pass 780 # with self._hotkeyLock: 781 # if self._hotkeys is not None: 782 # self._hotkeys = None 783 # self._hotkeySetID += 1 784 # self._hotkeyCallback = None 785 # self._clearHotkeyRequest() 867 with self._hotkeyLock: 868 if self._hotkeyCodes is not None: 869 self._hotkeyCodes = None 870 self._hotkeySetID += 1 871 self._hotkeyCallback = None 872 self._clearHotkeyRequest() 786 873 787 874 def disconnect(self, closingMessage = None, duration = 3): … … 803 890 simulator of the given type.""" 804 891 self._fsType = fsType 805 # TODO: implement hotkey handling for X-Plane806 # with self._hotkeyLock:807 # if self._hotkeys is not None:808 # self._hotkeySetGeneration += 1 809 810 # self._handler.requestRead([(0x320c, "u")],811 # self._handleNumHotkeys,812 # (self._hotkeySetID,813 # self._hotkeySetGeneration)) 892 with self._hotkeyLock: 893 if self._hotkeyCodes is not None: 894 self._hotkeySetGeneration += 1 895 896 self._handler.registerHotkeys(self._hotkeyCodes, 897 self._handleHotkeysRegistered, 898 (self._hotkeySetID, 899 self._hotkeySetGeneration)) 900 814 901 self._connectionListener.connected(fsType, descriptor) 815 902 … … 1024 1111 self._handler.disconnect() 1025 1112 1026 def _handleNumHotkeys(self, data, (id, generation)): 1027 """Handle the result of the query of the number of hotkeys""" 1028 pass 1029 # TODO: implement hotkey handling for X-Plane 1030 # with self._hotkeyLock: 1031 # if id==self._hotkeySetID and generation==self._hotkeySetGeneration: 1032 # numHotkeys = data[0] 1033 # print "xplra.Simulator._handleNumHotkeys: numHotkeys:", numHotkeys 1034 # data = [(0x3210 + i*4, "d") for i in range(0, numHotkeys)] 1035 # self._handler.requestRead(data, self._handleHotkeyTable, 1036 # (id, generation)) 1037 1038 def _setupHotkeys(self, data): 1039 """Setup the hiven hotkeys and return the data to be written. 1040 1041 If there were hotkeys set previously, they are reused as much as 1042 possible. Any of them not reused will be cleared.""" 1043 # TODO: implement hotkey handling for X-Plane 1044 hotkeys = self._hotkeys 1045 numHotkeys = len(hotkeys) 1046 1047 oldHotkeyOffsets = set([] if self._hotkeyOffets is None else 1048 self._hotkeyOffets) 1049 1050 self._hotkeyOffets = [] 1051 numOffsets = 0 1052 1053 while oldHotkeyOffsets: 1054 offset = oldHotkeyOffsets.pop() 1055 self._hotkeyOffets.append(offset) 1056 numOffsets += 1 1057 1058 if numOffsets>=numHotkeys: 1059 break 1060 1061 for i in range(0, len(data)): 1062 if numOffsets>=numHotkeys: 1063 break 1064 1065 if data[i]==0: 1066 self._hotkeyOffets.append(0x3210 + i*4) 1067 numOffsets += 1 1068 1069 writeData = [] 1070 for i in range(0, numOffsets): 1071 Simulator._appendHotkeyData(writeData, 1072 self._hotkeyOffets[i], 1073 hotkeys[i]) 1074 1075 for offset in oldHotkeyOffsets: 1076 writeData.append((offset, "u", long(0))) 1077 1078 return writeData 1079 1080 def _handleHotkeyTable(self, data, (id, generation)): 1081 """Handle the result of the query of the hotkey table.""" 1082 with self._hotkeyLock: 1083 if id==self._hotkeySetID and generation==self._hotkeySetGeneration: 1084 writeData = self._setupHotkeys(data) 1085 self._handler.requestWrite(writeData, 1086 self._handleHotkeysWritten, 1087 (id, generation)) 1088 1089 def _handleHotkeysWritten(self, success, (id, generation)): 1113 def _handleHotkeysRegistered(self, success, (id, generation)): 1090 1114 """Handle the result of the hotkeys having been written.""" 1091 1115 with self._hotkeyLock: 1092 1116 if success and id==self._hotkeySetID and \ 1093 1117 generation==self._hotkeySetGeneration: 1094 data = [(offset + 3, "b") for offset in self._hotkeyOffets]1095 1096 1118 self._hotkeyRequestID = \ 1097 self._handler.requestPeriodicRead(0.5, data,1098 1099 1119 self._handler.requestHotkeysState(0.5, 1120 self._handleHotkeys, 1121 (id, generation)) 1100 1122 1101 1123 def _handleHotkeys(self, data, (id, generation)): … … 1114 1136 1115 1137 if hotkeysPressed: 1116 data = []1117 for index in hotkeysPressed:1118 data.append((offsets[index]+3, "b", int(0)))1119 self._handler.requestWrite(data, self._handleHotkeysCleared)1120 1121 1138 callback(id, hotkeysPressed) 1122 1123 def _handleHotkeysCleared(self, sucess, extra):1124 """Callback for the hotkey-clearing write request."""1125 1139 1126 1140 def _clearHotkeyRequest(self): 1127 1141 """Clear the hotkey request in the handler if there is any.""" 1128 1142 if self._hotkeyRequestID is not None: 1143 self._handler.unregisterHotkeys(self._hotkeysUnregistered) 1129 1144 self._handler.clearPeriodic(self._hotkeyRequestID) 1130 1145 self._hotkeyRequestID = None 1146 1147 def _hotkeysUnregistered(self): 1148 """Called when the hotkeys have been unregistered.""" 1149 pass 1131 1150 1132 1151 #------------------------------------------------------------------------------
Note:
See TracChangeset
for help on using the changeset viewer.