Changeset 168:71af690e0c26 for src/mlx


Ignore:
Timestamp:
05/12/12 11:52:03 (13 years ago)
Author:
István Váradi <ivaradi@…>
Branch:
default
Phase:
public
Message:

The hotkey handling works

Location:
src/mlx
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • src/mlx/fsuipc.py

    r162 r168  
    308308            self._waitConnectionRequest()
    309309           
    310             if self._connect():
     310            if self._connect()>0:
    311311                self._handleConnection()
    312312
     
    319319                self._requestCondition.wait()
    320320           
    321     def _connect(self, autoReconnection = False):
     321    def _connect(self, autoReconnection = False, attempts = 0):
    322322        """Try to connect to the flight simulator via FSUIPC
    323323
     
    325325        not due to no longer requested.
    326326        """
    327         attempts = 0
    328327        while self._connectionRequested:
     328            if attempts>=self.NUM_CONNECTATTEMPTS:
     329                self._connectionRequested = False
     330                if autoReconnection:
     331                    Handler._callSafe(lambda:     
     332                                      self._connectionListener.disconnected())
     333                else:
     334                    Handler._callSafe(lambda:     
     335                                      self._connectionListener.connectionFailed())
     336                return 0
     337               
    329338            try:
    330339                attempts += 1
     
    338347                                                                         description))
    339348                self._connected = True
    340                 return True
     349                return attempts
    341350            except Exception, e:
    342                 print "fsuipc.Handler._connect: connection failed: " + str(e)
     351                print "fsuipc.Handler._connect: connection failed: " + str(e) + \
     352                      " (attempts: %d)" % (attempts,)
    343353                if attempts<self.NUM_CONNECTATTEMPTS:
    344354                    time.sleep(self.CONNECT_INTERVAL)
    345                 else:
    346                     self._connectionRequested = False
    347                     if autoReconnection:
    348                         Handler._callSafe(lambda:     
    349                                           self._connectionListener.disconnected())
    350                     else:
    351                         Handler._callSafe(lambda:     
    352                                           self._connectionListener.connectionFailed())
    353 
    354         return False
    355355               
    356356    def _handleConnection(self):
     
    386386            self._connected = False
    387387           
    388     def _processRequest(self, request, time):
     388    def _processRequest(self, request, time, attempts):
    389389        """Process the given request.
    390390
     
    409409            except Exception as e:
    410410                print "fsuipc.Handler._processRequest: FSUIPC connection failed (" + \
    411                       str(e) + "), reconnecting."
     411                      str(e) + "), reconnecting (attempts=%d)." % (attempts,)
    412412                needReconnect = True
    413413
     
    416416                    self._requests.insert(0, request)
    417417                self._disconnect()
    418                 self._connect(autoReconnection = True)
     418                return self._connect(autoReconnection = True, attempts = attempts)
     419            else:
     420                return 0
    419421        finally:
    420422            self._requestCondition.acquire()
     
    424426
    425427        Will be called with the request lock held."""
     428        attempts = 0
    426429        while self._connectionRequested and self._periodicRequests:
    427430            self._periodicRequests.sort()
     
    433436                break
    434437           
    435             self._processRequest(request, t)
     438            attempts = self._processRequest(request, t, attempts)
    436439
    437440        while self._connectionRequested and self._requests:
     
    439442            del self._requests[0]
    440443
    441             self._processRequest(request, None)
     444            attempts = self._processRequest(request, None, attempts)
    442445
    443446        return self._connectionRequested
     
    490493
    491494        return timestamp
     495
     496    @staticmethod
     497    def _appendHotkeyData(data, offset, hotkey):
     498        """Append the data for the given hotkey to the given array, that is
     499        intended to be passed to requestWrite call on the handler."""
     500        data.append((offset + 0, "b", ord(hotkey.key)))
     501
     502        modifiers = 0
     503        if hotkey.ctrl: modifiers |= 0x02
     504        if hotkey.shift: modifiers |= 0x01
     505        data.append((offset + 1, "b", modifiers))
     506
     507        data.append((offset + 2, "b", 0))
     508       
     509        data.append((offset + 3, "b", 0))       
    492510
    493511    def __init__(self, connectionListener, connectAttempts = -1,
     
    515533        self._aircraft = None
    516534
    517         self._handler = Handler(connectionListener,
     535        self._handler = Handler(self,
    518536                                connectAttempts = connectAttempts,
    519537                                connectInterval = connectInterval)
     538        self._connectionListener = connectionListener
    520539        self._handler.start()
    521540
     
    537556        self._flareStart = None
    538557        self._flareStartFS = None
     558
     559        self._hotkeyLock = threading.Lock()
     560        self._hotkeys = None
     561        self._hotkeySetID = 0
     562        self._hotkeySetGeneration = 0
     563        self._hotkeyOffets = None
     564        self._hotkeyRequestID = None
     565        self._hotkeyCallback = None
    539566
    540567        self._latin1decoder = codecs.getdecoder("iso-8859-1")
     
    665692        self._syncTime = False
    666693        self._nextSyncTime = -1
     694
     695    def listenHotkeys(self, hotkeys, callback):
     696        """Start listening to the given hotkeys.
     697
     698        callback is function expecting two arguments:
     699        - the ID of the hotkey set as returned by this function,
     700        - the list of the indexes of the hotkeys that were pressed."""
     701        with self._hotkeyLock:
     702            assert self._hotkeys is None
     703
     704            self._hotkeys = hotkeys
     705            self._hotkeySetID += 1
     706            self._hotkeySetGeneration = 0
     707            self._hotkeyCallback = callback
     708           
     709            self._handler.requestRead([(0x320c, "u")],
     710                                      self._handleNumHotkeys,
     711                                      (self._hotkeySetID,
     712                                       self._hotkeySetGeneration))
     713
     714            return self._hotkeySetID
     715
     716    def clearHotkeys(self):
     717        """Clear the current hotkey set.
     718
     719        Note that it is possible, that the callback function set either
     720        previously or after calling this function by listenHotkeys() will be
     721        called with data from the previous hotkey set.
     722
     723        Therefore it is recommended to store the hotkey set ID somewhere and
     724        check that in the callback function. Right before calling
     725        clearHotkeys(), this stored ID should be cleared so that the check
     726        fails for sure."""
     727        with self._hotkeyLock:
     728            if self._hotkeys is not None:
     729                self._hotkeys = None
     730                self._hotkeySetID += 1
     731                self._hotkeyCallback = None
     732                self._clearHotkeyRequest()
    667733           
    668734    def disconnect(self, closingMessage = None, duration = 3):
     
    673739       
    674740        self._stopNormal()
     741        self.clearHotkeys()
    675742        if closingMessage is None:
    676743            self._handler.disconnect()
     
    678745            self.sendMessage(closingMessage, duration = duration,
    679746                             _disconnect = True)
     747
     748    def connected(self, fsType, descriptor):
     749        """Called when a connection has been established to the flight
     750        simulator of the given type."""
     751        with self._hotkeyLock:
     752            if self._hotkeys is not None:
     753                self._hotkeySetGeneration += 1
     754           
     755                self._handler.requestRead([(0x320c, "u")],
     756                                          self._handleNumHotkeys,
     757                                          (self._hotkeySetID,
     758                                           self._hotkeySetGeneration))
     759        self._connectionListener.connected(fsType, descriptor)
     760
     761    def connectionFailed(self):
     762        """Called when the connection could not be established."""
     763        with self._hotkeyLock:
     764            self._clearHotkeyRequest()
     765        self._connectionListener.connectionFailed()
     766
     767    def disconnected(self):
     768        """Called when a connection to the flight simulator has been broken."""
     769        with self._hotkeyLock:
     770            self._clearHotkeyRequest()
     771        self._connectionListener.disconnected()
    680772
    681773    def _startDefaultNormal(self):
     
    9151007        """Callback for a fuel setting request."""
    9161008        pass
     1009
     1010    def _handleNumHotkeys(self, data, (id, generation)):
     1011        """Handle the result of the query of the number of hotkeys"""
     1012        with self._hotkeyLock:
     1013            if id==self._hotkeySetID and generation==self._hotkeySetGeneration:
     1014                numHotkeys = data[0]
     1015                print "fsuipc.Simulator._handleNumHotkeys: numHotkeys:", numHotkeys
     1016                data = [(0x3210 + i*4, "d") for i in range(0, numHotkeys)]       
     1017                self._handler.requestRead(data, self._handleHotkeyTable,
     1018                                          (id, generation))
     1019
     1020    def _setupHotkeys(self, data):
     1021        """Setup the hiven hotkeys and return the data to be written.
     1022
     1023        If there were hotkeys set previously, they are reused as much as
     1024        possible. Any of them not reused will be cleared."""
     1025        hotkeys = self._hotkeys
     1026        numHotkeys = len(hotkeys)
     1027
     1028        oldHotkeyOffsets = set([] if self._hotkeyOffets is None else
     1029                               self._hotkeyOffets)
     1030
     1031        self._hotkeyOffets = []
     1032        numOffsets = 0
     1033
     1034        while oldHotkeyOffsets:
     1035            offset = oldHotkeyOffsets.pop()
     1036            self._hotkeyOffets.append(offset)
     1037            numOffsets += 1
     1038
     1039            if numOffsets>=numHotkeys:
     1040                break
     1041
     1042        for i in range(0, len(data)):
     1043            if numOffsets>=numHotkeys:
     1044                break
     1045
     1046            if data[i]==0:
     1047                self._hotkeyOffets.append(0x3210 + i*4)
     1048                numOffsets += 1
     1049
     1050        writeData = []
     1051        for i in range(0, numOffsets):
     1052            Simulator._appendHotkeyData(writeData,
     1053                                        self._hotkeyOffets[i],
     1054                                        hotkeys[i])
     1055
     1056        for offset in oldHotkeyOffsets:
     1057            writeData.append((offset, "u", long(0)))
     1058
     1059        return writeData
     1060
     1061    def _handleHotkeyTable(self, data, (id, generation)):
     1062        """Handle the result of the query of the hotkey table."""
     1063        with self._hotkeyLock:
     1064            if id==self._hotkeySetID and generation==self._hotkeySetGeneration:
     1065                writeData = self._setupHotkeys(data)
     1066                self._handler.requestWrite(writeData,
     1067                                           self._handleHotkeysWritten,
     1068                                           (id, generation))
     1069           
     1070    def _handleHotkeysWritten(self, success, (id, generation)):
     1071        """Handle the result of the hotkeys having been written."""
     1072        with self._hotkeyLock:           
     1073            if success and id==self._hotkeySetID and \
     1074            generation==self._hotkeySetGeneration:
     1075                data = [(offset + 3, "b") for offset in self._hotkeyOffets]
     1076       
     1077                self._hotkeyRequestID = \
     1078                    self._handler.requestPeriodicRead(0.5, data,
     1079                                                      self._handleHotkeys,
     1080                                                      (id, generation))
     1081
     1082    def _handleHotkeys(self, data, (id, generation)):
     1083        """Handle the hotkeys."""       
     1084        with self._hotkeyLock:
     1085            if id!=self._hotkeySetID or generation!=self._hotkeySetGeneration:
     1086                return
     1087
     1088            callback = self._hotkeyCallback
     1089            offsets = self._hotkeyOffets
     1090
     1091        hotkeysPressed = []
     1092        for i in range(0, len(data)):
     1093            if data[i]!=0:
     1094                hotkeysPressed.append(i)
     1095
     1096        if hotkeysPressed:
     1097            data = []
     1098            for index in hotkeysPressed:
     1099                data.append((offsets[index]+3, "b", int(0)))
     1100            self._handler.requestWrite(data, self._handleHotkeysCleared)
     1101
     1102            callback(id, hotkeysPressed)
     1103
     1104    def _handleHotkeysCleared(self, sucess, extra):
     1105        """Callback for the hotkey-clearing write request."""       
     1106
     1107    def _clearHotkeyRequest(self):
     1108        """Clear the hotkey request in the handler if there is any."""
     1109        if self._hotkeyRequestID is not None:
     1110            self._handler.clearPeriodic(self._hotkeyRequestID)
     1111            self._hotkeyRequestID = None
    9171112                                                 
    9181113#------------------------------------------------------------------------------
  • src/mlx/gui/gui.py

    r164 r168  
    152152        self._lastLoadedPIREP = None
    153153
     154        self._hotkeySetID = None
     155
    154156    @property
    155157    def mainWindow(self):
     
    320322            self._wizard.connected(fsType, descriptor)
    321323        self._reconnecting = False
     324        self._listenHotkeys()
    322325
    323326    def connectionFailed(self):
     
    402405        """Disconnect from the simulator if connected."""
    403406        self.stopMonitoring()
     407        self._clearHotkeys()
    404408
    405409        if self._connected:
     
    875879    def _editPreferences(self, menuItem):
    876880        """Callback for editing the preferences."""
     881        self._clearHotkeys()
    877882        self._preferences.run(self.config)
    878883        self._setupTimeSync()
     884        self._listenHotkeys()
    879885
    880886    def _setupTimeSync(self):
     
    11061112        if callback is not None:
    11071113            callback(returned, result)
     1114
     1115    def _listenHotkeys(self):
     1116        """Setup the hotkeys based on the configuration."""
     1117        if self._hotkeySetID is None and self._simulator is not None:
     1118            self._hotkeySetID = \
     1119                self._simulator.listenHotkeys([self.config.pilotHotkey,
     1120                                               self.config.checklistHotkey],
     1121                                              self._handleHotkeys)
     1122
     1123    def _clearHotkeys(self):
     1124        """Clear the hotkeys."""
     1125        if self._hotkeySetID is not None:
     1126            self._hotkeySetID=None
     1127            self._simulator.clearHotkeys()
     1128
     1129    def _handleHotkeys(self, id, hotkeys):
     1130        """Handle the hotkeys."""
     1131        if id==self._hotkeySetID:
     1132            print "gui.GUI._handleHotkeys", hotkeys
  • src/mlx/gui/prefs.py

    r167 r168  
    4040        labelAlignment = gtk.Alignment(xalign = 0.0, yalign = 0.5,
    4141                                       xscale = 0.0, yscale = 0.0)
     42        labelAlignment.set_padding(padding_top = 0, padding_bottom = 0,
     43                                   padding_left = 0, padding_right = 4)
    4244        labelAlignment.add(label)
    43         self.pack_start(labelAlignment, False, False, 8)
     45        self.pack_start(labelAlignment, False, False, 0)
    4446
    4547        self._ctrl = gtk.CheckButton("Ctrl")
     
    5456
    5557        self._hotkeyModel = gtk.ListStore(str)
    56         for keyCode in range(ord("0"), ord("9")) + range(ord("A"), ord("Z")):
     58        for keyCode in range(ord("0"), ord("9")+1) + range(ord("A"), ord("Z")+1):
    5759            self._hotkeyModel.append([chr(keyCode)])
    5860
Note: See TracChangeset for help on using the changeset viewer.