def startSelecting(self, firstkey=None, mouse=False):   # firstkey is the key the user was
        #pressing. left, right, etc
        """Mark selection for copy/cut/move - trigger with shift-arrow-keys"""
        # any other key returns (cancels)
        # print message: "Select mode - Enter to select, Esc to cancel"
        self.undo.push()
        startPoint =  [self.xy[0],  self.xy[1]]   # set to wherever the cursor is
        endPoint = startPoint
        selecting = True
        self.stdscr.nodelay(0)  # wait for getch input
        c = firstkey
        self.clearStatusBar()
        #self.addstr(self.statusBarLineNum, 0, f"Use arrow keys to make selection, enter when done.")
        while selecting:
            endPoint =  [self.xy[0],  self.xy[1]]   # set to wherever the cursor is
            self.refresh()
            self.addstr(self.statusBarLineNum + 1, 0, f"Use arrow keys to make selection, enter when done.")
            # draw block area on top of drawing area
            mov = self.mov
            if endPoint[0] >= startPoint[0]:    # if we're moving right of start point
                firstLineNum = startPoint[0]
                lastLineNum = endPoint[0]
            else:   # otherwise, we're moving left
                lastLineNum = startPoint[0]
                firstLineNum = endPoint[0]
            if endPoint[1] >= startPoint[1]:    # we're moving down from start point
                firstColNum = startPoint[1]
                lastColNum = endPoint[1]
            else:   # we're moving up from start point
                lastColNum = startPoint[1]
                firstColNum = endPoint[1]
            # draw selected area inverse
            for linenum in range(firstLineNum, lastLineNum + 1):
                for colnum in range(firstColNum - 1, lastColNum):
                    #if colnum == self.mov.sizeX - 1:   # prevent overflow on last line
                    #    colnum -= 1
                    try:
                        charColor = mov.currentFrame.newColorMap[linenum][colnum]
                    except Exception as E:
                        self.notify(f"Exception E: {E}")
                        linenum = linenum - 1
                        charColor = mov.currentFrame.newColorMap[linenum][colnum]
                        #pdb.set_trace()
                    try: # set ncurss color pair
                        cursesColorPair = self.ansi.colorPairMap[tuple(charColor)] 
                    except: # Or if we can't, fail to the terminal's default color
                        cursesColorPair = 0
                    self.addstr(linenum - self.appState.topLine, colnum - self.appState.firstCol, mov.currentFrame.content[linenum][colnum], curses.color_pair(cursesColorPair) | curses.A_REVERSE)
            width = lastColNum - firstColNum + 1
            height = lastLineNum - firstLineNum + 1
            # end draw block area
            #self.stdscr.redrawwin()
            c = self.stdscr.getch()
            if c in [98, curses.KEY_LEFT, curses.KEY_SLEFT]:
                self.move_cursor_left()
            elif c in [98, curses.KEY_RIGHT, curses.KEY_SRIGHT]:
                #if colnum == self.mov.sizeX - 1:   # prevent overflow on last line
                self.move_cursor_right()
            # 337 and 520 - shift-up, 336 and 513 = shift-down
            elif c in [339, curses.KEY_PPAGE]:  # page up
                self.move_cursor_pgup()
            elif c in [338, curses.KEY_NPAGE]:  # page down
                self.move_cursor_pgdown()
            elif c in [98, curses.KEY_UP, 337, 520]:
                self.move_cursor_up()
            elif c in [98, curses.KEY_DOWN, 336, 513]:
                self.move_cursor_down()
            elif c in [339, curses.KEY_HOME]:  # 339 = home
                self.xy[1] = 1
            elif c in [338, curses.KEY_END]:   # 338 = end
                self.xy[1] = self.mov.sizeX - 1
            elif c in [13, curses.KEY_ENTER]:
                # Ask user what operation they want, and then do it on the selected area
                # copy, cut, fill, or copy into all frames :)
                prompting = True
                self.clearStatusBar()
                self.promptPrint("[C]opy, Cu[t], [D]elete, [F]ill, Co[l]or, Flip [X/Y], New [B]rush, copy to [A]ll Frames in range? " )
                while prompting:
                    prompt_ch = self.stdscr.getch()
                    if chr(prompt_ch) in ['c', 'C']:    # Copy
                        self.copySegmentToClipboard([firstLineNum, firstColNum], height, width)
                        prompting = False
                    if chr(prompt_ch) in ['b', 'B']:    # Make Brush
                        self.copySegmentToBrush([firstLineNum, firstColNum], height, width)
                        prompting = False
                    #if chr(prompt_ch) in ['m', 'M']:    # move
                    #    prompting = False
                    elif chr(prompt_ch) in ['x', 'X']:    # flip horizontally
                        self.flipSegmentHorizontal([firstLineNum, firstColNum], height, width)
                        #prompting = False
                        self.refresh()
                    elif chr(prompt_ch) in ['y', 'Y']:    # flip vertically 
                        self.flipSegmentVertical([firstLineNum, firstColNum], height, width)
                        #prompting = False
                        self.refresh()
                    #    self.undo.push()
                    #    self.mov.currentFrame.flip_horizontal()
                    if chr(prompt_ch) in ['t', 'T']:    # Cut to clipboard
                        self.clearStatusBar()
                        if self.mov.hasMultipleFrames():
                            self.promptPrint("Cut across all frames in playback range (Y/N)? ")
                            askingAboutRange = True
                        else:
                            self.copySegmentToClipboard([firstLineNum, firstColNum], height, width)
                            self.undo.push()
                            self.deleteSegment([firstLineNum, firstColNum], height, width)
                            askingAboutRange = False
                        while askingAboutRange:
                            prompt_ch = self.stdscr.getch()
                            if chr(prompt_ch) in ['y', 'Y']:    # yes, all range
                                self.copySegmentToClipboard([firstLineNum, firstColNum], height, width)
                                self.undo.push()
                                self.deleteSegment([firstLineNum, firstColNum], height, width, frange=self.appState.playbackRange)
                                askingAboutRange = False
                            if chr(prompt_ch) in ['n', 'N']:    # No, only one frame
                                self.copySegmentToClipboard([firstLineNum, firstColNum], height, width)
                                self.undo.push()
                                self.deleteSegment([firstLineNum, firstColNum], height, width)
                                askingAboutRange = False
                            elif prompt_ch == 27:  # esc, cancel
                                askingAboutRange = False
                        prompting = False
                    elif chr(prompt_ch) in ['d', 'D']:    # delete/clear
                        self.clearStatusBar()
                        if self.mov.hasMultipleFrames():
                            self.promptPrint("Delete across all frames in playback range (Y/N)? ")
                            askingAboutRange = True
                        else:
                            self.undo.push()
                            self.deleteSegment([firstLineNum, firstColNum], height, width)
                            askingAboutRange = False
                        while askingAboutRange:
                            prompt_ch = self.stdscr.getch()
                            if chr(prompt_ch) in ['y', 'Y']:    # yes, all range
                                self.undo.push()
                                self.deleteSegment([firstLineNum, firstColNum], height, width, frange=self.appState.playbackRange)
                                askingAboutRange = False
                            if chr(prompt_ch) in ['n', 'N']:    # yes, all range
                                self.undo.push()
                                self.deleteSegment([firstLineNum, firstColNum], height, width)
                                askingAboutRange = False
                            elif prompt_ch == 27:  # esc, cancel
                                askingAboutRange = False
                        prompting = False
                    elif chr(prompt_ch) in ['l', 'L']:    # color
                        self.clearStatusBar()
                        if self.mov.hasMultipleFrames():
                            self.promptPrint("Color across all frames in playback range (Y/N)? ")
                            askingAboutRange = True
                        else:
                            self.undo.push()
                            self.colorSegment([firstLineNum, firstColNum], height, width)
                            askingAboutRange = False
                        while askingAboutRange:
                            prompt_ch = self.stdscr.getch()
                            if chr(prompt_ch) in ['y', 'Y']:    # yes, all range
                                self.undo.push()
                                self.colorSegment([firstLineNum, firstColNum], height, width, frange=self.appState.playbackRange)
                                askingAboutRange = False
                            if chr(prompt_ch) in ['n', 'N']:    # yes, all range
                                self.undo.push()
                                self.colorSegment([firstLineNum, firstColNum], height, width)
                                askingAboutRange = False
                            elif prompt_ch == 27:  # esc, cancel
                                askingAboutRange = False
                        prompting = False
                    elif chr(prompt_ch) in ['f', 'F']:    # fill
                        self.clearStatusBar()
                        self.promptPrint(f"Enter fill character, or press enter for {self.appState.drawChar}: ")
                        askingAboutChar = True
                        canceled = False
                        drawChar = 'X'
                        prompt_ch = self.stdscr.getch()
                        if prompt_ch == 27:     # esc, cancel
                            canceled = True
                        elif prompt_ch in [13, curses.KEY_ENTER]:
                            drawChar = self.appState.drawChar
                        elif prompt_ch in [curses.KEY_F1]:
                            drawChar = chr(self.chMap['f1'])
                        elif prompt_ch in [curses.KEY_F2]:
                            drawChar = chr(self.chMap['f2'])
                        elif prompt_ch in [curses.KEY_F3]:
                            drawChar = chr(self.chMap['f3'])
                        elif prompt_ch in [curses.KEY_F4]:
                            drawChar = chr(self.chMap['f4'])
                        elif prompt_ch in [curses.KEY_F5]:
                            drawChar = chr(self.chMap['f5'])
                        elif prompt_ch in [curses.KEY_F6]:
                            drawChar = chr(self.chMap['f6'])
                        elif prompt_ch in [curses.KEY_F7]:
                            drawChar = chr(self.chMap['f7'])
                        elif prompt_ch in [curses.KEY_F8]:
                            drawChar = chr(self.chMap['f8'])
                        elif prompt_ch in [curses.KEY_F9]:
                            drawChar = chr(self.chMap['f9'])
                        elif prompt_ch in [curses.KEY_F10]:
                            drawChar = chr(self.chMap['f10'])
                        else:
                            drawChar = chr(prompt_ch)
                        if canceled:
                            askingAboutRange = False
                            prompting = False
                        else:
                            self.clearStatusBar()
                            if self.mov.hasMultipleFrames():
                                self.promptPrint("Fill across all frames in playback range (Y/N)? ")
                                askingAboutRange = True
                            else:   # Just one frame, so don't worry about the range.
                                self.undo.push()
                                self.fillSegment([firstLineNum, firstColNum], height, width, fillChar=drawChar)
                                askingAboutRange = False
                        while askingAboutRange:
                            prompt_ch = self.stdscr.getch()
                            if chr(prompt_ch) in ['y', 'Y']:    # yes, all range
                                self.undo.push()
                                self.fillSegment([firstLineNum, firstColNum], height, width, frange=self.appState.playbackRange, fillChar=drawChar)
                                askingAboutRange = False
                            if chr(prompt_ch) in ['n', 'N']:    # yes, all range
                                self.undo.push()
                                self.fillSegment([firstLineNum, firstColNum], height, width, fillChar=drawChar)
                                askingAboutRange = False
                            elif prompt_ch == 27:  # esc, cancel
                                askingAboutRange = False
                        prompting = False
                    elif chr(prompt_ch) in ['a', 'A']:    # copy to all frames
                        self.copySegmentToAllFrames([firstLineNum, firstColNum], height, width, frange=self.appState.playbackRange)
                        prompting = False
                    elif prompt_ch == 27:  # esc, cancel
                        self.undo.undo()
                        prompting = False
                    elif prompt_ch in [13, curses.KEY_ENTER]: # enter
                        # Confirm. Don't pop the clipboard like esc does.
                        prompting = False
                selecting = False
            elif c == curses.KEY_MOUSE: 
                try:
                    _, mouseX, mouseY, _, mouseState = curses.getmouse()
                except:
                    pass
                realmaxY,realmaxX = self.realstdscr.getmaxyx()
                # enable mouse tracking only when the button is pressed
                if not self.appState.hasMouseScroll:
                    curses.BUTTON5_PRESSED = 0
                    curses.BUTTON4_PRESSED = 0
                try:
                    curses.BUTTON5_PRESSED
                except:
                    curses.BUTTON5_PRESSED = 0
                try:
                    curses.BUTTON4_PRESSED
                except:
                    curses.BUTTON4_PRESSED = 0
                if mouseState & curses.BUTTON4_PRESSED:   # wheel up
                    if mouseY < self.mov.sizeY and mouseX < self.mov.sizeX \
                        and mouseY + self.appState.topLine < self.appState.topLine + self.statusBarLineNum:
                        # We're in in edit/canvas area
                        self.move_cursor_up()
                elif mouseState & curses.BUTTON5_PRESSED:   # wheel down
                    if mouseY < self.mov.sizeY and mouseX < self.mov.sizeX \
                        and mouseY + self.appState.topLine < self.appState.topLine + self.statusBarLineNum:
                        # We're in in edit/canvas area
                        self.move_cursor_down()
                if mouseState == curses.BUTTON1_CLICKED or mouseState & curses.BUTTON_SHIFT:
                    if mouseY < self.mov.sizeY and mouseX < self.mov.sizeX \
                        and mouseY + self.appState.topLine < self.appState.topLine + self.statusBarLineNum:
                        # We're in in edit/canvas area
                        self.xy[1] = mouseX + 1 + self.appState.firstCol # set cursor position
                        self.xy[0] = mouseY + self.appState.topLine
                            

            elif c == 27:   # esc
                selecting = False
        if self.playing:
            self.stdscr.nodelay(1)
        else:
            self.stdscr.nodelay(0)
Mark selection for copy/cut/move - trigger with shift-arrow-keys
durdraw/durdraw_ui_curses.py